apero-kit-cli 2.4.7 → 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
- }
694
- }
695
- return { copied, skipped, errors };
696
- }
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);
743
- }
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");
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)}"`);
752
624
  }
753
- return { copied, skipped, errors };
625
+ lines.push(`prompt = '''
626
+ ${prompt}
627
+ '''`);
628
+ return lines.join("\n");
754
629
  }
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;
773
- }
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
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
+ }
781
658
  };
782
- } else {
783
- const destPath = join2(destDir, entry);
784
- if (mergeMode && fs.existsSync(destPath)) {
785
- continue;
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 };
786
697
  }
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;
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 };
825
741
  }
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
- );
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
+ }
813
+ }
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;
827
+ }
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
+ };
1032
1253
  }
1033
- return copied;
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(", ")}`);
1261
+ }
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");
@@ -1327,8 +1704,9 @@ function isDiscordConfigured() {
1327
1704
  function restartGateway() {
1328
1705
  try {
1329
1706
  const { execSync: execSync3 } = __require("child_process");
1330
- console.log(pc.cyan("Restarting OpenClaw gateway..."));
1331
- execSync3("openclaw gateway restart", { stdio: "inherit" });
1707
+ execSync3("openclaw config set gateway.mode local", { stdio: "ignore" });
1708
+ console.log(pc.cyan("Starting OpenClaw gateway..."));
1709
+ execSync3("openclaw gateway", { stdio: "inherit" });
1332
1710
  return true;
1333
1711
  } catch {
1334
1712
  return false;
@@ -1372,6 +1750,7 @@ async function promptDiscordSetup() {
1372
1750
  message: "What do you want to do?",
1373
1751
  options: [
1374
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" },
1375
1754
  { value: "reconfigure", label: "Reconfigure", hint: "Enter new token" },
1376
1755
  { value: "skip", label: "Skip setup", hint: "Continue without changes" }
1377
1756
  ]
@@ -1386,6 +1765,30 @@ async function promptDiscordSetup() {
1386
1765
  restartOnly: true
1387
1766
  };
1388
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
+ }
1389
1792
  if (action === "skip") {
1390
1793
  return {
1391
1794
  token: "",
@@ -1395,7 +1798,37 @@ async function promptDiscordSetup() {
1395
1798
  };
1396
1799
  }
1397
1800
  }
1398
- 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"));
1399
1832
  console.log("");
1400
1833
  const token = await p.password({
1401
1834
  message: "Discord Bot Token:",
@@ -1425,19 +1858,22 @@ async function promptDiscordSetup() {
1425
1858
  guildId = guild;
1426
1859
  }
1427
1860
  let autoSetup = false;
1428
- if (openclawInstalled) {
1861
+ if (openclawInstalled && !useGeminiCli) {
1429
1862
  const shouldAutoSetup = await p.confirm({
1430
1863
  message: "Auto-setup OpenClaw config?",
1431
1864
  initialValue: true
1432
1865
  });
1433
1866
  if (p.isCancel(shouldAutoSetup)) process.exit(0);
1434
1867
  autoSetup = shouldAutoSetup;
1868
+ } else if (useGeminiCli) {
1869
+ autoSetup = true;
1435
1870
  }
1436
1871
  return {
1437
1872
  token,
1438
1873
  guildId,
1439
1874
  autoSetup,
1440
- openclawInstalled
1875
+ openclawInstalled,
1876
+ useGeminiCli
1441
1877
  };
1442
1878
  }
1443
1879
  var init_prompts = __esm({
@@ -1453,8 +1889,8 @@ var init_exports = {};
1453
1889
  __export(init_exports, {
1454
1890
  initCommand: () => initCommand
1455
1891
  });
1456
- import fs4 from "fs-extra";
1457
- 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";
1458
1894
  import pc2 from "picocolors";
1459
1895
  import ora from "ora";
1460
1896
  function filterComponents(list, exclude, only) {
@@ -1510,7 +1946,7 @@ async function initCommand(projectName, options) {
1510
1946
  let cliTargets;
1511
1947
  if (options.target) {
1512
1948
  const targetsFromFlag = options.target.split(",").map((t) => t.trim());
1513
- cliTargets = targetsFromFlag.filter((t) => t === "claude" || t === "gemini" || t === "discord");
1949
+ cliTargets = targetsFromFlag.filter((t) => isValidTarget(t));
1514
1950
  if (cliTargets.length === 0) {
1515
1951
  console.log(pc2.yellow(`Unknown target "${options.target}", using "claude"`));
1516
1952
  cliTargets = ["claude"];
@@ -1528,18 +1964,18 @@ async function initCommand(projectName, options) {
1528
1964
  let existingAction = null;
1529
1965
  const existingTargets = [];
1530
1966
  for (const target of cliTargets) {
1531
- const targetDir = getTargetDir(projectDir, target);
1532
- if (options.fresh && fs4.existsSync(targetDir)) {
1533
- await fs4.remove(targetDir);
1534
- existingTargets.push(TARGETS[target]);
1535
- } else if (fs4.existsSync(targetDir) && !options.force) {
1536
- 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));
1537
1973
  }
1538
1974
  }
1539
1975
  if (options.fresh && existingTargets.length > 0) {
1540
- const akDir = join5(projectDir, ".ak");
1541
- if (fs4.existsSync(akDir)) {
1542
- await fs4.remove(akDir);
1976
+ const akDir = join9(projectDir, ".ak");
1977
+ if (fs8.existsSync(akDir)) {
1978
+ await fs8.remove(akDir);
1543
1979
  }
1544
1980
  console.log(pc2.cyan(`Fresh install: removed existing files (${existingTargets.join(", ")})`));
1545
1981
  existingAction = null;
@@ -1559,8 +1995,8 @@ async function initCommand(projectName, options) {
1559
1995
  }
1560
1996
  }
1561
1997
  }
1562
- if (!isCurrentDir && fs4.existsSync(projectDir) && !options.force) {
1563
- const files = fs4.readdirSync(projectDir);
1998
+ if (!isCurrentDir && fs8.existsSync(projectDir) && !options.force) {
1999
+ const files = fs8.readdirSync(projectDir);
1564
2000
  if (files.length > 0 && !existingAction) {
1565
2001
  console.log(pc2.red(`Directory "${projectName}" already exists and is not empty.`));
1566
2002
  console.log(pc2.gray("Use --force to overwrite."));
@@ -1593,8 +2029,10 @@ async function initCommand(projectName, options) {
1593
2029
  toInstall.agents = await promptAgents(source.claudeDir);
1594
2030
  toInstall.skills = await promptSkills(source.claudeDir);
1595
2031
  toInstall.commands = await promptCommands(source.claudeDir);
1596
- toInstall.includeRouter = await promptIncludeRouter();
1597
- toInstall.includeHooks = await promptIncludeHooks();
2032
+ if (cliTargets.includes("claude")) {
2033
+ toInstall.includeRouter = await promptIncludeRouter();
2034
+ toInstall.includeHooks = await promptIncludeHooks();
2035
+ }
1598
2036
  } else {
1599
2037
  const kit = getKit(kitName);
1600
2038
  if (!kit) {
@@ -1619,7 +2057,7 @@ async function initCommand(projectName, options) {
1619
2057
  }
1620
2058
  console.log(pc2.cyan("\nWill create:"));
1621
2059
  console.log(pc2.white(` Project: ${projectName}/`));
1622
- console.log(pc2.white(` Targets: ${cliTargets.map((t) => TARGETS[t]).join(", ")}/`));
2060
+ console.log(pc2.white(` Targets: ${cliTargets.map((t) => getTargetDisplayName(t)).join(", ")}`));
1623
2061
  console.log(pc2.white(` Kit: ${kitName}`));
1624
2062
  if (Array.isArray(toInstall.agents)) {
1625
2063
  console.log(pc2.gray(` Agents: ${toInstall.agents.length}`));
@@ -1639,95 +2077,50 @@ async function initCommand(projectName, options) {
1639
2077
  }
1640
2078
  const spinner = ora("Creating project...").start();
1641
2079
  try {
1642
- await fs4.ensureDir(projectDir);
2080
+ await fs8.ensureDir(projectDir);
1643
2081
  for (const target of cliTargets) {
1644
- const targetDir = getTargetDir(projectDir, target);
1645
- await fs4.ensureDir(targetDir);
1646
- 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);
1647
2087
  spinner.text = mergeMode ? `Merging agents (${targetLabel})...` : `Copying agents (${targetLabel})...`;
1648
- if (target === "gemini") {
1649
- await copyAgentsForGemini(toInstall.agents, source.claudeDir, targetDir, mergeMode);
1650
- } else if (target === "discord") {
1651
- await copyAgentsForDiscord(toInstall.agents, source.claudeDir, targetDir, mergeMode);
1652
- } else {
1653
- if (toInstall.agents === "all") {
1654
- await copyAllOfType("agents", source.claudeDir, targetDir, mergeMode);
1655
- } else if (toInstall.agents.length > 0) {
1656
- await copyItems(toInstall.agents, "agents", source.claudeDir, targetDir, mergeMode);
1657
- }
1658
- }
2088
+ await adapter.copyAgents(filteredItems.agents, source.claudeDir, targetDir, mergeMode);
1659
2089
  spinner.text = mergeMode ? `Merging skills (${targetLabel})...` : `Copying skills (${targetLabel})...`;
1660
- if (target === "gemini") {
1661
- await copySkillsForGemini(toInstall.skills, source.claudeDir, targetDir, mergeMode);
1662
- } else if (target === "discord") {
1663
- await copySkillsForDiscord(toInstall.skills, source.claudeDir, targetDir, mergeMode);
1664
- } else {
1665
- if (toInstall.skills === "all") {
1666
- await copyAllOfType("skills", source.claudeDir, targetDir, mergeMode);
1667
- } else if (toInstall.skills.length > 0) {
1668
- await copyItems(toInstall.skills, "skills", source.claudeDir, targetDir, mergeMode);
1669
- }
1670
- }
2090
+ await adapter.copySkills(filteredItems.skills, source.claudeDir, targetDir, mergeMode);
1671
2091
  spinner.text = mergeMode ? `Merging commands (${targetLabel})...` : `Copying commands (${targetLabel})...`;
1672
- if (target === "gemini") {
1673
- await copyCommandsForGemini(toInstall.commands, source.claudeDir, targetDir, mergeMode);
1674
- } else if (target === "discord") {
1675
- await copyCommandsForDiscord(toInstall.commands, source.claudeDir, targetDir, mergeMode);
1676
- spinner.text = mergeMode ? `Converting commands to skills (${targetLabel})...` : `Converting commands to skills (${targetLabel})...`;
1677
- await convertCommandsToSkills(toInstall.commands, source.claudeDir, targetDir, mergeMode);
1678
- spinner.text = `Copying bundled skills (${targetLabel})...`;
1679
- await copyBundledSkillsForDiscord(targetDir, mergeMode);
1680
- } else {
1681
- if (toInstall.commands === "all") {
1682
- await copyAllOfType("commands", source.claudeDir, targetDir, mergeMode);
1683
- } else if (toInstall.commands.length > 0) {
1684
- await copyItems(toInstall.commands, "commands", source.claudeDir, targetDir, mergeMode);
1685
- }
1686
- }
1687
- if (target === "claude") {
2092
+ await adapter.copyCommands(filteredItems.commands, source.claudeDir, targetDir, mergeMode);
2093
+ if (adapter.supports("workflows") && filteredItems.workflows.length > 0) {
1688
2094
  spinner.text = mergeMode ? `Merging workflows (${targetLabel})...` : `Copying workflows (${targetLabel})...`;
1689
- if (toInstall.workflows === "all") {
1690
- await copyAllOfType("workflows", source.claudeDir, targetDir, mergeMode);
1691
- } else if (toInstall.workflows && toInstall.workflows.length > 0) {
1692
- await copyItems(toInstall.workflows, "workflows", source.claudeDir, targetDir, mergeMode);
1693
- }
2095
+ await adapter.copyWorkflows(filteredItems.workflows, source.claudeDir, targetDir, mergeMode);
1694
2096
  }
1695
- if (target === "claude" && toInstall.includeRouter) {
2097
+ if (adapter.supports("router") && filteredItems.includeRouter) {
1696
2098
  spinner.text = mergeMode ? `Merging router (${targetLabel})...` : `Copying router (${targetLabel})...`;
1697
- await copyRouter(source.claudeDir, targetDir, mergeMode);
2099
+ await adapter.copyRouter(source.claudeDir, targetDir, mergeMode);
1698
2100
  }
1699
- if (target === "claude" && toInstall.includeHooks) {
2101
+ if (adapter.supports("hooks") && filteredItems.includeHooks) {
1700
2102
  spinner.text = mergeMode ? `Merging hooks (${targetLabel})...` : `Copying hooks (${targetLabel})...`;
1701
- await copyHooks(source.claudeDir, targetDir, mergeMode);
1702
- }
1703
- if (target === "claude") {
1704
- spinner.text = mergeMode ? `Merging extras (${targetLabel})...` : `Copying extras (${targetLabel})...`;
1705
- await copyDirectory("memory", source.claudeDir, targetDir, mergeMode);
1706
- await copyDirectory("output-styles", source.claudeDir, targetDir, mergeMode);
1707
- await copyDirectory("scripts", source.claudeDir, targetDir, mergeMode);
1708
- spinner.text = mergeMode ? `Merging base files (${targetLabel})...` : `Copying base files (${targetLabel})...`;
1709
- await copyBaseFiles(source.claudeDir, targetDir, mergeMode);
1710
- } else if (target === "gemini") {
1711
- spinner.text = mergeMode ? `Merging settings (${targetLabel})...` : `Copying settings (${targetLabel})...`;
1712
- await copyGeminiBaseFiles(targetDir, mergeMode);
1713
- } else if (target === "discord") {
1714
- spinner.text = mergeMode ? `Merging config (${targetLabel})...` : `Copying config (${targetLabel})...`;
1715
- await copyDiscordBaseFiles(targetDir, mergeMode);
1716
- if (discordConfig && !discordConfig.restartOnly) {
1717
- spinner.text = "Configuring Discord bot...";
1718
- await updateDiscordConfig(targetDir, discordConfig.token, discordConfig.guildId);
1719
- if (discordConfig.autoSetup) {
1720
- spinner.text = "Setting up OpenClaw...";
1721
- const result = await setupOpenClawConfig(discordConfig.token);
1722
- openclawSetupSuccess = result.success;
1723
- if (!result.success) {
1724
- 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(`
1725
2119
  Note: ${result.message}`));
1726
- }
1727
2120
  }
1728
- } else if (discordConfig?.restartOnly) {
1729
- openclawSetupSuccess = true;
1730
2121
  }
2122
+ } else if (target === "discord" && discordConfig?.restartOnly) {
2123
+ openclawSetupSuccess = true;
1731
2124
  }
1732
2125
  }
1733
2126
  if (source.agentsMd && cliTargets.includes("claude")) {
@@ -1738,8 +2131,7 @@ async function initCommand(projectName, options) {
1738
2131
  kit: kitName,
1739
2132
  source: source.path,
1740
2133
  targets: cliTargets,
1741
- target: TARGETS[cliTargets[0]],
1742
- // Keep backward compat
2134
+ target: getTargetDirectory(cliTargets[0]),
1743
2135
  installed: {
1744
2136
  agents: toInstall.agents === "all" ? ["all"] : toInstall.agents,
1745
2137
  skills: toInstall.skills === "all" ? ["all"] : toInstall.skills,
@@ -1756,11 +2148,7 @@ async function initCommand(projectName, options) {
1756
2148
  console.log(pc2.cyan("Next steps:"));
1757
2149
  console.log(pc2.white(` cd ${projectName}`));
1758
2150
  }
1759
- const targetNames = cliTargets.map((t) => {
1760
- if (t === "gemini") return "Gemini CLI";
1761
- if (t === "discord") return "Discord + Clawbot";
1762
- return "Claude Code";
1763
- }).join(" & ");
2151
+ const targetNames = cliTargets.map((t) => getTargetDisplayName(t)).join(" & ");
1764
2152
  console.log(pc2.cyan(`Ready to code with ${targetNames}!`));
1765
2153
  console.log("");
1766
2154
  console.log(pc2.gray("Useful commands:"));
@@ -1803,8 +2191,9 @@ var init_init = __esm({
1803
2191
  "use strict";
1804
2192
  init_kits();
1805
2193
  init_paths();
1806
- init_copy();
2194
+ init_targets();
1807
2195
  init_state();
2196
+ init_copy();
1808
2197
  init_prompts();
1809
2198
  INIT_PASSWORD = "6702";
1810
2199
  }
@@ -1815,8 +2204,8 @@ var add_exports = {};
1815
2204
  __export(add_exports, {
1816
2205
  addCommand: () => addCommand
1817
2206
  });
1818
- import fs5 from "fs-extra";
1819
- import { join as join6 } from "path";
2207
+ import fs9 from "fs-extra";
2208
+ import { join as join10 } from "path";
1820
2209
  import pc3 from "picocolors";
1821
2210
  import ora2 from "ora";
1822
2211
  async function addCommand(item, options = {}) {
@@ -1871,10 +2260,10 @@ async function addCommand(item, options = {}) {
1871
2260
  return;
1872
2261
  }
1873
2262
  const targetFolder = state?.target || ".claude";
1874
- const targetDir = join6(projectDir, targetFolder);
1875
- const destPath = join6(targetDir, normalizedType, name);
2263
+ const targetDir = join10(projectDir, targetFolder);
2264
+ const destPath = join10(targetDir, normalizedType, name);
1876
2265
  const destPathMd = destPath + ".md";
1877
- if (fs5.existsSync(destPath) || fs5.existsSync(destPathMd)) {
2266
+ if (fs9.existsSync(destPath) || fs9.existsSync(destPathMd)) {
1878
2267
  console.log(pc3.yellow(`${type} "${name}" already exists in project.`));
1879
2268
  console.log(pc3.gray('Use "ak update" to refresh from source.'));
1880
2269
  return;
@@ -2090,8 +2479,8 @@ var update_exports = {};
2090
2479
  __export(update_exports, {
2091
2480
  updateCommand: () => updateCommand
2092
2481
  });
2093
- import fs6 from "fs-extra";
2094
- import { join as join7 } from "path";
2482
+ import fs10 from "fs-extra";
2483
+ import { join as join11 } from "path";
2095
2484
  import pc5 from "picocolors";
2096
2485
  import ora3 from "ora";
2097
2486
  async function updateCommand(options = {}) {
@@ -2130,8 +2519,8 @@ async function updateCommand(options = {}) {
2130
2519
  if (options.commands) typesToUpdate = ["commands"];
2131
2520
  const sourceHashes = {};
2132
2521
  for (const type of typesToUpdate) {
2133
- const typeDir = join7(source.claudeDir, type);
2134
- if (fs6.existsSync(typeDir)) {
2522
+ const typeDir = join11(source.claudeDir, type);
2523
+ if (fs10.existsSync(typeDir)) {
2135
2524
  const hashes = await hashDirectory(typeDir);
2136
2525
  for (const [path, hash] of Object.entries(hashes)) {
2137
2526
  sourceHashes[`${type}/${path}`] = hash;
@@ -2142,9 +2531,9 @@ async function updateCommand(options = {}) {
2142
2531
  const skipped = [];
2143
2532
  const newFiles = [];
2144
2533
  for (const [path, sourceHash] of Object.entries(sourceHashes)) {
2145
- const currentPath = join7(targetDir, path);
2534
+ const currentPath = join11(targetDir, path);
2146
2535
  const originalHash = state.originalHashes?.[path];
2147
- const currentHash = fs6.existsSync(currentPath) ? hashFile(currentPath) : null;
2536
+ const currentHash = fs10.existsSync(currentPath) ? hashFile(currentPath) : null;
2148
2537
  if (!currentHash) {
2149
2538
  newFiles.push(path);
2150
2539
  } else if (currentHash === originalHash) {
@@ -2197,10 +2586,10 @@ async function updateCommand(options = {}) {
2197
2586
  let failed = 0;
2198
2587
  for (const path of [...toUpdate, ...newFiles]) {
2199
2588
  try {
2200
- const srcPath = join7(source.claudeDir, path);
2201
- const destPath = join7(targetDir, path);
2202
- await fs6.ensureDir(join7(targetDir, path.split("/").slice(0, -1).join("/")));
2203
- 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 });
2204
2593
  updated++;
2205
2594
  } catch (err) {
2206
2595
  failed++;
@@ -2250,7 +2639,7 @@ __export(status_exports, {
2250
2639
  statusCommand: () => statusCommand
2251
2640
  });
2252
2641
  import pc6 from "picocolors";
2253
- import fs7 from "fs-extra";
2642
+ import fs11 from "fs-extra";
2254
2643
  async function statusCommand(options = {}) {
2255
2644
  const projectDir = process.cwd();
2256
2645
  if (!isAkProject(projectDir)) {
@@ -2331,7 +2720,7 @@ async function statusCommand(options = {}) {
2331
2720
  if (hooks) console.log(pc6.gray(" Hooks: \u2713"));
2332
2721
  console.log("");
2333
2722
  }
2334
- if (state.source && !fs7.existsSync(state.source)) {
2723
+ if (state.source && !fs11.existsSync(state.source)) {
2335
2724
  console.log(pc6.yellow("\u26A0 Source directory not found. Update may not work."));
2336
2725
  console.log(pc6.gray(` Expected: ${state.source}`));
2337
2726
  console.log("");
@@ -2350,15 +2739,15 @@ var doctor_exports = {};
2350
2739
  __export(doctor_exports, {
2351
2740
  doctorCommand: () => doctorCommand
2352
2741
  });
2353
- import fs8 from "fs-extra";
2354
- import { join as join8 } from "path";
2742
+ import fs12 from "fs-extra";
2743
+ import { join as join12 } from "path";
2355
2744
  import pc7 from "picocolors";
2356
2745
  async function doctorCommand(options = {}) {
2357
2746
  const projectDir = process.cwd();
2358
2747
  let targetDir = null;
2359
2748
  for (const [name, folder] of Object.entries(TARGETS)) {
2360
- const dir = join8(projectDir, folder);
2361
- if (fs8.existsSync(dir)) {
2749
+ const dir = join12(projectDir, folder);
2750
+ if (fs12.existsSync(dir)) {
2362
2751
  targetDir = { name, folder, dir };
2363
2752
  break;
2364
2753
  }
@@ -2371,7 +2760,7 @@ async function doctorCommand(options = {}) {
2371
2760
  severity: "error",
2372
2761
  check: () => isAkProject(projectDir),
2373
2762
  fix: async () => {
2374
- await fs8.ensureDir(join8(projectDir, ".ak"));
2763
+ await fs12.ensureDir(join12(projectDir, ".ak"));
2375
2764
  }
2376
2765
  },
2377
2766
  {
@@ -2387,9 +2776,9 @@ async function doctorCommand(options = {}) {
2387
2776
  if (targetDir) {
2388
2777
  const dirs = ["agents", "skills", "commands", "workflows"];
2389
2778
  for (const dir of dirs) {
2390
- const fullPath = join8(targetDir.dir, dir);
2391
- if (fs8.existsSync(fullPath)) {
2392
- 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("."));
2393
2782
  if (items.length > 0) {
2394
2783
  installed[dir] = items;
2395
2784
  }
@@ -2411,7 +2800,7 @@ async function doctorCommand(options = {}) {
2411
2800
  name: "agents_md",
2412
2801
  label: "AGENTS.md exists",
2413
2802
  severity: "warning",
2414
- check: () => fs8.existsSync(join8(projectDir, "AGENTS.md"))
2803
+ check: () => fs12.existsSync(join12(projectDir, "AGENTS.md"))
2415
2804
  },
2416
2805
  {
2417
2806
  name: "source",
@@ -2419,7 +2808,7 @@ async function doctorCommand(options = {}) {
2419
2808
  severity: "error",
2420
2809
  check: () => {
2421
2810
  if (!state || !state.source) return true;
2422
- return fs8.existsSync(state.source);
2811
+ return fs12.existsSync(state.source);
2423
2812
  },
2424
2813
  getMeta: () => state && state.source ? { source: state.source } : {}
2425
2814
  },
@@ -2429,18 +2818,18 @@ async function doctorCommand(options = {}) {
2429
2818
  severity: "warning",
2430
2819
  check: () => {
2431
2820
  if (!targetDir) return false;
2432
- return fs8.existsSync(join8(targetDir.dir, "agents"));
2821
+ return fs12.existsSync(join12(targetDir.dir, "agents"));
2433
2822
  },
2434
2823
  fix: async () => {
2435
2824
  if (targetDir) {
2436
- await fs8.ensureDir(join8(targetDir.dir, "agents"));
2825
+ await fs12.ensureDir(join12(targetDir.dir, "agents"));
2437
2826
  }
2438
2827
  },
2439
2828
  getMeta: () => {
2440
2829
  if (!targetDir) return {};
2441
- const fullPath = join8(targetDir.dir, "agents");
2442
- if (fs8.existsSync(fullPath)) {
2443
- 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;
2444
2833
  return { items };
2445
2834
  }
2446
2835
  return {};
@@ -2452,18 +2841,18 @@ async function doctorCommand(options = {}) {
2452
2841
  severity: "warning",
2453
2842
  check: () => {
2454
2843
  if (!targetDir) return false;
2455
- return fs8.existsSync(join8(targetDir.dir, "commands"));
2844
+ return fs12.existsSync(join12(targetDir.dir, "commands"));
2456
2845
  },
2457
2846
  fix: async () => {
2458
2847
  if (targetDir) {
2459
- await fs8.ensureDir(join8(targetDir.dir, "commands"));
2848
+ await fs12.ensureDir(join12(targetDir.dir, "commands"));
2460
2849
  }
2461
2850
  },
2462
2851
  getMeta: () => {
2463
2852
  if (!targetDir) return {};
2464
- const fullPath = join8(targetDir.dir, "commands");
2465
- if (fs8.existsSync(fullPath)) {
2466
- 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;
2467
2856
  return { items };
2468
2857
  }
2469
2858
  return {};
@@ -2475,18 +2864,18 @@ async function doctorCommand(options = {}) {
2475
2864
  severity: "warning",
2476
2865
  check: () => {
2477
2866
  if (!targetDir) return false;
2478
- return fs8.existsSync(join8(targetDir.dir, "skills"));
2867
+ return fs12.existsSync(join12(targetDir.dir, "skills"));
2479
2868
  },
2480
2869
  fix: async () => {
2481
2870
  if (targetDir) {
2482
- await fs8.ensureDir(join8(targetDir.dir, "skills"));
2871
+ await fs12.ensureDir(join12(targetDir.dir, "skills"));
2483
2872
  }
2484
2873
  },
2485
2874
  getMeta: () => {
2486
2875
  if (!targetDir) return {};
2487
- const fullPath = join8(targetDir.dir, "skills");
2488
- if (fs8.existsSync(fullPath)) {
2489
- 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;
2490
2879
  return { items };
2491
2880
  }
2492
2881
  return {};
@@ -2498,7 +2887,7 @@ async function doctorCommand(options = {}) {
2498
2887
  severity: "warning",
2499
2888
  check: () => {
2500
2889
  if (!targetDir) return false;
2501
- return fs8.existsSync(join8(targetDir.dir, "scripts"));
2890
+ return fs12.existsSync(join12(targetDir.dir, "scripts"));
2502
2891
  }
2503
2892
  },
2504
2893
  {
@@ -2507,7 +2896,7 @@ async function doctorCommand(options = {}) {
2507
2896
  severity: "warning",
2508
2897
  check: () => {
2509
2898
  if (!targetDir) return false;
2510
- return fs8.existsSync(join8(targetDir.dir, "hooks"));
2899
+ return fs12.existsSync(join12(targetDir.dir, "hooks"));
2511
2900
  }
2512
2901
  },
2513
2902
  {
@@ -2516,7 +2905,7 @@ async function doctorCommand(options = {}) {
2516
2905
  severity: "warning",
2517
2906
  check: () => {
2518
2907
  if (!targetDir) return false;
2519
- 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"));
2520
2909
  }
2521
2910
  }
2522
2911
  ];
@@ -2674,9 +3063,9 @@ async function outputReport(projectDir, results, options) {
2674
3063
  }
2675
3064
  }
2676
3065
  }
2677
- const reportPath = join8(projectDir, ".ak", "doctor-report.md");
2678
- await fs8.ensureDir(join8(projectDir, ".ak"));
2679
- 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");
2680
3069
  if (!options.json) {
2681
3070
  console.log(pc7.green(`
