@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/CHANGELOG.md +18 -0
- package/dist/cli.js +345 -92
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +13 -7
- package/dist/index.js +137 -60
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +71 -43
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -2
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
|
|
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
|
-
|
|
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 :
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
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) =>
|
|
632
|
+
status.cssFiles = cssFiles.map((f) => join7(stylesDir, f));
|
|
636
633
|
}
|
|
637
634
|
} catch (e) {
|
|
638
635
|
}
|
|
639
636
|
}
|
|
640
|
-
const assetsDir =
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 ||
|
|
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 =
|
|
795
|
+
filePath = join8(memoryPath, `${key}.md`);
|
|
799
796
|
} else {
|
|
800
797
|
const subDir = type === "observation" ? "observations" : type === "handoff" ? "handoffs" : type === "research" ? "research" : "";
|
|
801
|
-
filePath =
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
1107
|
-
const { token } = await
|
|
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:
|
|
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
|
|
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
|
|
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(
|
|
1300
|
-
const globalContent = await readFile(
|
|
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(
|
|
1308
|
-
const projectContent = await readFile(
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
2577
|
+
const commandsDir = join5(paths.commands(configPath), category);
|
|
2549
2578
|
await mkdir2(commandsDir, { recursive: true });
|
|
2550
2579
|
const fileName = `${name}.md`;
|
|
2551
|
-
const filePath =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
*
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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.
|
|
4048
|
-
logger.
|
|
4049
|
-
|
|
4050
|
-
logger.
|
|
4051
|
-
|
|
4052
|
-
|
|
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${
|
|
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:
|
|
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(
|
|
4651
|
+
await mkdir9(join14(configDir, dir), { recursive: true });
|
|
4422
4652
|
}
|
|
4423
4653
|
const defaultConfig = {
|
|
4424
|
-
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
|
-
|
|
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(
|
|
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:
|
|
4463
|
-
const { existsSync:
|
|
4464
|
-
const { homedir:
|
|
4465
|
-
const { fileURLToPath:
|
|
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 =
|
|
4697
|
+
const currentFile = fileURLToPath3(import.meta.url);
|
|
4468
4698
|
const currentDir = dirname2(currentFile);
|
|
4469
|
-
const aikitPath =
|
|
4470
|
-
const mcpServerPath =
|
|
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
|
-
|
|
4703
|
+
join14(homedir3(), ".config", "opencode", "opencode.json"),
|
|
4474
4704
|
// Project-level config
|
|
4475
|
-
|
|
4705
|
+
join14(projectPath, ".opencode", "opencode.json"),
|
|
4476
4706
|
// Alternative global location
|
|
4477
|
-
|
|
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 =
|
|
4716
|
+
const configDir = join14(configPath, "..");
|
|
4487
4717
|
await mkdir9(configDir, { recursive: true });
|
|
4488
4718
|
let config = {};
|
|
4489
|
-
if (
|
|
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 =
|
|
4511
|
-
await mkdir9(
|
|
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:
|
|
4806
|
+
const { join: join14 } = await import("path");
|
|
4554
4807
|
const projectPath = process.cwd();
|
|
4555
|
-
const opencodeCommandDir =
|
|
4556
|
-
const aikitDir =
|
|
4557
|
-
const opencodeAgentDir =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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++;
|