@tdsoft-tech/aikit 0.1.4 → 0.1.6

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/cli.js CHANGED
@@ -169,7 +169,7 @@ __export(figma_mcp_exports, {
169
169
  FigmaMcpClient: () => FigmaMcpClient
170
170
  });
171
171
  import { writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
172
- import { join as join5 } from "path";
172
+ import { join as join6 } from "path";
173
173
  import { existsSync as existsSync2 } from "fs";
174
174
  var FigmaMcpClient;
175
175
  var init_figma_mcp = __esm({
@@ -179,10 +179,8 @@ var init_figma_mcp = __esm({
179
179
  init_logger();
180
180
  FigmaMcpClient = class {
181
181
  apiKey;
182
- configManager;
183
- constructor(apiKey, configManager) {
182
+ constructor(apiKey, _configManager) {
184
183
  this.apiKey = apiKey;
185
- this.configManager = configManager;
186
184
  }
187
185
  /**
188
186
  * Fetch helper with simple retry/backoff for 429/5xx
@@ -328,7 +326,6 @@ ${text}`);
328
326
  if (fill.type === "SOLID" && fill.color) {
329
327
  const { r, g, b, a } = fill.color;
330
328
  const hex = this.rgbaToHex(r, g, b, a);
331
- const name = node.name || "Color";
332
329
  if (!colorMap.has(hex)) {
333
330
  colorMap.set(hex, hex);
334
331
  }
@@ -531,7 +528,7 @@ ${text}`);
531
528
  }, "Figma images listing");
532
529
  const imageData = await response.json();
533
530
  const images = imageData.images;
534
- const fullAssetsDir = assetsDir.startsWith("/") ? assetsDir : join5(process.cwd(), assetsDir);
531
+ const fullAssetsDir = assetsDir.startsWith("/") ? assetsDir : join6(process.cwd(), assetsDir);
535
532
  if (!existsSync2(fullAssetsDir)) {
536
533
  await mkdir3(fullAssetsDir, { recursive: true });
537
534
  }
@@ -552,7 +549,7 @@ ${text}`);
552
549
  const safeName = node.name.replace(/[^a-z0-9]/gi, "_").toLowerCase().substring(0, 50);
553
550
  const extension = "png";
554
551
  const filename = `${safeName}_${node.id.substring(0, 8)}.${extension}`;
555
- const filePath = join5(fullAssetsDir, filename);
552
+ const filePath = join6(fullAssetsDir, filename);
556
553
  await writeFile3(filePath, Buffer.from(imageBuffer));
557
554
  downloadedAssets.push({
558
555
  nodeId: node.id,
@@ -593,7 +590,7 @@ __export(figma_screen_developer_exports, {
593
590
  compareCodeWithFigma: () => compareCodeWithFigma
594
591
  });
595
592
  import { readFile as readFile4, readdir as readdir3 } from "fs/promises";
596
- import { join as join6 } from "path";
593
+ import { join as join7 } from "path";
597
594
  import { existsSync as existsSync3 } from "fs";
598
595
  async function checkCurrentCodeStatus(projectPath = process.cwd()) {
599
596
  const status = {
@@ -607,13 +604,13 @@ async function checkCurrentCodeStatus(projectPath = process.cwd()) {
607
604
  };
608
605
  try {
609
606
  const htmlFiles = ["index.html", "index.htm", "main.html"].filter(
610
- (file) => existsSync3(join6(projectPath, file))
607
+ (file) => existsSync3(join7(projectPath, file))
611
608
  );
612
609
  if (htmlFiles.length > 0) {
613
610
  status.hasHTML = true;
614
611
  status.htmlFile = htmlFiles[0];
615
612
  try {
616
- const htmlContent = await readFile4(join6(projectPath, htmlFiles[0]), "utf-8");
613
+ const htmlContent = await readFile4(join7(projectPath, htmlFiles[0]), "utf-8");
617
614
  const sectionMatches = htmlContent.match(/<(section|div|header|footer|main|article|aside)[^>]*(?:id|class)=["']([^"']+)["']/gi);
618
615
  if (sectionMatches) {
619
616
  status.sections = sectionMatches.map((match) => {
@@ -625,19 +622,19 @@ async function checkCurrentCodeStatus(projectPath = process.cwd()) {
625
622
  } catch (e) {
626
623
  }
627
624
  }
628
- const stylesDir = join6(projectPath, "styles");
625
+ const stylesDir = join7(projectPath, "styles");
629
626
  if (existsSync3(stylesDir)) {
630
627
  try {
631
628
  const files = await readdir3(stylesDir);
632
629
  const cssFiles = files.filter((f) => f.endsWith(".css"));
633
630
  if (cssFiles.length > 0) {
634
631
  status.hasCSS = true;
635
- status.cssFiles = cssFiles.map((f) => join6(stylesDir, f));
632
+ status.cssFiles = cssFiles.map((f) => join7(stylesDir, f));
636
633
  }
637
634
  } catch (e) {
638
635
  }
639
636
  }
640
- const assetsDir = join6(projectPath, "assets", "images");
637
+ const assetsDir = join7(projectPath, "assets", "images");
641
638
  if (existsSync3(assetsDir)) {
642
639
  try {
643
640
  const files = await readdir3(assetsDir);
@@ -716,7 +713,7 @@ __export(memory_exports, {
716
713
  MemoryManager: () => MemoryManager
717
714
  });
718
715
  import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4, access as access2, constants as constants2 } from "fs/promises";
719
- import { join as join7 } from "path";
716
+ import { join as join8 } from "path";
720
717
  var MemoryManager;
721
718
  var init_memory = __esm({
722
719
  "src/core/memory.ts"() {
@@ -736,13 +733,13 @@ var init_memory = __esm({
736
733
  const memoryPath = paths.memory(this.config.configPath);
737
734
  const subDirs = ["observations", "handoffs", "research"];
738
735
  for (const subDir of subDirs) {
739
- const dirPath = join7(memoryPath, subDir);
736
+ const dirPath = join8(memoryPath, subDir);
740
737
  try {
741
738
  const { readdir: readdir7 } = await import("fs/promises");
742
739
  const files = await readdir7(dirPath);
743
740
  for (const file of files) {
744
741
  if (!file.endsWith(".md")) continue;
745
- const content = await readFile5(join7(dirPath, file), "utf-8");
742
+ const content = await readFile5(join8(dirPath, file), "utf-8");
746
743
  const summary = this.extractSummary(content);
747
744
  memories.push({
748
745
  key: `${subDir}/${file.replace(".md", "")}`,
@@ -766,11 +763,11 @@ var init_memory = __esm({
766
763
  const memoryPath = paths.memory(this.config.configPath);
767
764
  let filePath;
768
765
  if (key.includes("/")) {
769
- filePath = join7(memoryPath, `${key}.md`);
766
+ filePath = join8(memoryPath, `${key}.md`);
770
767
  } else {
771
768
  const subDirs = ["observations", "handoffs", "research", "_templates"];
772
769
  for (const subDir of subDirs) {
773
- const testPath = join7(memoryPath, subDir, `${key}.md`);
770
+ const testPath = join8(memoryPath, subDir, `${key}.md`);
774
771
  try {
775
772
  await access2(testPath, constants2.R_OK);
776
773
  filePath = testPath;
@@ -779,7 +776,7 @@ var init_memory = __esm({
779
776
  continue;
780
777
  }
781
778
  }
782
- filePath = filePath || join7(memoryPath, `${key}.md`);
779
+ filePath = filePath || join8(memoryPath, `${key}.md`);
783
780
  }
784
781
  try {
785
782
  return await readFile5(filePath, "utf-8");
@@ -795,10 +792,10 @@ var init_memory = __esm({
795
792
  const type = options?.type || "custom";
796
793
  let filePath;
797
794
  if (key.includes("/")) {
798
- filePath = join7(memoryPath, `${key}.md`);
795
+ filePath = join8(memoryPath, `${key}.md`);
799
796
  } else {
800
797
  const subDir = type === "observation" ? "observations" : type === "handoff" ? "handoffs" : type === "research" ? "research" : "";
801
- filePath = join7(memoryPath, subDir, `${key}.md`);
798
+ filePath = join8(memoryPath, subDir, `${key}.md`);
802
799
  }
803
800
  const { dirname: dirname2 } = await import("path");
804
801
  await mkdir4(dirname2(filePath), { recursive: true });
@@ -932,7 +929,7 @@ __export(tool_config_exports, {
932
929
  ToolConfigManager: () => ToolConfigManager
933
930
  });
934
931
  import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8, access as access4, constants as constants4 } from "fs/promises";
935
- import { join as join11 } from "path";
932
+ import { join as join13 } from "path";
936
933
  import { z as z3 } from "zod";
937
934
  var ToolConfigSchema, REGISTERED_TOOLS, ToolConfigManager;
938
935
  var init_tool_config = __esm({
@@ -960,7 +957,7 @@ var init_tool_config = __esm({
960
957
  toolsConfigPath;
961
958
  constructor(config) {
962
959
  this.config = config;
963
- this.toolsConfigPath = join11(this.config.configPath, "config", "tools.json");
960
+ this.toolsConfigPath = join13(this.config.configPath, "config", "tools.json");
964
961
  }
965
962
  /**
966
963
  * Get all registered tools with their current status
@@ -1054,7 +1051,7 @@ var init_tool_config = __esm({
1054
1051
  * Save configurations
1055
1052
  */
1056
1053
  async saveConfigs(configs) {
1057
- const configDir = join11(this.config.configPath, "config");
1054
+ const configDir = join13(this.config.configPath, "config");
1058
1055
  await mkdir8(configDir, { recursive: true });
1059
1056
  await writeFile8(this.toolsConfigPath, JSON.stringify(configs, null, 2));
1060
1057
  }
@@ -1103,8 +1100,8 @@ var init_figma_oauth = __esm({
1103
1100
  console.log('3. Give it a name (e.g., "AIKit")');
1104
1101
  console.log("4. Copy the token (you won't see it again!)");
1105
1102
  console.log("5. Paste it here when prompted\n");
1106
- const { default: inquirer } = await import("inquirer");
1107
- const { token } = await inquirer.prompt([
1103
+ const { default: inquirer2 } = await import("inquirer");
1104
+ const { token } = await inquirer2.prompt([
1108
1105
  {
1109
1106
  type: "password",
1110
1107
  name: "token",
@@ -1134,14 +1131,14 @@ var init_figma_oauth = __esm({
1134
1131
  * Alternative: Manual token input
1135
1132
  */
1136
1133
  async authenticateManual() {
1137
- const { default: inquirer } = await import("inquirer");
1134
+ const { default: inquirer2 } = await import("inquirer");
1138
1135
  console.log("\n\u{1F510} Figma Authentication (Manual)\n");
1139
1136
  console.log("To get your Figma Personal Access Token:");
1140
1137
  console.log("1. Visit: https://www.figma.com/developers/api#access-tokens");
1141
1138
  console.log('2. Scroll to "Personal access tokens"');
1142
1139
  console.log('3. Click "Create new token"');
1143
1140
  console.log("4. Copy the token and paste it below\n");
1144
- const { token } = await inquirer.prompt([
1141
+ const { token } = await inquirer2.prompt([
1145
1142
  {
1146
1143
  type: "password",
1147
1144
  name: "token",
@@ -1195,6 +1192,7 @@ var init_figma_oauth = __esm({
1195
1192
  init_esm_shims();
1196
1193
  import { Command } from "commander";
1197
1194
  import chalk2 from "chalk";
1195
+ import inquirer from "inquirer";
1198
1196
 
1199
1197
  // src/index.ts
1200
1198
  init_esm_shims();
@@ -1203,8 +1201,28 @@ init_esm_shims();
1203
1201
  init_esm_shims();
1204
1202
  init_paths();
1205
1203
  import { readFile, access, constants } from "fs/promises";
1206
- import { join as join2 } from "path";
1204
+ import { join as join3 } from "path";
1207
1205
  import { z } from "zod";
1206
+
1207
+ // src/utils/version.ts
1208
+ init_esm_shims();
1209
+ import { readFileSync } from "fs";
1210
+ import { fileURLToPath as fileURLToPath2 } from "url";
1211
+ import { dirname, join as join2 } from "path";
1212
+ function getVersion() {
1213
+ try {
1214
+ const __filename2 = fileURLToPath2(import.meta.url);
1215
+ const __dirname2 = dirname(__filename2);
1216
+ const packageJsonPath = join2(__dirname2, "..", "package.json");
1217
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
1218
+ return packageJson.version;
1219
+ } catch (error) {
1220
+ console.warn("Warning: Could not read version from package.json, using fallback");
1221
+ return "0.0.0";
1222
+ }
1223
+ }
1224
+
1225
+ // src/core/config.ts
1208
1226
  var ConfigSchema = z.object({
1209
1227
  version: z.string(),
1210
1228
  skills: z.object({
@@ -1296,23 +1314,23 @@ async function loadConfig(projectPath) {
1296
1314
  let configPath;
1297
1315
  let configData = {};
1298
1316
  try {
1299
- await access(join2(globalConfigPath, "aikit.json"), constants.R_OK);
1300
- const globalContent = await readFile(join2(globalConfigPath, "aikit.json"), "utf-8");
1317
+ await access(join3(globalConfigPath, "aikit.json"), constants.R_OK);
1318
+ const globalContent = await readFile(join3(globalConfigPath, "aikit.json"), "utf-8");
1301
1319
  configData = JSON.parse(globalContent);
1302
1320
  configPath = globalConfigPath;
1303
1321
  } catch {
1304
1322
  configPath = projectConfigPath;
1305
1323
  }
1306
1324
  try {
1307
- await access(join2(projectConfigPath, "aikit.json"), constants.R_OK);
1308
- const projectContent = await readFile(join2(projectConfigPath, "aikit.json"), "utf-8");
1325
+ await access(join3(projectConfigPath, "aikit.json"), constants.R_OK);
1326
+ const projectContent = await readFile(join3(projectConfigPath, "aikit.json"), "utf-8");
1309
1327
  const projectData = JSON.parse(projectContent);
1310
1328
  configData = deepMerge(configData, projectData);
1311
1329
  configPath = projectConfigPath;
1312
1330
  } catch {
1313
1331
  }
1314
1332
  if (!configData.version) {
1315
- configData.version = "0.1.0";
1333
+ configData.version = getVersion();
1316
1334
  }
1317
1335
  const parsed = ConfigSchema.parse(configData);
1318
1336
  return new Config({
@@ -1341,8 +1359,9 @@ function deepMerge(base, override) {
1341
1359
  // src/core/skills.ts
1342
1360
  init_esm_shims();
1343
1361
  init_paths();
1362
+ init_logger();
1344
1363
  import { readFile as readFile2, readdir, writeFile, mkdir } from "fs/promises";
1345
- import { join as join3, basename, extname } from "path";
1364
+ import { join as join4, basename, extname } from "path";
1346
1365
  import matter from "gray-matter";
1347
1366
  var SkillEngine = class {
1348
1367
  config;
@@ -1413,7 +1432,7 @@ var SkillEngine = class {
1413
1432
  const skillsDir = paths.skills(configPath);
1414
1433
  await mkdir(skillsDir, { recursive: true });
1415
1434
  const fileName = `${name.replace(/\s+/g, "-").toLowerCase()}.md`;
1416
- const filePath = join3(skillsDir, fileName);
1435
+ const filePath = join4(skillsDir, fileName);
1417
1436
  const frontmatter = {
1418
1437
  name,
1419
1438
  description: options?.description || `Use when you need to ${name}`,
@@ -1474,12 +1493,22 @@ Describe what this skill does.
1474
1493
  if (globalSkillsPath === projectSkillsPath) {
1475
1494
  return { count: 0, synced: [] };
1476
1495
  }
1477
- const globalSkills = await this.loadSkillsFromDir(globalSkillsPath);
1496
+ let globalSkills = [];
1497
+ try {
1498
+ globalSkills = await this.loadSkillsFromDir(globalSkillsPath);
1499
+ } catch (error) {
1500
+ logger.warn("Global skills directory not found. Skipping sync.");
1501
+ return { count: 0, synced: [] };
1502
+ }
1503
+ if (globalSkills.length === 0) {
1504
+ logger.info("No global skills to sync.");
1505
+ return { count: 0, synced: [] };
1506
+ }
1478
1507
  await mkdir(projectSkillsPath, { recursive: true });
1479
1508
  const synced = [];
1480
1509
  for (const skill of globalSkills) {
1481
1510
  const fileName = `${skill.name.replace(/\s+/g, "-").toLowerCase()}.md`;
1482
- const destPath = join3(projectSkillsPath, fileName);
1511
+ const destPath = join4(projectSkillsPath, fileName);
1483
1512
  const srcContent = await readFile2(skill.filePath, "utf-8");
1484
1513
  await writeFile(destPath, srcContent);
1485
1514
  synced.push(skill.name);
@@ -1513,7 +1542,7 @@ ${skill.content}
1513
1542
  const skills = [];
1514
1543
  for (const file of files) {
1515
1544
  if (extname(file) !== ".md") continue;
1516
- const filePath = join3(dir, file);
1545
+ const filePath = join4(dir, file);
1517
1546
  const content = await readFile2(filePath, "utf-8");
1518
1547
  const { data, content: body } = matter(content);
1519
1548
  const frontmatter = data;
@@ -1853,7 +1882,7 @@ ${agent.delegatesTo.map((a) => `- @${a}`).join("\n")}` : ""}
1853
1882
  init_esm_shims();
1854
1883
  init_paths();
1855
1884
  import { readFile as readFile3, readdir as readdir2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1856
- import { join as join4, basename as basename2, extname as extname2 } from "path";
1885
+ import { join as join5, basename as basename2, extname as extname2 } from "path";
1857
1886
  import matter2 from "gray-matter";
1858
1887
  var DEFAULT_COMMANDS = [
1859
1888
  // Core Workflow Commands (Beads integration)
@@ -2545,10 +2574,10 @@ var CommandRunner = class {
2545
2574
  async createCommand(name, options) {
2546
2575
  const configPath = options?.global ? paths.globalConfig() : this.config.configPath;
2547
2576
  const category = options?.category || "utility";
2548
- const commandsDir = join4(paths.commands(configPath), category);
2577
+ const commandsDir = join5(paths.commands(configPath), category);
2549
2578
  await mkdir2(commandsDir, { recursive: true });
2550
2579
  const fileName = `${name}.md`;
2551
- const filePath = join4(commandsDir, fileName);
2580
+ const filePath = join5(commandsDir, fileName);
2552
2581
  const frontmatter = {
2553
2582
  name,
2554
2583
  description: options?.description || `Custom command: ${name}`,
@@ -2607,7 +2636,7 @@ ${command.content}
2607
2636
  try {
2608
2637
  const entries = await readdir2(currentDir, { withFileTypes: true });
2609
2638
  for (const entry of entries) {
2610
- const fullPath = join4(currentDir, entry.name);
2639
+ const fullPath = join5(currentDir, entry.name);
2611
2640
  if (entry.isDirectory()) {
2612
2641
  await processDir(fullPath, entry.name);
2613
2642
  } else if (extname2(entry.name) === ".md") {
@@ -2640,7 +2669,7 @@ init_esm_shims();
2640
2669
  init_paths();
2641
2670
  init_logger();
2642
2671
  import { readdir as readdir4, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
2643
- import { join as join8, extname as extname3 } from "path";
2672
+ import { join as join9, extname as extname3 } from "path";
2644
2673
  import { z as z2 } from "zod";
2645
2674
  var ToolArgSchema = z2.object({
2646
2675
  type: z2.enum(["string", "number", "boolean", "array", "object"]),
@@ -3102,7 +3131,7 @@ ${tokens.screens?.map((s, i) => `${i + 1}. ${s.name} (ID: ${s.id})`).join("\n")
3102
3131
  try {
3103
3132
  const fileData = await client.getFileData(figmaUrl);
3104
3133
  const projectPath = process.cwd();
3105
- const assetsDir = join8(projectPath, "assets", "images");
3134
+ const assetsDir = join9(projectPath, "assets", "images");
3106
3135
  const assets = await client.downloadAssets(fileKey, fileData.document, assetsDir, selectedScreen.id);
3107
3136
  downloadedAssets = assets || [];
3108
3137
  logger.info(`Downloaded ${downloadedAssets.length} assets for screen ${selectedScreen.name}`);
@@ -3348,7 +3377,7 @@ var ToolRegistry = class {
3348
3377
  const toolsDir = paths.tools(configPath);
3349
3378
  await mkdir5(toolsDir, { recursive: true });
3350
3379
  const fileName = `${name}.ts`;
3351
- const filePath = join8(toolsDir, fileName);
3380
+ const filePath = join9(toolsDir, fileName);
3352
3381
  const argsSchema = Object.entries(options.args).map(([argName, arg]) => ` ${argName}: {
3353
3382
  type: '${arg.type}',
3354
3383
  description: '${arg.description}',
@@ -3402,7 +3431,7 @@ ${argsDesc}
3402
3431
  }
3403
3432
  for (const file of files) {
3404
3433
  if (extname3(file) !== ".ts" && extname3(file) !== ".js") continue;
3405
- const filePath = join8(dir, file);
3434
+ const filePath = join9(dir, file);
3406
3435
  try {
3407
3436
  const toolModule = await import(`file://${filePath}`);
3408
3437
  const tool = toolModule.default;
@@ -3422,7 +3451,7 @@ init_esm_shims();
3422
3451
  init_paths();
3423
3452
  init_logger();
3424
3453
  import { readdir as readdir5, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
3425
- import { join as join9, basename as basename3, extname as extname4 } from "path";
3454
+ import { join as join10, basename as basename3, extname as extname4 } from "path";
3426
3455
  var PluginSystem = class {
3427
3456
  config;
3428
3457
  plugins = /* @__PURE__ */ new Map();
@@ -3522,7 +3551,7 @@ var PluginSystem = class {
3522
3551
  const pluginsDir = paths.plugins(configPath);
3523
3552
  await mkdir6(pluginsDir, { recursive: true });
3524
3553
  const fileName = `${name}.ts`;
3525
- const filePath = join9(pluginsDir, fileName);
3554
+ const filePath = join10(pluginsDir, fileName);
3526
3555
  const content = `import { Plugin } from 'aikit';
3527
3556
 
3528
3557
  /**
@@ -3612,7 +3641,7 @@ export default ${toPascalCase(name)}Plugin;
3612
3641
  }
3613
3642
  for (const file of files) {
3614
3643
  if (extname4(file) !== ".ts" && extname4(file) !== ".js") continue;
3615
- const filePath = join9(dir, file);
3644
+ const filePath = join10(dir, file);
3616
3645
  const name = basename3(file, extname4(file));
3617
3646
  this.plugins.set(name, {
3618
3647
  name,
@@ -3719,7 +3748,7 @@ init_esm_shims();
3719
3748
  init_paths();
3720
3749
  init_logger();
3721
3750
  import { readFile as readFile6, writeFile as writeFile7, readdir as readdir6, access as access3, constants as constants3, mkdir as mkdir7 } from "fs/promises";
3722
- import { join as join10 } from "path";
3751
+ import { join as join11 } from "path";
3723
3752
  import { exec } from "child_process";
3724
3753
  import { promisify } from "util";
3725
3754
  var execAsync = promisify(exec);
@@ -3764,7 +3793,19 @@ var BeadsIntegration = class {
3764
3793
  }
3765
3794
  }
3766
3795
  /**
3767
- * Initialize Beads in project
3796
+ * Install Beads CLI globally
3797
+ */
3798
+ async install() {
3799
+ try {
3800
+ await execAsync("npm install -g beads");
3801
+ return true;
3802
+ } catch (error) {
3803
+ logger.error("Failed to install Beads CLI:", error);
3804
+ return false;
3805
+ }
3806
+ }
3807
+ /**
3808
+ * Initialize Beads in project using bd CLI
3768
3809
  */
3769
3810
  async init() {
3770
3811
  try {
@@ -3776,6 +3817,44 @@ var BeadsIntegration = class {
3776
3817
  return false;
3777
3818
  }
3778
3819
  }
3820
+ /**
3821
+ * Initialize local .beads directory (works without global beads CLI)
3822
+ */
3823
+ async initLocal() {
3824
+ try {
3825
+ const beadsDir = paths.beadsDir(this.projectPath);
3826
+ await mkdir7(beadsDir, { recursive: true });
3827
+ const readmeContent = `# Beads - Task Tracking
3828
+
3829
+ This directory contains task beads for tracking work items.
3830
+
3831
+ ## How it works
3832
+ - Each file is a task bead (bead-001.md, bead-002.md, etc.)
3833
+ - Status: todo, in-progress, completed, blocked
3834
+ - Use \`/create\` command to create new tasks
3835
+ - Use \`/finish\` command to complete tasks with quality gates
3836
+
3837
+ ## Beads CLI
3838
+ For full functionality, install beads globally:
3839
+ \`\`\`bash
3840
+ npm install -g beads
3841
+ bd init
3842
+ \`\`\`
3843
+
3844
+ ## Available Commands
3845
+ - \`bd ready\` - Show available work
3846
+ - \`bd show <id>\` - View task details
3847
+ - \`bd update <id> --status in_progress\` - Update task status
3848
+ - \`bd close <id>\` - Complete task
3849
+ - \`bd sync\` - Sync with git
3850
+ `;
3851
+ await writeFile7(join11(beadsDir, "README.md"), readmeContent);
3852
+ return true;
3853
+ } catch (error) {
3854
+ logger.error("Failed to initialize .beads directory:", error);
3855
+ return false;
3856
+ }
3857
+ }
3779
3858
  /**
3780
3859
  * Get current status
3781
3860
  */
@@ -3812,7 +3891,7 @@ var BeadsIntegration = class {
3812
3891
  const files = await readdir6(beadsDir);
3813
3892
  for (const file of files) {
3814
3893
  if (!file.match(/^bead-\d+\.md$/)) continue;
3815
- const content = await readFile6(join10(beadsDir, file), "utf-8");
3894
+ const content = await readFile6(join11(beadsDir, file), "utf-8");
3816
3895
  const bead = this.parseBeadFile(file, content);
3817
3896
  if (bead) beads.push(bead);
3818
3897
  }
@@ -3827,7 +3906,7 @@ var BeadsIntegration = class {
3827
3906
  const beadsDir = paths.beadsDir(this.projectPath);
3828
3907
  const fileName = id.endsWith(".md") ? id : `${id}.md`;
3829
3908
  try {
3830
- const content = await readFile6(join10(beadsDir, fileName), "utf-8");
3909
+ const content = await readFile6(join11(beadsDir, fileName), "utf-8");
3831
3910
  return this.parseBeadFile(fileName, content);
3832
3911
  } catch {
3833
3912
  return null;
@@ -3871,7 +3950,7 @@ ${description}
3871
3950
  ## Progress
3872
3951
 
3873
3952
  `;
3874
- await writeFile7(join10(beadsDir, `${id}.md`), content);
3953
+ await writeFile7(join11(beadsDir, `${id}.md`), content);
3875
3954
  return {
3876
3955
  id,
3877
3956
  title,
@@ -3888,7 +3967,7 @@ ${description}
3888
3967
  async updateBeadStatus(id, status) {
3889
3968
  const beadsDir = paths.beadsDir(this.projectPath);
3890
3969
  const fileName = id.endsWith(".md") ? id : `${id}.md`;
3891
- const filePath = join10(beadsDir, fileName);
3970
+ const filePath = join11(beadsDir, fileName);
3892
3971
  try {
3893
3972
  let content = await readFile6(filePath, "utf-8");
3894
3973
  content = content.replace(
@@ -3911,7 +3990,7 @@ ${description}
3911
3990
  async addNote(id, note) {
3912
3991
  const beadsDir = paths.beadsDir(this.projectPath);
3913
3992
  const fileName = id.endsWith(".md") ? id : `${id}.md`;
3914
- const filePath = join10(beadsDir, fileName);
3993
+ const filePath = join11(beadsDir, fileName);
3915
3994
  try {
3916
3995
  let content = await readFile6(filePath, "utf-8");
3917
3996
  const notesMatch = content.match(/## Notes\n([\s\S]*?)(?=\n##|$)/);
@@ -4020,14 +4099,125 @@ init_logger();
4020
4099
  // src/index.ts
4021
4100
  init_logger();
4022
4101
  init_paths();
4023
- var VERSION = "0.1.4";
4024
4102
 
4025
4103
  // src/cli.ts
4026
4104
  init_memory();
4105
+
4106
+ // src/utils/cli-detector.ts
4107
+ init_esm_shims();
4108
+ import { execSync } from "child_process";
4109
+ import { existsSync as existsSync4 } from "fs";
4110
+ import { join as join12 } from "path";
4111
+ import { homedir as homedir2 } from "os";
4112
+ var CliDetector = class {
4113
+ /**
4114
+ * Check if OpenCode is installed
4115
+ */
4116
+ static async checkOpenCode() {
4117
+ try {
4118
+ const opencodePath = process.platform === "win32" ? process.env.APPDATA || join12(homedir2(), "AppData", "Roaming") : join12(homedir2(), ".config");
4119
+ const opencodeConfig = join12(opencodePath, "opencode", "opencode.json");
4120
+ const installed = existsSync4(opencodeConfig);
4121
+ let version;
4122
+ if (installed) {
4123
+ try {
4124
+ execSync("opencode --version", { stdio: "ignore" });
4125
+ version = "installed";
4126
+ } catch {
4127
+ }
4128
+ }
4129
+ return {
4130
+ name: "opencode" /* OPENCODE */,
4131
+ displayName: "OpenCode",
4132
+ detected: true,
4133
+ installed,
4134
+ version,
4135
+ configPath: opencodeConfig
4136
+ };
4137
+ } catch {
4138
+ return {
4139
+ name: "opencode" /* OPENCODE */,
4140
+ displayName: "OpenCode",
4141
+ detected: false,
4142
+ installed: false
4143
+ };
4144
+ }
4145
+ }
4146
+ /**
4147
+ * Check if Claude CLI is installed
4148
+ */
4149
+ static async checkClaude() {
4150
+ try {
4151
+ execSync("claude --version", { stdio: "ignore" });
4152
+ return {
4153
+ name: "claude" /* CLAUDE */,
4154
+ displayName: "Claude CLI",
4155
+ detected: true,
4156
+ installed: true,
4157
+ version: "installed"
4158
+ };
4159
+ } catch {
4160
+ return {
4161
+ name: "claude" /* CLAUDE */,
4162
+ displayName: "Claude CLI",
4163
+ detected: true,
4164
+ installed: false
4165
+ };
4166
+ }
4167
+ }
4168
+ /**
4169
+ * Check if GitHub CLI is installed
4170
+ */
4171
+ static async checkGitHub() {
4172
+ try {
4173
+ const output = execSync("gh --version", { stdio: "pipe", encoding: "utf-8" });
4174
+ const match = output.match(/gh version ([\d.]+)/);
4175
+ const version = match?.[1];
4176
+ return {
4177
+ name: "github" /* GITHUB */,
4178
+ displayName: "GitHub CLI",
4179
+ detected: true,
4180
+ installed: true,
4181
+ version
4182
+ };
4183
+ } catch {
4184
+ return {
4185
+ name: "github" /* GITHUB */,
4186
+ displayName: "GitHub CLI",
4187
+ detected: true,
4188
+ installed: false
4189
+ };
4190
+ }
4191
+ }
4192
+ /**
4193
+ * Check all supported CLIs
4194
+ */
4195
+ static async checkAll() {
4196
+ const results = [];
4197
+ results.push(await this.checkOpenCode());
4198
+ results.push(await this.checkClaude());
4199
+ results.push(await this.checkGitHub());
4200
+ return results;
4201
+ }
4202
+ /**
4203
+ * Filter tools by installation status
4204
+ */
4205
+ static filterInstalled(tools) {
4206
+ return tools.filter((t) => !t.installed && t.detected);
4207
+ }
4208
+ /**
4209
+ * Filter tools that can be installed
4210
+ */
4211
+ static filterInstallable(tools) {
4212
+ return tools.filter((t) => t.detected && !t.installed);
4213
+ }
4214
+ };
4215
+
4216
+ // src/cli.ts
4027
4217
  init_logger();
4028
4218
  init_paths();
4029
4219
  var program = new Command();
4030
- program.name("aikit").description("Open-source AI coding agent toolkit for OpenCode").version(VERSION);
4220
+ program.name("aikit").description("Open-source AI coding agent toolkit for OpenCode").version(getVersion());
4031
4221
  program.command("init").description("Initialize AIKit configuration").option("-g, --global", "Initialize global configuration").option("-p, --project", "Initialize project-level configuration").action(async (options) => {
4032
4222
  const configDir = options.global ? paths.globalConfig() : paths.projectConfig();
4033
4223
  console.log(chalk2.bold("\n\u{1F680} AIKit Setup\n"));
@@ -4042,14 +4232,54 @@ program.command("init").description("Initialize AIKit configuration").option("-g
4042
4232
  if (result.count > 0) {
4043
4233
  logger.success(`\u2713 Synced ${result.count} skills`);
4044
4234
  }
4235
+ console.log(chalk2.bold("\n\u{1F50D} Checking CLI tools...\n"));
4236
+ const cliTools = await CliDetector.checkAll();
4237
+ const installableTools = CliDetector.filterInstallable(cliTools);
4238
+ for (const tool of cliTools) {
4239
+ const status = tool.installed ? chalk2.green("\u2713 Installed") : chalk2.yellow("\u2717 Not installed");
4240
+ const version = tool.version ? chalk2.gray(` (${tool.version})`) : "";
4241
+ console.log(` ${status} ${chalk2.cyan(tool.displayName)}${version}`);
4242
+ }
4243
+ if (installableTools.length > 0) {
4244
+ console.log();
4245
+ const { installTools } = await inquirer.prompt([
4246
+ {
4247
+ type: "checkbox",
4248
+ name: "installTools",
4249
+ message: "Select CLI tools to install (press Enter to skip):",
4250
+ choices: installableTools.map((tool) => ({
4251
+ name: tool.name,
4252
+ value: tool,
4253
+ checked: true
4254
+ // Default to install all
4255
+ }))
4256
+ }
4257
+ ]);
4258
+ if (installTools.length > 0) {
4259
+ console.log();
4260
+ logger.info(`Installing ${installTools.length} CLI tool(s)...`);
4261
+ for (const tool of installTools) {
4262
+ await installCliTool(tool);
4263
+ }
4264
+ console.log();
4265
+ logger.success("\u2713 CLI tools installed");
4266
+ } else {
4267
+ console.log();
4268
+ logger.info("Skipping CLI tool installation");
4269
+ }
4270
+ } else {
4271
+ console.log();
4272
+ logger.success("\u2713 All CLI tools already installed");
4273
+ }
4045
4274
  const beads = new BeadsIntegration();
4046
4275
  const beadsStatus = await beads.getStatus();
4047
- if (!beadsStatus.installed) {
4048
- logger.warn("Beads not installed. Please install it manually with: npm install -g beads");
4049
- } else if (!beadsStatus.initialized) {
4050
- logger.info("Initializing beads...");
4051
- await beads.init();
4052
- logger.success("\u2713 Beads initialized");
4276
+ if (!beadsStatus.initialized) {
4277
+ logger.info("Initializing .beads directory...");
4278
+ await beads.initLocal();
4279
+ logger.success("\u2713 .beads directory created");
4280
+ if (!beadsStatus.installed) {
4281
+ logger.info("Tip: Install Beads CLI globally for full functionality: npm install -g beads");
4282
+ }
4053
4283
  } else {
4054
4284
  logger.info("Beads already initialized");
4055
4285
  }
@@ -4372,7 +4602,7 @@ beadsCmd.command("status").description("Show current Beads status").action(async
4372
4602
  });
4373
4603
  program.command("status").description("Show AIKit status").action(async () => {
4374
4604
  console.log(chalk2.bold(`
4375
- \u{1F680} AIKit v${VERSION}
4605
+ \u{1F680} AIKit v${getVersion}
4376
4606
  `));
4377
4607
  try {
4378
4608
  const config = await loadConfig();
@@ -4399,7 +4629,7 @@ program.command("status").description("Show AIKit status").action(async () => {
4399
4629
  });
4400
4630
  async function initializeConfig(configDir, _isGlobal) {
4401
4631
  const { mkdir: mkdir9, writeFile: writeFile9 } = await import("fs/promises");
4402
- const { join: join12 } = await import("path");
4632
+ const { join: join14 } = await import("path");
4403
4633
  const dirs = [
4404
4634
  "",
4405
4635
  "skills",
@@ -4418,10 +4648,10 @@ async function initializeConfig(configDir, _isGlobal) {
4418
4648
  "memory/research"
4419
4649
  ];
4420
4650
  for (const dir of dirs) {
4421
- await mkdir9(join12(configDir, dir), { recursive: true });
4651
+ await mkdir9(join14(configDir, dir), { recursive: true });
4422
4652
  }
4423
4653
  const defaultConfig = {
4424
- version: VERSION,
4654
+ version: getVersion,
4425
4655
  skills: { enabled: true },
4426
4656
  agents: { enabled: true, default: "build" },
4427
4657
  commands: { enabled: true },
@@ -4432,7 +4662,7 @@ async function initializeConfig(configDir, _isGlobal) {
4432
4662
  antiHallucination: { enabled: true }
4433
4663
  };
4434
4664
  await writeFile9(
4435
- join12(configDir, "aikit.json"),
4665
+ join14(configDir, "aikit.json"),
4436
4666
  JSON.stringify(defaultConfig, null, 2)
4437
4667
  );
4438
4668
  const agentsMd = `# AIKit Agent Rules
@@ -4455,26 +4685,26 @@ async function initializeConfig(configDir, _isGlobal) {
4455
4685
  ## Project-Specific Rules
4456
4686
  Add your project-specific rules here.
4457
4687
  `;
4458
- await writeFile9(join12(configDir, "AGENTS.md"), agentsMd);
4688
+ await writeFile9(join14(configDir, "AGENTS.md"), agentsMd);
4459
4689
  }
4460
4690
  async function configureMcpServer(projectPath) {
4461
4691
  const { mkdir: mkdir9, writeFile: writeFile9, readFile: readFile8 } = await import("fs/promises");
4462
- const { join: join12 } = await import("path");
4463
- const { existsSync: existsSync4 } = await import("fs");
4464
- const { homedir: homedir2 } = await import("os");
4465
- const { fileURLToPath: fileURLToPath2 } = await import("url");
4692
+ const { join: join14 } = await import("path");
4693
+ const { existsSync: existsSync5 } = await import("fs");
4694
+ const { homedir: homedir3 } = await import("os");
4695
+ const { fileURLToPath: fileURLToPath3 } = await import("url");
4466
4696
  const { dirname: dirname2 } = await import("path");
4467
- const currentFile = fileURLToPath2(import.meta.url);
4697
+ const currentFile = fileURLToPath3(import.meta.url);
4468
4698
  const currentDir = dirname2(currentFile);
4469
- const aikitPath = join12(currentDir, "..");
4470
- const mcpServerPath = join12(aikitPath, "dist", "mcp-server.js");
4699
+ const aikitPath = join14(currentDir, "..");
4700
+ const mcpServerPath = join14(aikitPath, "dist", "mcp-server.js");
4471
4701
  const configLocations = [
4472
4702
  // Global config (most common)
4473
- join12(homedir2(), ".config", "opencode", "opencode.json"),
4703
+ join14(homedir3(), ".config", "opencode", "opencode.json"),
4474
4704
  // Project-level config
4475
- join12(projectPath, ".opencode", "opencode.json"),
4705
+ join14(projectPath, ".opencode", "opencode.json"),
4476
4706
  // Alternative global location
4477
- join12(homedir2(), ".opencode", "opencode.json")
4707
+ join14(homedir3(), ".opencode", "opencode.json")
4478
4708
  ];
4479
4709
  const mcpServerConfig = {
4480
4710
  type: "local",
@@ -4483,10 +4713,10 @@ async function configureMcpServer(projectPath) {
4483
4713
  };
4484
4714
  for (const configPath of configLocations) {
4485
4715
  try {
4486
- const configDir = join12(configPath, "..");
4716
+ const configDir = join14(configPath, "..");
4487
4717
  await mkdir9(configDir, { recursive: true });
4488
4718
  let config = {};
4489
- if (existsSync4(configPath)) {
4719
+ if (existsSync5(configPath)) {
4490
4720
  try {
4491
4721
  const existing = await readFile8(configPath, "utf-8");
4492
4722
  config = JSON.parse(existing);
@@ -4507,8 +4737,8 @@ async function configureMcpServer(projectPath) {
4507
4737
  continue;
4508
4738
  }
4509
4739
  }
4510
- const instructionsPath = join12(projectPath, ".opencode", "MCP_SETUP.md");
4511
- await mkdir9(join12(projectPath, ".opencode"), { recursive: true });
4740
+ const instructionsPath = join14(projectPath, ".opencode", "MCP_SETUP.md");
4741
+ await mkdir9(join14(projectPath, ".opencode"), { recursive: true });
4512
4742
  await writeFile9(instructionsPath, `# AIKit MCP Server Configuration
4513
4743
 
4514
4744
  ## Automatic Setup Failed
@@ -4548,15 +4778,38 @@ After restarting OpenCode, check:
4548
4778
  logger.warn(`
4549
4779
  \u26A0\uFE0F Could not auto-configure MCP server. See: ${instructionsPath}`);
4550
4780
  }
4781
+ async function installCliTool(tool) {
4782
+ try {
4783
+ logger.info(`Installing ${tool.displayName}...`);
4784
+ switch (tool.name) {
4785
+ case "opencode" /* OPENCODE */:
4786
+ await installToOpenCode(paths.opencodeConfig());
4787
+ break;
4788
+ case "claude" /* CLAUDE */:
4789
+ const { execSync: execSync2 } = await import("child_process");
4790
+ execSync2("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
4791
+ break;
4792
+ case "github" /* GITHUB */:
4793
+ const { execSync: execGh } = await import("child_process");
4794
+ execGh("npm install -g gh", { stdio: "inherit" });
4795
+ break;
4796
+ }
4797
+ logger.success(`\u2713 ${tool.displayName} installed`);
4798
+ return true;
4799
+ } catch (error) {
4800
+ logger.error(`Failed to install ${tool.displayName}:`, error);
4801
+ return false;
4802
+ }
4803
+ }
4551
4804
  async function installToOpenCode(_opencodePath) {
4552
4805
  const { mkdir: mkdir9, writeFile: writeFile9, access: access5 } = await import("fs/promises");
4553
- const { join: join12 } = await import("path");
4806
+ const { join: join14 } = await import("path");
4554
4807
  const projectPath = process.cwd();
4555
- const opencodeCommandDir = join12(projectPath, ".opencode", "command");
4556
- const aikitDir = join12(projectPath, ".aikit");
4557
- const opencodeAgentDir = join12(paths.opencodeConfig(), "agent");
4808
+ const opencodeCommandDir = join14(projectPath, ".opencode", "command");
4809
+ const aikitDir = join14(projectPath, ".aikit");
4810
+ const opencodeAgentDir = join14(paths.opencodeConfig(), "agent");
4558
4811
  await mkdir9(opencodeCommandDir, { recursive: true });
4559
- await mkdir9(join12(aikitDir, "skills"), { recursive: true });
4812
+ await mkdir9(join14(aikitDir, "skills"), { recursive: true });
4560
4813
  await mkdir9(opencodeAgentDir, { recursive: true });
4561
4814
  const agentFiles = {
4562
4815
  agent: `---
@@ -4629,7 +4882,7 @@ tools:
4629
4882
  Use to interpret visual assets (components, layout, colors, typography) and translate to tasks.`
4630
4883
  };
4631
4884
  for (const [name, content] of Object.entries(agentFiles)) {
4632
- const filePath = join12(opencodeAgentDir, `${name}.md`);
4885
+ const filePath = join14(opencodeAgentDir, `${name}.md`);
4633
4886
  try {
4634
4887
  await access5(filePath);
4635
4888
  } catch {
@@ -4886,7 +5139,7 @@ ${cmd.content}
4886
5139
  }
4887
5140
  let count = 0;
4888
5141
  for (const [name, content] of Object.entries(opencodeCommands)) {
4889
- const filePath = join12(opencodeCommandDir, `${name}.md`);
5142
+ const filePath = join14(opencodeCommandDir, `${name}.md`);
4890
5143
  await writeFile9(filePath, content.trim());
4891
5144
  logger.info(` \u2713 Created /${name} command`);
4892
5145
  count++;