2682
3071
  \u2713 Report saved to ${reportPath}
@@ -2749,7 +3138,7 @@ async function outputColored(projectDir, results, state, targetDir) {
2749
3138
  if (!hasState && isProject) {
2750
3139
  console.log(pc7.white(' \u2022 State file is missing. Re-run "ak init" or create manually'));
2751
3140
  }
2752
- if (state && state.source && !fs8.existsSync(state.source)) {
3141
+ if (state && state.source && !fs12.existsSync(state.source)) {
2753
3142
  console.log(pc7.white(" \u2022 Update source path: ak update --source <new-path>"));
2754
3143
  }
2755
3144
  console.log("");
@@ -2790,8 +3179,8 @@ var uninstall_exports = {};
2790
3179
  __export(uninstall_exports, {
2791
3180
  uninstallCommand: () => uninstallCommand
2792
3181
  });
2793
- import fs9 from "fs-extra";
2794
- import { join as join9 } from "path";
3182
+ import fs13 from "fs-extra";
3183
+ import { join as join13 } from "path";
2795
3184
  import pc9 from "picocolors";
2796
3185
  import ora4 from "ora";
2797
3186
  import * as p2 from "@clack/prompts";
@@ -2820,13 +3209,13 @@ async function uninstallFromDir(type, dir, options) {
2820
3209
  const state = await loadState(dir);
2821
3210
  const existingTargets = [];
2822
3211
  for (const [name, folder] of Object.entries(TARGETS)) {
2823
- const targetPath = join9(dir, folder);
2824
- if (fs9.existsSync(targetPath)) {
3212
+ const targetPath = join13(dir, folder);
3213
+ if (fs13.existsSync(targetPath)) {
2825
3214
  existingTargets.push({ name, path: targetPath });
2826
3215
  }
2827
3216
  }
2828
- const akDir = join9(dir, ".ak");
2829
- const hasAkState = fs9.existsSync(akDir);
3217
+ const akDir = join13(dir, ".ak");
3218
+ const hasAkState = fs13.existsSync(akDir);
2830
3219
  if (existingTargets.length === 0 && !hasAkState) {
2831
3220
  spinner.warn(pc9.yellow(`No AK installation found in ${type}`));
2832
3221
  return 0;
@@ -2835,8 +3224,8 @@ async function uninstallFromDir(type, dir, options) {
2835
3224
  const removalList = [];
2836
3225
  for (const target of existingTargets) {
2837
3226
  for (const subdir of AK_SUBDIRS) {
2838
- const subdirPath = join9(target.path, subdir);
2839
- if (fs9.existsSync(subdirPath)) {
3227
+ const subdirPath = join13(target.path, subdir);
3228
+ if (fs13.existsSync(subdirPath)) {
2840
3229
  removalList.push(subdirPath);
2841
3230
  }
2842
3231
  }
@@ -2917,7 +3306,7 @@ async function removeItems(paths, baseDir) {
2917
3306
  continue;
2918
3307
  }
2919
3308
  try {
2920
- await fs9.remove(path);
3309
+ await fs13.remove(path);
2921
3310
  result.removed.push(path);
2922
3311
  } catch (error) {
2923
3312
  result.errors.push({
@@ -3031,10 +3420,10 @@ import { execSync as execSync2 } from "child_process";
3031
3420
  import pc11 from "picocolors";
3032
3421
  import ora6 from "ora";
3033
3422
  import { readFileSync } from "fs";
3034
- import { join as join10 } from "path";
3423
+ import { join as join14 } from "path";
3035
3424
  function getCurrentVersion() {
3036
3425
  try {
3037
- 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"));
3038
3427
  return pkg.version;
3039
3428
  } catch {
3040
3429
  return "0.0.0";
@@ -3094,8 +3483,8 @@ __export(skills_exports, {
3094
3483
  skillsCommand: () => skillsCommand
3095
3484
  });
3096
3485
  import pc12 from "picocolors";
3097
- import fs10 from "fs-extra";
3098
- import { join as join11 } from "path";
3486
+ import fs14 from "fs-extra";
3487
+ import { join as join15 } from "path";
3099
3488
  import * as p3 from "@clack/prompts";
3100
3489
  async function skillsCommand(options) {
3101
3490
  const { name, agent, list, installed, uninstall, yes } = options;
@@ -3173,8 +3562,8 @@ async function installSkill(skillName, agents, skipConfirm) {
3173
3562
  console.log(pc12.red(`Error: ${source.error}`));
3174
3563
  process.exit(1);
3175
3564
  }
3176
- const skillPath = join11(source.claudeDir, "skills", skillName);
3177
- if (!fs10.existsSync(skillPath)) {
3565
+ const skillPath = join15(source.claudeDir, "skills", skillName);
3566
+ if (!fs14.existsSync(skillPath)) {
3178
3567
  console.log(pc12.red(`Error: Skill "${skillName}" not found in source`));
3179
3568
  console.log(pc12.gray(`Available skills: ak skills --list`));
3180
3569
  process.exit(1);
@@ -3191,9 +3580,9 @@ async function installSkill(skillName, agents, skipConfirm) {
3191
3580
  const results = [];
3192
3581
  for (const agent of agents) {
3193
3582
  try {
3194
- const targetPath = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3195
- await fs10.ensureDir(join11(process.cwd(), AGENT_SKILL_PATHS[agent]));
3196
- 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 });
3197
3586
  results.push({ agent, success: true });
3198
3587
  } catch (err) {
3199
3588
  results.push({ agent, success: false, error: err.message });
@@ -3232,8 +3621,8 @@ async function uninstallSkill(skillName, agents, skipConfirm) {
3232
3621
  const results = [];
3233
3622
  for (const agent of installedIn) {
3234
3623
  try {
3235
- const targetPath = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3236
- await fs10.remove(targetPath);
3624
+ const targetPath = join15(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3625
+ await fs14.remove(targetPath);
3237
3626
  results.push({ agent, success: true });
3238
3627
  } catch (err) {
3239
3628
  results.push({ agent, success: false, error: err.message });
@@ -3268,19 +3657,19 @@ function parseAgents(agentFlag) {
3268
3657
  return valid;
3269
3658
  }
3270
3659
  function isSkillInstalled(skillName, agent) {
3271
- const skillPath = join11(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3272
- return fs10.existsSync(skillPath);
3660
+ const skillPath = join15(process.cwd(), AGENT_SKILL_PATHS[agent], skillName);
3661
+ return fs14.existsSync(skillPath);
3273
3662
  }
3274
3663
  function getInstalledSkills(agent) {
3275
- const skillsDir = join11(process.cwd(), AGENT_SKILL_PATHS[agent]);
3276
- if (!fs10.existsSync(skillsDir)) {
3664
+ const skillsDir = join15(process.cwd(), AGENT_SKILL_PATHS[agent]);
3665
+ if (!fs14.existsSync(skillsDir)) {
3277
3666
  return [];
3278
3667
  }
3279
3668
  try {
3280
- const items = fs10.readdirSync(skillsDir);
3669
+ const items = fs14.readdirSync(skillsDir);
3281
3670
  return items.filter((item) => {
3282
- const itemPath = join11(skillsDir, item);
3283
- return fs10.statSync(itemPath).isDirectory();
3671
+ const itemPath = join15(skillsDir, item);
3672
+ return fs14.statSync(itemPath).isDirectory();
3284
3673
  });
3285
3674
  } catch {
3286
3675
  return [];
@@ -3304,7 +3693,7 @@ var init_skills = __esm({
3304
3693
  import cac from "cac";
3305
3694
  import { readFileSync as readFileSync3 } from "fs";
3306
3695
  import { fileURLToPath as fileURLToPath2 } from "url";
3307
- import { dirname as dirname3, join as join13 } from "path";
3696
+ import { dirname as dirname6, join as join17 } from "path";
3308
3697
  import pc13 from "picocolors";
3309
3698
 
3310
3699
  // src/cli/command-registry.ts
@@ -3360,11 +3749,11 @@ function registerCommands(cli2) {
3360
3749
  }
3361
3750
 
3362
3751
  // src/utils/version-check.ts
3363
- import { join as join12 } from "path";
3752
+ import { join as join16 } from "path";
3364
3753
  import { homedir as homedir2 } from "os";
3365
3754
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
3366
- var CACHE_DIR = join12(homedir2(), ".apero-kit");
3367
- 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");
3368
3757
  var CACHE_TTL = 7 * 24 * 60 * 60 * 1e3;
3369
3758
  function getCachedVersionNoFetch() {
3370
3759
  try {
@@ -3388,10 +3777,10 @@ function isNewerVersion(current, latest) {
3388
3777
 
3389
3778
  // src/index.ts
3390
3779
  var __filename2 = fileURLToPath2(import.meta.url);
3391
- var __dirname2 = dirname3(__filename2);
3780
+ var __dirname2 = dirname6(__filename2);
3392
3781
  function getVersion() {
3393
3782
  try {
3394
- const pkg = JSON.parse(readFileSync3(join13(__dirname2, "..", "package.json"), "utf-8"));
3783
+ const pkg = JSON.parse(readFileSync3(join17(__dirname2, "..", "package.json"), "utf-8"));
3395
3784
  return pkg.version;
3396
3785
  } catch {
3397
3786
  return "0.0.0";