@tdsoft-tech/aikit 0.1.9 → 0.1.12

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
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
4
10
  var __esm = (fn, res) => function __init() {
5
11
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
12
  };
@@ -735,8 +741,8 @@ var init_memory = __esm({
735
741
  for (const subDir of subDirs) {
736
742
  const dirPath = join8(memoryPath, subDir);
737
743
  try {
738
- const { readdir: readdir7 } = await import("fs/promises");
739
- const files = await readdir7(dirPath);
744
+ const { readdir: readdir10 } = await import("fs/promises");
745
+ const files = await readdir10(dirPath);
740
746
  for (const file of files) {
741
747
  if (!file.endsWith(".md")) continue;
742
748
  const content = await readFile5(join8(dirPath, file), "utf-8");
@@ -797,8 +803,8 @@ var init_memory = __esm({
797
803
  const subDir = type === "observation" ? "observations" : type === "handoff" ? "handoffs" : type === "research" ? "research" : "";
798
804
  filePath = join8(memoryPath, subDir, `${key}.md`);
799
805
  }
800
- const { dirname: dirname2 } = await import("path");
801
- await mkdir4(dirname2(filePath), { recursive: true });
806
+ const { dirname: dirname4 } = await import("path");
807
+ await mkdir4(dirname4(filePath), { recursive: true });
802
808
  if (options?.append) {
803
809
  try {
804
810
  const existing = await readFile5(filePath, "utf-8");
@@ -928,8 +934,8 @@ var tool_config_exports = {};
928
934
  __export(tool_config_exports, {
929
935
  ToolConfigManager: () => ToolConfigManager
930
936
  });
931
- import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8, access as access4, constants as constants4 } from "fs/promises";
932
- import { join as join13 } from "path";
937
+ import { readFile as readFile11, writeFile as writeFile12, mkdir as mkdir10, access as access4, constants as constants4 } from "fs/promises";
938
+ import { join as join17 } from "path";
933
939
  import { z as z3 } from "zod";
934
940
  var ToolConfigSchema, REGISTERED_TOOLS, ToolConfigManager;
935
941
  var init_tool_config = __esm({
@@ -957,7 +963,7 @@ var init_tool_config = __esm({
957
963
  toolsConfigPath;
958
964
  constructor(config) {
959
965
  this.config = config;
960
- this.toolsConfigPath = join13(this.config.configPath, "config", "tools.json");
966
+ this.toolsConfigPath = join17(this.config.configPath, "config", "tools.json");
961
967
  }
962
968
  /**
963
969
  * Get all registered tools with their current status
@@ -1041,7 +1047,7 @@ var init_tool_config = __esm({
1041
1047
  async loadConfigs() {
1042
1048
  try {
1043
1049
  await access4(this.toolsConfigPath, constants4.R_OK);
1044
- const content = await readFile7(this.toolsConfigPath, "utf-8");
1050
+ const content = await readFile11(this.toolsConfigPath, "utf-8");
1045
1051
  return JSON.parse(content);
1046
1052
  } catch {
1047
1053
  return {};
@@ -1051,9 +1057,9 @@ var init_tool_config = __esm({
1051
1057
  * Save configurations
1052
1058
  */
1053
1059
  async saveConfigs(configs) {
1054
- const configDir = join13(this.config.configPath, "config");
1055
- await mkdir8(configDir, { recursive: true });
1056
- await writeFile8(this.toolsConfigPath, JSON.stringify(configs, null, 2));
1060
+ const configDir = join17(this.config.configPath, "config");
1061
+ await mkdir10(configDir, { recursive: true });
1062
+ await writeFile12(this.toolsConfigPath, JSON.stringify(configs, null, 2));
1057
1063
  }
1058
1064
  };
1059
1065
  }
@@ -1100,8 +1106,8 @@ var init_figma_oauth = __esm({
1100
1106
  console.log('3. Give it a name (e.g., "AIKit")');
1101
1107
  console.log("4. Copy the token (you won't see it again!)");
1102
1108
  console.log("5. Paste it here when prompted\n");
1103
- const { default: inquirer2 } = await import("inquirer");
1104
- const { token } = await inquirer2.prompt([
1109
+ const { default: inquirer3 } = await import("inquirer");
1110
+ const { token } = await inquirer3.prompt([
1105
1111
  {
1106
1112
  type: "password",
1107
1113
  name: "token",
@@ -1131,14 +1137,14 @@ var init_figma_oauth = __esm({
1131
1137
  * Alternative: Manual token input
1132
1138
  */
1133
1139
  async authenticateManual() {
1134
- const { default: inquirer2 } = await import("inquirer");
1140
+ const { default: inquirer3 } = await import("inquirer");
1135
1141
  console.log("\n\u{1F510} Figma Authentication (Manual)\n");
1136
1142
  console.log("To get your Figma Personal Access Token:");
1137
1143
  console.log("1. Visit: https://www.figma.com/developers/api#access-tokens");
1138
1144
  console.log('2. Scroll to "Personal access tokens"');
1139
1145
  console.log('3. Click "Create new token"');
1140
1146
  console.log("4. Copy the token and paste it below\n");
1141
- const { token } = await inquirer2.prompt([
1147
+ const { token } = await inquirer3.prompt([
1142
1148
  {
1143
1149
  type: "password",
1144
1150
  name: "token",
@@ -1191,8 +1197,8 @@ var init_figma_oauth = __esm({
1191
1197
  // src/cli.ts
1192
1198
  init_esm_shims();
1193
1199
  import { Command } from "commander";
1194
- import chalk2 from "chalk";
1195
- import inquirer from "inquirer";
1200
+ import chalk3 from "chalk";
1201
+ import inquirer2 from "inquirer";
1196
1202
 
1197
1203
  // src/index.ts
1198
1204
  init_esm_shims();
@@ -1765,6 +1771,51 @@ For diagrams:
1765
1771
  - Map to code structure
1766
1772
  - Note data flow`,
1767
1773
  delegatesTo: []
1774
+ },
1775
+ {
1776
+ name: "one-shot",
1777
+ displayName: "@one-shot",
1778
+ description: "End-to-end autonomous task execution (beta)",
1779
+ useWhen: "Complete tasks autonomously from start to finish with minimal intervention",
1780
+ capabilities: [
1781
+ "Gather requirements interactively",
1782
+ "Create detailed implementation plans",
1783
+ "Execute tasks with dynamic agent selection",
1784
+ "Run quality gates until all pass",
1785
+ "Multi-level verification",
1786
+ "Auto-recovery from failures",
1787
+ "Generate completion proof"
1788
+ ],
1789
+ systemPrompt: `You are the one-shot agent. Your role is to execute tasks autonomously from start to finish.
1790
+
1791
+ ## Workflow Phases
1792
+
1793
+ 1. **REQUIREMENTS**: Gather task type, scope, dependencies, success criteria
1794
+ 2. **PLANNING**: Create detailed plan with @planner, recommend skills/tools
1795
+ 3. **COMPLEXITY**: Auto-split large tasks (>30min, >10 files, >500 lines)
1796
+ 4. **EXECUTION**: Execute with parallel tasks, dynamic agent delegation
1797
+ 5. **TESTING**: Run quality gates (typecheck, test, lint, build) until all pass
1798
+ 6. **VERIFICATION**: Multi-level verification (gates + manual + deployment)
1799
+ 7. **COMPLETION**: Generate proof, update tracking, collect feedback
1800
+
1801
+ ## Quality Gates (Must ALL Pass)
1802
+ - npm run typecheck - No type errors
1803
+ - npm run test - All tests pass
1804
+ - npm run lint - No linting errors
1805
+ - npm run build - Build succeeds
1806
+
1807
+ ## Error Recovery (3 Levels)
1808
+ - Level 1: Auto-fix (type errors, lint --fix)
1809
+ - Level 2: Alternative approach via @review
1810
+ - Level 3: User intervention + follow-up task creation
1811
+
1812
+ ## Best Practices
1813
+ - Use for straightforward tasks first
1814
+ - Consider /plan + /implement for complex features
1815
+ - Review changes before final approval
1816
+
1817
+ \u26A0\uFE0F This mode is experimental. Start with simpler tasks.`,
1818
+ delegatesTo: ["planner", "build", "review", "scout", "explore", "vision"]
1768
1819
  }
1769
1820
  ];
1770
1821
  var AgentManager = class {
@@ -2037,6 +2088,95 @@ Before marking complete:
2037
2088
  2. Display summary to user
2038
2089
  3. Propose next actions
2039
2090
  4. Continue from where left off`
2091
+ },
2092
+ {
2093
+ name: "one-shot",
2094
+ description: "End-to-end autonomous task execution (beta)",
2095
+ category: "core",
2096
+ usage: "/one-shot <task description>",
2097
+ examples: ["/one-shot Add user authentication", "/one-shot Fix navigation bug"],
2098
+ content: `One-Shot Mode (beta) - End-to-end autonomous task execution.
2099
+
2100
+ \u26A0\uFE0F This mode is experimental. Use for straightforward tasks first.
2101
+
2102
+ ## Workflow
2103
+
2104
+ **Phase 1: Requirements Gathering**
2105
+ - Interactive selection of task type (Feature, Bug Fix, Refactoring, etc.)
2106
+ - Scope clarification
2107
+ - Dependencies identification
2108
+ - Success criteria definition
2109
+ - User selects progress level (Minimal/Moderate/Detailed/Quiet)
2110
+
2111
+ **Phase 2: Planning**
2112
+ - Delegate to @planner agent
2113
+ - Create detailed implementation plan
2114
+ - Recommend relevant skills and tools
2115
+ - Create Beads task for tracking
2116
+
2117
+ **Phase 3: Complexity Check & Auto-Split**
2118
+ - Analyze task complexity
2119
+ - Split into multiple beads if needed:
2120
+ * Time > 30 minutes
2121
+ * >10 files affected
2122
+ * >500 lines to change
2123
+ * Touches >2 sub-systems
2124
+
2125
+ **Phase 4: Execution**
2126
+ - Build dependency graph
2127
+ - Execute tasks in parallel (max 3 concurrent)
2128
+ - Dynamic agent selection (@build \u2192 @review \u2192 @scout \u2192 ...)
2129
+ - Integrate skills (TDD, debugging, etc.)
2130
+ - Smart terminal access (auto-allow/ask/forbid)
2131
+
2132
+ **Phase 5: Enhanced Testing & Validation**
2133
+ - Auto-generate test scripts for new functionality
2134
+ - Run quality gates: typecheck, test, lint, build
2135
+ - Execute sample commands (with user approval)
2136
+ - Validate logs semantically with historical comparison
2137
+ - Retry loop (max 3 attempts) with:
2138
+ * Auto-fix type errors, lint errors
2139
+ * Alternative approaches from @review
2140
+ * User intervention on final failure
2141
+
2142
+ **Phase 6: Multi-Level Verification**
2143
+ - All quality gates passed \u2713
2144
+ - Manual verification confirmation
2145
+ - Deployment approval (if needed)
2146
+ - Rollback confirmation (if verification fails)
2147
+
2148
+ **Phase 7: Completion**
2149
+ - Generate proof of completion
2150
+ * Files changed
2151
+ * Test results
2152
+ * Build output
2153
+ * Deployment status
2154
+ - Update Beads task \u2192 completed
2155
+ - Store proof in bead notes
2156
+ - Collect beta feedback
2157
+
2158
+ ## Quality Gates (Must ALL Pass)
2159
+ - \`npm run typecheck\` - No type errors
2160
+ - \`npm run test\` - All tests pass
2161
+ - \`npm run lint\` - No linting errors
2162
+ - \`npm run build\` - Build succeeds
2163
+
2164
+ ## Success Criteria
2165
+ - All tests passing
2166
+ - No regressions
2167
+ - Manual verification
2168
+ - Deployment complete (if applicable)
2169
+ - Beads task completed with proof
2170
+
2171
+ ## Error Handling
2172
+ - **Level 1**: Auto-fix (type errors, lint --fix)
2173
+ - **Level 2**: Alternative approach (@review delegation)
2174
+ - **Level 3**: User intervention + follow-up bead creation
2175
+
2176
+ ## Tips
2177
+ \u2713 Use for straightforward tasks first
2178
+ \u2713 Consider /plan + /implement for complex features
2179
+ \u2713 Review changes before final approval`
2040
2180
  },
2041
2181
  // Quick Actions
2042
2182
  {
@@ -4221,11 +4361,1058 @@ var CliDetector = class {
4221
4361
  // src/cli.ts
4222
4362
  init_logger();
4223
4363
  init_paths();
4364
+
4365
+ // src/core/sync-engine.ts
4366
+ init_esm_shims();
4367
+ import { readFile as readFile10, writeFile as writeFile11, copyFile, mkdir as mkdir9 } from "fs/promises";
4368
+ import { join as join16, dirname as dirname3 } from "path";
4369
+ import inquirer from "inquirer";
4370
+ import chalk2 from "chalk";
4371
+
4372
+ // src/core/version-manager.ts
4373
+ init_esm_shims();
4374
+ init_paths();
4375
+ init_logger();
4376
+ import { readFile as readFile7, readdir as readdir7, writeFile as writeFile8, stat } from "fs/promises";
4377
+ import { join as join13 } from "path";
4378
+ import { createHash } from "crypto";
4379
+ var VersionManager = class {
4380
+ config;
4381
+ constructor(config) {
4382
+ this.config = config;
4383
+ }
4384
+ /**
4385
+ * Get current installed version
4386
+ */
4387
+ async getCurrentVersion() {
4388
+ const versionPath = join13(paths.globalConfig(), ".version.json");
4389
+ try {
4390
+ const content = await readFile7(versionPath, "utf-8");
4391
+ return JSON.parse(content);
4392
+ } catch {
4393
+ return null;
4394
+ }
4395
+ }
4396
+ /**
4397
+ * Get package version from package.json
4398
+ */
4399
+ getPackageVersion() {
4400
+ try {
4401
+ const packageJson = __require(join13(process.cwd(), "package.json"));
4402
+ return packageJson.version || "0.0.0";
4403
+ } catch {
4404
+ return "0.0.0";
4405
+ }
4406
+ }
4407
+ /**
4408
+ * Check for updates
4409
+ */
4410
+ async checkForUpdates() {
4411
+ const installed = await this.getCurrentVersion();
4412
+ const packageVersion = this.getPackageVersion();
4413
+ if (!installed) {
4414
+ return {
4415
+ hasUpdate: true,
4416
+ fromVersion: "none",
4417
+ toVersion: packageVersion,
4418
+ newSkills: [],
4419
+ modifiedSkills: [],
4420
+ removedSkills: [],
4421
+ conflicts: [],
4422
+ configChanges: ["Initial version tracking"]
4423
+ };
4424
+ }
4425
+ const hasUpdate = installed.installedVersion !== packageVersion;
4426
+ if (!hasUpdate) {
4427
+ return {
4428
+ hasUpdate: false,
4429
+ fromVersion: installed.installedVersion,
4430
+ toVersion: packageVersion,
4431
+ newSkills: [],
4432
+ modifiedSkills: [],
4433
+ removedSkills: [],
4434
+ conflicts: [],
4435
+ configChanges: []
4436
+ };
4437
+ }
4438
+ const changes = await this.detectChanges();
4439
+ return {
4440
+ hasUpdate: true,
4441
+ fromVersion: installed.installedVersion,
4442
+ toVersion: packageVersion,
4443
+ ...changes
4444
+ };
4445
+ }
4446
+ /**
4447
+ * Detect changes between versions
4448
+ */
4449
+ async detectChanges() {
4450
+ const globalSkillsPath = paths.skills(paths.globalConfig());
4451
+ const projectSkillsPath = paths.skills(this.config.configPath);
4452
+ const sourceSkills = await this.loadSkillHashes(globalSkillsPath);
4453
+ const userSkills = await this.loadSkillHashes(projectSkillsPath);
4454
+ const newSkills = [];
4455
+ const modifiedSkills = [];
4456
+ const removedSkills = [];
4457
+ const conflicts = [];
4458
+ const installedSkills = /* @__PURE__ */ new Map();
4459
+ const installedPath = join13(paths.globalConfig(), ".installed-skills.json");
4460
+ try {
4461
+ const installedData = await readFile7(installedPath, "utf-8");
4462
+ const installedList = JSON.parse(installedData);
4463
+ installedList.forEach((skill) => {
4464
+ installedSkills.set(skill.name, skill);
4465
+ });
4466
+ } catch {
4467
+ }
4468
+ for (const sourceSkill of sourceSkills) {
4469
+ const installed = installedSkills.get(sourceSkill.name);
4470
+ const user = userSkills.find((s) => s.name === sourceSkill.name);
4471
+ if (!installed) {
4472
+ newSkills.push(sourceSkill);
4473
+ } else if (installed.hash !== sourceSkill.hash) {
4474
+ modifiedSkills.push(sourceSkill);
4475
+ if (user && user.hash !== installed.hash) {
4476
+ conflicts.push({
4477
+ skillName: sourceSkill.name,
4478
+ userHash: user.hash,
4479
+ sourceHash: sourceSkill.hash,
4480
+ installedHash: installed.hash,
4481
+ userModified: user.hash !== installed.hash,
4482
+ sourceModified: sourceSkill.hash !== installed.hash
4483
+ });
4484
+ }
4485
+ }
4486
+ }
4487
+ for (const [name, installedSkill] of installedSkills.entries()) {
4488
+ const existsInSource = sourceSkills.find((s) => s.name === name);
4489
+ if (!existsInSource) {
4490
+ removedSkills.push(installedSkill);
4491
+ }
4492
+ }
4493
+ return {
4494
+ newSkills,
4495
+ modifiedSkills,
4496
+ removedSkills,
4497
+ conflicts,
4498
+ configChanges: []
4499
+ // Will be detected separately
4500
+ };
4501
+ }
4502
+ /**
4503
+ * Load skill hashes from directory
4504
+ */
4505
+ async loadSkillHashes(skillsPath) {
4506
+ const hashes = [];
4507
+ try {
4508
+ const loadFromDir = async (dir) => {
4509
+ const files = await readdir7(dir);
4510
+ for (const file of files) {
4511
+ const filePath = join13(dir, file);
4512
+ const stats = await stat(filePath);
4513
+ if (stats.isDirectory()) {
4514
+ await loadFromDir(filePath);
4515
+ } else if (file.endsWith(".md")) {
4516
+ const hash = await this.calculateSkillHash(filePath);
4517
+ hashes.push({
4518
+ path: filePath,
4519
+ name: file.replace(".md", ""),
4520
+ hash,
4521
+ category: this.extractCategory(dir, skillsPath)
4522
+ });
4523
+ }
4524
+ }
4525
+ };
4526
+ await loadFromDir(skillsPath);
4527
+ } catch (error) {
4528
+ logger.debug(`Could not load skills from ${skillsPath}:`, error);
4529
+ }
4530
+ return hashes;
4531
+ }
4532
+ /**
4533
+ * Calculate hash for a skill file
4534
+ */
4535
+ async calculateSkillHash(filePath) {
4536
+ try {
4537
+ const content = await readFile7(filePath, "utf-8");
4538
+ return createHash("sha256").update(content).digest("hex");
4539
+ } catch {
4540
+ return "";
4541
+ }
4542
+ }
4543
+ /**
4544
+ * Extract category from path
4545
+ */
4546
+ extractCategory(filePath, basePath) {
4547
+ const relative = filePath.replace(basePath + "/", "");
4548
+ const parts = relative.split("/");
4549
+ if (parts.length > 1) {
4550
+ return parts[0];
4551
+ }
4552
+ return "uncategorized";
4553
+ }
4554
+ /**
4555
+ * Save installed skills info
4556
+ */
4557
+ async saveInstalledSkills(skills) {
4558
+ const installedPath = join13(paths.globalConfig(), ".installed-skills.json");
4559
+ try {
4560
+ await writeFile8(installedPath, JSON.stringify(skills, null, 2));
4561
+ } catch (error) {
4562
+ logger.error("Failed to save installed skills info:", error);
4563
+ }
4564
+ }
4565
+ /**
4566
+ * Update version file
4567
+ */
4568
+ async updateVersion(version, migration) {
4569
+ const current = await this.getCurrentVersion() || {
4570
+ installedVersion: "0.0.0",
4571
+ lastSynced: (/* @__PURE__ */ new Date()).toISOString(),
4572
+ packageVersion: "0.0.0",
4573
+ migrationHistory: []
4574
+ };
4575
+ const updated = {
4576
+ installedVersion: version,
4577
+ lastSynced: (/* @__PURE__ */ new Date()).toISOString(),
4578
+ packageVersion: this.getPackageVersion(),
4579
+ migrationHistory: migration ? [...current.migrationHistory, migration] : current.migrationHistory
4580
+ };
4581
+ const versionPath = join13(paths.globalConfig(), ".version.json");
4582
+ await writeFile8(versionPath, JSON.stringify(updated, null, 2));
4583
+ }
4584
+ /**
4585
+ * Check if migration is needed
4586
+ */
4587
+ async needsMigration() {
4588
+ const current = await this.getCurrentVersion();
4589
+ const packageVersion = this.getPackageVersion();
4590
+ return current?.installedVersion !== packageVersion;
4591
+ }
4592
+ };
4593
+
4594
+ // src/core/backup-manager.ts
4595
+ init_esm_shims();
4596
+ init_logger();
4597
+ import { readFile as readFile8, writeFile as writeFile9, readdir as readdir8, stat as stat2, unlink, mkdir as mkdir8 } from "fs/promises";
4598
+ import { join as join14, dirname as dirname2 } from "path";
4599
+ import { createHash as createHash2 } from "crypto";
4600
+ var BackupManager = class {
4601
+ configPath;
4602
+ backupsDir;
4603
+ maxBackups;
4604
+ constructor(configPath, maxBackups = 5) {
4605
+ this.configPath = configPath;
4606
+ this.backupsDir = join14(configPath, ".backups");
4607
+ this.maxBackups = maxBackups;
4608
+ }
4609
+ /**
4610
+ * Create backup before update
4611
+ */
4612
+ async createBackup(fromVersion, toVersion) {
4613
+ try {
4614
+ await mkdir8(this.backupsDir, { recursive: true });
4615
+ const backupId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
4616
+ const backupPath = join14(this.backupsDir, `${backupId}-v${toVersion}`);
4617
+ await mkdir8(backupPath, { recursive: true });
4618
+ logger.info(`Creating backup: ${backupPath}`);
4619
+ const files = [];
4620
+ const backupItems = [
4621
+ "skills/",
4622
+ "aikit.json",
4623
+ "AGENTS.md",
4624
+ "config/"
4625
+ ];
4626
+ for (const item of backupItems) {
4627
+ const files2 = await this.backupItem(this.configPath, item, backupPath);
4628
+ files2.push(...files2);
4629
+ }
4630
+ const manifest = {
4631
+ backupId,
4632
+ fromVersion,
4633
+ toVersion,
4634
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4635
+ files,
4636
+ success: true
4637
+ };
4638
+ const manifestPath = join14(backupPath, "backup-manifest.json");
4639
+ await writeFile9(manifestPath, JSON.stringify(manifest, null, 2));
4640
+ await this.cleanupOldBackups();
4641
+ logger.success(`\u2713 Backup created: ${backupId}`);
4642
+ return backupId;
4643
+ } catch (error) {
4644
+ logger.error("Failed to create backup:", error);
4645
+ return null;
4646
+ }
4647
+ }
4648
+ /**
4649
+ * Backup a file or directory
4650
+ */
4651
+ async backupItem(sourceDir, item, targetDir) {
4652
+ const sourcePath = join14(sourceDir, item);
4653
+ const targetPath = join14(targetDir, item);
4654
+ const files = [];
4655
+ try {
4656
+ const stats = await stat2(sourcePath);
4657
+ if (stats.isDirectory()) {
4658
+ await mkdir8(targetPath, { recursive: true });
4659
+ const entries = await readdir8(sourcePath);
4660
+ for (const entry of entries) {
4661
+ const entryFiles = await this.backupItem(sourcePath, entry, targetPath);
4662
+ files.push(...entryFiles);
4663
+ }
4664
+ } else if (stats.isFile()) {
4665
+ await mkdir8(dirname2(targetPath), { recursive: true });
4666
+ await this.copyFile(sourcePath, targetPath);
4667
+ const hash = await this.calculateHash(targetPath);
4668
+ files.push({
4669
+ path: item,
4670
+ hash,
4671
+ size: stats.size
4672
+ });
4673
+ }
4674
+ } catch (error) {
4675
+ logger.debug(`Could not backup ${item}:`, error);
4676
+ }
4677
+ return files;
4678
+ }
4679
+ /**
4680
+ * Copy file with hash calculation
4681
+ */
4682
+ async copyFile(source, target) {
4683
+ const content = await readFile8(source);
4684
+ await writeFile9(target, content);
4685
+ }
4686
+ /**
4687
+ * Calculate file hash
4688
+ */
4689
+ async calculateHash(filePath) {
4690
+ try {
4691
+ const content = await readFile8(filePath);
4692
+ return createHash2("sha256").update(content).digest("hex");
4693
+ } catch {
4694
+ return "";
4695
+ }
4696
+ }
4697
+ /**
4698
+ * List available backups
4699
+ */
4700
+ async listBackups() {
4701
+ try {
4702
+ const entries = await readdir8(this.backupsDir);
4703
+ const backups = [];
4704
+ for (const entry of entries) {
4705
+ const backupPath = join14(this.backupsDir, entry);
4706
+ const manifestPath = join14(backupPath, "backup-manifest.json");
4707
+ try {
4708
+ const manifestContent = await readFile8(manifestPath, "utf-8");
4709
+ const manifest = JSON.parse(manifestContent);
4710
+ const size = await this.calculateBackupSize(backupPath);
4711
+ backups.push({
4712
+ manifest,
4713
+ path: backupPath,
4714
+ size
4715
+ });
4716
+ } catch {
4717
+ }
4718
+ }
4719
+ backups.sort(
4720
+ (a, b) => new Date(b.manifest.timestamp).getTime() - new Date(a.manifest.timestamp).getTime()
4721
+ );
4722
+ return backups;
4723
+ } catch {
4724
+ return [];
4725
+ }
4726
+ }
4727
+ /**
4728
+ * Calculate backup directory size
4729
+ */
4730
+ async calculateBackupSize(backupPath) {
4731
+ let totalSize = 0;
4732
+ try {
4733
+ const calculate = async (dir) => {
4734
+ const entries = await readdir8(dir);
4735
+ for (const entry of entries) {
4736
+ const entryPath = join14(dir, entry);
4737
+ const stats = await stat2(entryPath);
4738
+ if (stats.isDirectory()) {
4739
+ await calculate(entryPath);
4740
+ } else {
4741
+ totalSize += stats.size;
4742
+ }
4743
+ }
4744
+ };
4745
+ await calculate(backupPath);
4746
+ } catch {
4747
+ }
4748
+ return totalSize;
4749
+ }
4750
+ /**
4751
+ * Restore from backup
4752
+ */
4753
+ async restoreBackup(backupId) {
4754
+ try {
4755
+ const backups = await this.listBackups();
4756
+ const backup = backups.find((b) => b.manifest.backupId === backupId);
4757
+ if (!backup) {
4758
+ logger.error(`Backup not found: ${backupId}`);
4759
+ return false;
4760
+ }
4761
+ logger.info(`Restoring from backup: ${backupId}`);
4762
+ const isValid = await this.validateBackup(backup);
4763
+ if (!isValid) {
4764
+ logger.error("Backup validation failed");
4765
+ return false;
4766
+ }
4767
+ for (const file of backup.manifest.files) {
4768
+ const sourcePath = join14(backup.path, file.path);
4769
+ const targetPath = join14(this.configPath, file.path);
4770
+ await mkdir8(dirname2(targetPath), { recursive: true });
4771
+ await this.copyFile(sourcePath, targetPath);
4772
+ }
4773
+ logger.success(`\u2713 Backup restored: ${backupId}`);
4774
+ return true;
4775
+ } catch (error) {
4776
+ logger.error("Failed to restore backup:", error);
4777
+ return false;
4778
+ }
4779
+ }
4780
+ /**
4781
+ * Validate backup integrity
4782
+ */
4783
+ async validateBackup(backup) {
4784
+ try {
4785
+ const manifestPath = join14(backup.path, "backup-manifest.json");
4786
+ await readFile8(manifestPath, "utf-8");
4787
+ for (const file of backup.manifest.files) {
4788
+ const filePath = join14(backup.path, file.path);
4789
+ await stat2(filePath);
4790
+ const currentHash = await this.calculateHash(filePath);
4791
+ if (currentHash !== file.hash) {
4792
+ logger.warn(`File hash mismatch: ${file.path}`);
4793
+ return false;
4794
+ }
4795
+ }
4796
+ return true;
4797
+ } catch (error) {
4798
+ logger.debug("Backup validation failed:", error);
4799
+ return false;
4800
+ }
4801
+ }
4802
+ /**
4803
+ * Delete backup
4804
+ */
4805
+ async deleteBackup(backupId) {
4806
+ try {
4807
+ const backups = await this.listBackups();
4808
+ const backup = backups.find((b) => b.manifest.backupId === backupId);
4809
+ if (!backup) {
4810
+ return false;
4811
+ }
4812
+ const entries = await readdir8(backup.path);
4813
+ for (const entry of entries) {
4814
+ const entryPath = join14(backup.path, entry);
4815
+ const stats = await stat2(entryPath);
4816
+ if (stats.isDirectory()) {
4817
+ await this.removeDirectory(entryPath);
4818
+ } else {
4819
+ await unlink(entryPath);
4820
+ }
4821
+ }
4822
+ logger.success(`\u2713 Backup deleted: ${backupId}`);
4823
+ return true;
4824
+ } catch (error) {
4825
+ logger.error("Failed to delete backup:", error);
4826
+ return false;
4827
+ }
4828
+ }
4829
+ /**
4830
+ * Remove directory recursively
4831
+ */
4832
+ async removeDirectory(dirPath) {
4833
+ const entries = await readdir8(dirPath);
4834
+ for (const entry of entries) {
4835
+ const entryPath = join14(dirPath, entry);
4836
+ const stats = await stat2(entryPath);
4837
+ if (stats.isDirectory()) {
4838
+ await this.removeDirectory(entryPath);
4839
+ } else {
4840
+ await unlink(entryPath);
4841
+ }
4842
+ }
4843
+ await unlink(dirPath);
4844
+ }
4845
+ /**
4846
+ * Cleanup old backups (keep only maxBackups)
4847
+ */
4848
+ async cleanupOldBackups() {
4849
+ try {
4850
+ const backups = await this.listBackups();
4851
+ if (backups.length <= this.maxBackups) {
4852
+ return;
4853
+ }
4854
+ const toDelete = backups.slice(this.maxBackups);
4855
+ for (const backup of toDelete) {
4856
+ await this.deleteBackup(backup.manifest.backupId);
4857
+ }
4858
+ logger.info(`Cleaned up ${toDelete.length} old backup(s)`);
4859
+ } catch (error) {
4860
+ logger.error("Failed to cleanup old backups:", error);
4861
+ }
4862
+ }
4863
+ /**
4864
+ * Format backup size for display
4865
+ */
4866
+ formatSize(bytes) {
4867
+ const units = ["B", "KB", "MB", "GB"];
4868
+ let size = bytes;
4869
+ let unitIndex = 0;
4870
+ while (size >= 1024 && unitIndex < units.length - 1) {
4871
+ size /= 1024;
4872
+ unitIndex++;
4873
+ }
4874
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
4875
+ }
4876
+ };
4877
+
4878
+ // src/core/migration-manager.ts
4879
+ init_esm_shims();
4880
+ init_logger();
4881
+ import { readFile as readFile9, writeFile as writeFile10, readdir as readdir9 } from "fs/promises";
4882
+ import { join as join15 } from "path";
4883
+ var MigrationManager = class {
4884
+ configPath;
4885
+ migrationsDir;
4886
+ constructor(configPath) {
4887
+ this.configPath = configPath;
4888
+ this.migrationsDir = join15(process.cwd(), "src/core/migrations");
4889
+ }
4890
+ /**
4891
+ * Load all available migrations
4892
+ */
4893
+ async loadMigrations() {
4894
+ const migrations = [];
4895
+ try {
4896
+ const files = await readdir9(this.migrationsDir);
4897
+ for (const file of files) {
4898
+ if (file.endsWith(".js") && file.startsWith("migrate-")) {
4899
+ try {
4900
+ const module = await import(join15(this.migrationsDir, file));
4901
+ const migration = module.default || module.migration;
4902
+ if (migration) {
4903
+ migrations.push(migration);
4904
+ }
4905
+ } catch (error) {
4906
+ logger.warn(`Failed to load migration ${file}:`, error);
4907
+ }
4908
+ }
4909
+ }
4910
+ } catch (error) {
4911
+ logger.debug("Could not load migrations:", error);
4912
+ }
4913
+ return migrations.sort((a, b) => a.version.localeCompare(b.version));
4914
+ }
4915
+ /**
4916
+ * Get applied migrations
4917
+ */
4918
+ async getAppliedMigrations() {
4919
+ const migrationHistoryPath = join15(this.configPath, ".migration-history.json");
4920
+ try {
4921
+ const content = await readFile9(migrationHistoryPath, "utf-8");
4922
+ const history = JSON.parse(content);
4923
+ return history.filter((m) => m.status === "completed").map((m) => m.to);
4924
+ } catch {
4925
+ return [];
4926
+ }
4927
+ }
4928
+ /**
4929
+ * Run pending migrations
4930
+ */
4931
+ async runPendingMigrations() {
4932
+ const appliedMigrations = await this.getAppliedMigrations();
4933
+ const allMigrations = await this.loadMigrations();
4934
+ const pendingMigrations = allMigrations.filter(
4935
+ (m) => !appliedMigrations.includes(m.version)
4936
+ );
4937
+ if (pendingMigrations.length === 0) {
4938
+ logger.info("No pending migrations");
4939
+ return { success: true, applied: [], failed: [] };
4940
+ }
4941
+ logger.info(`Running ${pendingMigrations.length} pending migration(s)...`);
4942
+ const applied = [];
4943
+ const failed = [];
4944
+ const migrationHistory = [];
4945
+ for (const migration of pendingMigrations) {
4946
+ try {
4947
+ logger.info(`Running migration: ${migration.version}`);
4948
+ logger.info(` ${migration.description}`);
4949
+ await migration.up();
4950
+ applied.push(migration.version);
4951
+ migrationHistory.push({
4952
+ from: "previous",
4953
+ to: migration.version,
4954
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4955
+ status: "completed"
4956
+ });
4957
+ logger.success(`\u2713 Migration completed: ${migration.version}`);
4958
+ } catch (error) {
4959
+ logger.error(`\u2717 Migration failed: ${migration.version}`, error);
4960
+ failed.push(migration.version);
4961
+ migrationHistory.push({
4962
+ from: "previous",
4963
+ to: migration.version,
4964
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4965
+ status: "failed"
4966
+ });
4967
+ break;
4968
+ }
4969
+ }
4970
+ await this.updateMigrationHistory(migrationHistory);
4971
+ return {
4972
+ success: failed.length === 0,
4973
+ applied,
4974
+ failed
4975
+ };
4976
+ }
4977
+ /**
4978
+ * Rollback migration
4979
+ */
4980
+ async rollbackMigration(version) {
4981
+ try {
4982
+ const applied = await this.getAppliedMigrations();
4983
+ if (!applied.includes(version)) {
4984
+ logger.error(`Migration not found in applied list: ${version}`);
4985
+ return false;
4986
+ }
4987
+ const allMigrations = await this.loadMigrations();
4988
+ const migration = allMigrations.find((m) => m.version === version);
4989
+ if (!migration) {
4990
+ logger.error(`Migration file not found: ${version}`);
4991
+ return false;
4992
+ }
4993
+ logger.info(`Rolling back migration: ${version}`);
4994
+ await migration.down();
4995
+ await this.updateMigrationHistoryStatus(version, "rolled-back");
4996
+ logger.success(`\u2713 Migration rolled back: ${version}`);
4997
+ return true;
4998
+ } catch (error) {
4999
+ logger.error("Failed to rollback migration:", error);
5000
+ return false;
5001
+ }
5002
+ }
5003
+ /**
5004
+ * Update migration history
5005
+ */
5006
+ async updateMigrationHistory(entries) {
5007
+ const historyPath = join15(this.configPath, ".migration-history.json");
5008
+ try {
5009
+ let history = [];
5010
+ try {
5011
+ const content = await readFile9(historyPath, "utf-8");
5012
+ history = JSON.parse(content);
5013
+ } catch {
5014
+ }
5015
+ history.push(...entries);
5016
+ await writeFile10(historyPath, JSON.stringify(history, null, 2));
5017
+ } catch (error) {
5018
+ logger.error("Failed to update migration history:", error);
5019
+ }
5020
+ }
5021
+ /**
5022
+ * Update migration history status
5023
+ */
5024
+ async updateMigrationHistoryStatus(version, status) {
5025
+ const historyPath = join15(this.configPath, ".migration-history.json");
5026
+ try {
5027
+ const content = await readFile9(historyPath, "utf-8");
5028
+ const history = JSON.parse(content);
5029
+ const updated = history.map(
5030
+ (m) => m.to === version ? { ...m, status } : m
5031
+ );
5032
+ await writeFile10(historyPath, JSON.stringify(updated, null, 2));
5033
+ } catch (error) {
5034
+ logger.error("Failed to update migration history status:", error);
5035
+ }
5036
+ }
5037
+ /**
5038
+ * Get migration history
5039
+ */
5040
+ async getMigrationHistory() {
5041
+ const historyPath = join15(this.configPath, ".migration-history.json");
5042
+ try {
5043
+ const content = await readFile9(historyPath, "utf-8");
5044
+ return JSON.parse(content);
5045
+ } catch {
5046
+ return [];
5047
+ }
5048
+ }
5049
+ /**
5050
+ * Check if migration is needed for version
5051
+ */
5052
+ async needsMigration(_fromVersion) {
5053
+ const applied = await this.getAppliedMigrations();
5054
+ const allMigrations = await this.loadMigrations();
5055
+ const pendingMigrations = allMigrations.filter(
5056
+ (m) => !applied.includes(m.version)
5057
+ );
5058
+ return pendingMigrations.length > 0;
5059
+ }
5060
+ };
5061
+
5062
+ // src/core/sync-engine.ts
5063
+ init_logger();
5064
+ init_paths();
5065
+ var SyncEngine = class {
5066
+ versionManager;
5067
+ backupManager;
5068
+ migrationManager;
5069
+ constructor(config) {
5070
+ this.versionManager = new VersionManager(config);
5071
+ this.backupManager = new BackupManager(config.configPath);
5072
+ this.migrationManager = new MigrationManager(config.configPath);
5073
+ }
5074
+ /**
5075
+ * Check for updates without applying
5076
+ */
5077
+ async checkForUpdates() {
5078
+ try {
5079
+ const changes = await this.versionManager.checkForUpdates();
5080
+ if (changes.hasUpdate) {
5081
+ this.displayUpdateInfo(changes);
5082
+ } else {
5083
+ console.log(chalk2.green("\u2713 Your AIKit is up to date"));
5084
+ console.log(` Installed: ${changes.fromVersion}`);
5085
+ console.log(` Latest: ${changes.toVersion}`);
5086
+ }
5087
+ return changes;
5088
+ } catch (error) {
5089
+ logger.error("Failed to check for updates:", error);
5090
+ return null;
5091
+ }
5092
+ }
5093
+ /**
5094
+ * Preview changes without applying
5095
+ */
5096
+ async previewUpdate() {
5097
+ try {
5098
+ console.log(chalk2.bold("\n\u{1F50D} Previewing update...\n"));
5099
+ const changes = await this.versionManager.checkForUpdates();
5100
+ if (!changes.hasUpdate) {
5101
+ console.log(chalk2.green("\u2713 No updates available"));
5102
+ return false;
5103
+ }
5104
+ await this.displayChanges(changes);
5105
+ console.log(chalk2.yellow("\n\u26A0\uFE0F This is a preview - no changes will be made."));
5106
+ console.log(chalk2.gray("Use `aikit sync apply` to apply these changes."));
5107
+ return true;
5108
+ } catch (error) {
5109
+ logger.error("Failed to preview update:", error);
5110
+ return false;
5111
+ }
5112
+ }
5113
+ /**
5114
+ * Apply update
5115
+ */
5116
+ async applyUpdate(options = {}) {
5117
+ try {
5118
+ const changes = await this.versionManager.checkForUpdates();
5119
+ if (!changes.hasUpdate) {
5120
+ console.log(chalk2.green("\u2713 Already up to date"));
5121
+ return {
5122
+ success: true,
5123
+ newSkills: [],
5124
+ updatedSkills: [],
5125
+ removedSkills: [],
5126
+ migrationsRun: []
5127
+ };
5128
+ }
5129
+ await this.displayChanges(changes);
5130
+ if (!options.force) {
5131
+ const { confirmed } = await inquirer.prompt([{
5132
+ type: "confirm",
5133
+ name: "confirmed",
5134
+ message: "Continue with update?",
5135
+ default: false
5136
+ }]);
5137
+ if (!confirmed) {
5138
+ console.log(chalk2.yellow("Update cancelled"));
5139
+ return {
5140
+ success: false,
5141
+ newSkills: [],
5142
+ updatedSkills: [],
5143
+ removedSkills: [],
5144
+ migrationsRun: []
5145
+ };
5146
+ }
5147
+ }
5148
+ let backupId = void 0;
5149
+ if (!options.dryRun && options.backup !== false) {
5150
+ console.log(chalk2.bold("\n\u{1F4E6} Creating backup..."));
5151
+ const backupResult = await this.backupManager.createBackup(
5152
+ changes.fromVersion,
5153
+ changes.toVersion
5154
+ );
5155
+ if (!backupResult) {
5156
+ throw new Error("Failed to create backup");
5157
+ }
5158
+ backupId = backupResult;
5159
+ }
5160
+ for (const conflict of changes.conflicts) {
5161
+ await this.resolveConflict(conflict);
5162
+ }
5163
+ console.log(chalk2.bold("\n\u{1F504} Running migrations..."));
5164
+ const migrationResult = await this.migrationManager.runPendingMigrations();
5165
+ if (!migrationResult.success) {
5166
+ throw new Error(`Migration failed: ${migrationResult.failed.join(", ")}`);
5167
+ }
5168
+ console.log(chalk2.bold("\n\u{1F4DD} Updating skills..."));
5169
+ const updateResult = await this.updateSkills(changes, options);
5170
+ await this.versionManager.updateVersion(changes.toVersion);
5171
+ if (backupId) {
5172
+ const allSkills = await this.versionManager.loadSkillHashes(paths.skills(paths.globalConfig()));
5173
+ await this.versionManager.saveInstalledSkills(allSkills);
5174
+ }
5175
+ console.log(chalk2.green("\n\u2705 Update complete!"));
5176
+ this.displaySummary({
5177
+ success: true,
5178
+ backupId,
5179
+ ...updateResult,
5180
+ migrationsRun: migrationResult.applied
5181
+ });
5182
+ return {
5183
+ success: true,
5184
+ backupId,
5185
+ ...updateResult,
5186
+ migrationsRun: migrationResult.applied
5187
+ };
5188
+ } catch (error) {
5189
+ logger.error("Update failed:", error);
5190
+ console.log(chalk2.red("\n\u274C Update failed"));
5191
+ return {
5192
+ success: false,
5193
+ newSkills: [],
5194
+ updatedSkills: [],
5195
+ removedSkills: [],
5196
+ migrationsRun: []
5197
+ };
5198
+ }
5199
+ }
5200
+ /**
5201
+ * Rollback to previous backup
5202
+ */
5203
+ async rollback(backupId) {
5204
+ try {
5205
+ console.log(chalk2.bold("\n\u{1F504} Rollback...\n"));
5206
+ if (!backupId) {
5207
+ const backups = await this.backupManager.listBackups();
5208
+ if (backups.length === 0) {
5209
+ console.log(chalk2.yellow("No backups available"));
5210
+ return false;
5211
+ }
5212
+ const { selectedBackup } = await inquirer.prompt([{
5213
+ type: "list",
5214
+ name: "selectedBackup",
5215
+ message: "Select backup to restore:",
5216
+ choices: backups.map((b) => ({
5217
+ name: `${b.manifest.backupId} (${b.manifest.fromVersion} \u2192 ${b.manifest.toVersion})`,
5218
+ value: b.manifest.backupId
5219
+ }))
5220
+ }]);
5221
+ backupId = selectedBackup;
5222
+ }
5223
+ if (!backupId) {
5224
+ console.log(chalk2.yellow("No backup ID provided"));
5225
+ return false;
5226
+ }
5227
+ const success = await this.backupManager.restoreBackup(backupId);
5228
+ if (success) {
5229
+ console.log(chalk2.green("\u2713 Rollback complete"));
5230
+ return true;
5231
+ }
5232
+ return false;
5233
+ } catch (error) {
5234
+ logger.error("Rollback failed:", error);
5235
+ return false;
5236
+ }
5237
+ }
5238
+ /**
5239
+ * Display update information
5240
+ */
5241
+ displayUpdateInfo(changes) {
5242
+ console.log(chalk2.bold("\n\u{1F4E2} New version available!\n"));
5243
+ console.log(` ${chalk2.cyan("Current:")} ${changes.fromVersion}`);
5244
+ console.log(` ${chalk2.cyan("Latest:")} ${changes.toVersion}
5245
+ `);
5246
+ }
5247
+ /**
5248
+ * Display changes summary
5249
+ */
5250
+ async displayChanges(changes) {
5251
+ console.log(chalk2.bold("\u{1F4CA} Changes detected:\n"));
5252
+ if (changes.newSkills.length > 0) {
5253
+ console.log(chalk2.green(" New Skills:"));
5254
+ changes.newSkills.forEach((skill) => {
5255
+ console.log(` + ${skill.name} (${skill.category})`);
5256
+ });
5257
+ }
5258
+ if (changes.modifiedSkills.length > 0) {
5259
+ console.log(chalk2.yellow(" Updated Skills:"));
5260
+ changes.modifiedSkills.forEach((skill) => {
5261
+ console.log(` ~ ${skill.name}`);
5262
+ });
5263
+ }
5264
+ if (changes.removedSkills.length > 0) {
5265
+ console.log(chalk2.red(" Removed Skills:"));
5266
+ changes.removedSkills.forEach((skill) => {
5267
+ console.log(` - ${skill.name}`);
5268
+ });
5269
+ }
5270
+ if (changes.conflicts.length > 0) {
5271
+ console.log(chalk2.bold.red(" \u26A0\uFE0F Conflicts:"));
5272
+ changes.conflicts.forEach((conflict) => {
5273
+ console.log(` ! ${conflict.skillName} (user modified)`);
5274
+ });
5275
+ }
5276
+ }
5277
+ /**
5278
+ * Resolve a conflict
5279
+ */
5280
+ async resolveConflict(conflict) {
5281
+ console.log(chalk2.bold.red(`
5282
+ \u26A0\uFE0F Conflict detected: ${conflict.skillName}
5283
+ `));
5284
+ console.log(chalk2.yellow("Your version differs from official version."));
5285
+ const { action } = await inquirer.prompt([{
5286
+ type: "list",
5287
+ name: "action",
5288
+ message: "Choose action:",
5289
+ choices: [
5290
+ {
5291
+ name: "Keep your version (will be renamed to -custom.md)",
5292
+ value: "preserve"
5293
+ },
5294
+ {
5295
+ name: "Overwrite with official version",
5296
+ value: "overwrite"
5297
+ },
5298
+ {
5299
+ name: "Skip this skill",
5300
+ value: "skip"
5301
+ }
5302
+ ]
5303
+ }]);
5304
+ if (action === "skip") {
5305
+ return;
5306
+ }
5307
+ if (action === "overwrite") {
5308
+ return;
5309
+ }
5310
+ console.log(chalk2.yellow(" Your version will be preserved as -custom.md"));
5311
+ }
5312
+ /**
5313
+ * Update skills based on changes
5314
+ */
5315
+ async updateSkills(changes, options) {
5316
+ const globalSkillsPath = paths.skills(paths.globalConfig());
5317
+ const projectSkillsPath = paths.skills(this.versionManager["config"].configPath);
5318
+ const newSkills = [];
5319
+ const updatedSkills = [];
5320
+ const removedSkills = [];
5321
+ for (const skill of changes.newSkills) {
5322
+ if (!options.dryRun) {
5323
+ await this.installSkill(globalSkillsPath, skill, projectSkillsPath);
5324
+ }
5325
+ newSkills.push(skill.name);
5326
+ console.log(chalk2.green(` + ${skill.name}`));
5327
+ }
5328
+ for (const skill of changes.modifiedSkills) {
5329
+ if (!options.dryRun) {
5330
+ await this.installSkill(globalSkillsPath, skill, projectSkillsPath);
5331
+ }
5332
+ updatedSkills.push(skill.name);
5333
+ console.log(chalk2.yellow(` ~ ${skill.name}`));
5334
+ }
5335
+ for (const skill of changes.removedSkills) {
5336
+ if (!options.dryRun) {
5337
+ await this.archiveSkill(projectSkillsPath, skill);
5338
+ }
5339
+ removedSkills.push(skill.name);
5340
+ console.log(chalk2.red(` - ${skill.name} (archived)`));
5341
+ }
5342
+ return {
5343
+ newSkills,
5344
+ updatedSkills,
5345
+ removedSkills
5346
+ };
5347
+ }
5348
+ /**
5349
+ * Install a skill
5350
+ */
5351
+ async installSkill(sourceDir, skill, targetDir) {
5352
+ const sourcePath = join16(sourceDir, skill.category, `${skill.name}.md`);
5353
+ const targetPath = join16(targetDir, skill.category, `${skill.name}.md`);
5354
+ await mkdir9(dirname3(targetPath), { recursive: true });
5355
+ await copyFile(sourcePath, targetPath);
5356
+ }
5357
+ /**
5358
+ * Archive a removed skill
5359
+ */
5360
+ async archiveSkill(targetDir, skill) {
5361
+ const sourcePath = join16(targetDir, skill.category, `${skill.name}.md`);
5362
+ const targetPath = join16(targetDir, skill.category, `${skill.name}-deprecated.md`);
5363
+ try {
5364
+ const content = await readFile10(sourcePath, "utf-8");
5365
+ const deprecatedNotice = `---
5366
+ \u26A0\uFE0F DEPRECATED: This skill has been removed
5367
+
5368
+ Deprecation date: ${(/* @__PURE__ */ new Date()).toISOString()}
5369
+ Reason: Check release notes for replacement
5370
+ ---
5371
+
5372
+ ${content}`;
5373
+ await mkdir9(dirname3(targetPath), { recursive: true });
5374
+ await writeFile11(targetPath, deprecatedNotice);
5375
+ } catch (error) {
5376
+ if (error.code === "ENOENT") {
5377
+ console.log(chalk2.yellow(` - ${skill.name} (not found, skipping)`));
5378
+ } else {
5379
+ throw error;
5380
+ }
5381
+ }
5382
+ }
5383
+ /**
5384
+ * Display sync summary
5385
+ */
5386
+ displaySummary(result) {
5387
+ console.log(chalk2.bold("\n\u{1F4CB} Summary:\n"));
5388
+ console.log(` Updated from: ${chalk2.cyan(result.backupId || "N/A")}`);
5389
+ console.log(` Updated to: ${chalk2.cyan("current")}`);
5390
+ console.log();
5391
+ if (result.newSkills.length > 0) {
5392
+ console.log(chalk2.green(` ${result.newSkills.length} new skills installed`));
5393
+ }
5394
+ if (result.updatedSkills.length > 0) {
5395
+ console.log(chalk2.yellow(` ${result.updatedSkills.length} skills updated`));
5396
+ }
5397
+ if (result.removedSkills.length > 0) {
5398
+ console.log(chalk2.red(` ${result.removedSkills.length} skills archived`));
5399
+ }
5400
+ if (result.migrationsRun.length > 0) {
5401
+ console.log(chalk2.blue(` ${result.migrationsRun.length} migrations run`));
5402
+ }
5403
+ if (result.backupId) {
5404
+ console.log(chalk2.gray(`
5405
+ Rollback available: aikit sync rollback ${result.backupId}`));
5406
+ }
5407
+ }
5408
+ };
5409
+
5410
+ // src/cli.ts
4224
5411
  var program = new Command();
4225
5412
  program.name("aikit").description("Open-source AI coding agent toolkit for OpenCode").version(getVersion());
4226
5413
  program.command("init").description("Initialize AIKit configuration").option("-g, --global", "Initialize global configuration").option("-p, --project", "Initialize project-level configuration").action(async (options) => {
4227
5414
  const configDir = options.global ? paths.globalConfig() : paths.projectConfig();
4228
- console.log(chalk2.bold("\n\u{1F680} AIKit Setup\n"));
5415
+ console.log(chalk3.bold("\n\u{1F680} AIKit Setup\n"));
4229
5416
  logger.info(`Initializing AIKit in ${configDir}...`);
4230
5417
  try {
4231
5418
  await initializeConfig(configDir, options.global);
@@ -4237,17 +5424,17 @@ program.command("init").description("Initialize AIKit configuration").option("-g
4237
5424
  if (result.count > 0) {
4238
5425
  logger.success(`\u2713 Synced ${result.count} skills`);
4239
5426
  }
4240
- console.log(chalk2.bold("\n\u{1F50D} Checking CLI tools...\n"));
5427
+ console.log(chalk3.bold("\n\u{1F50D} Checking CLI tools...\n"));
4241
5428
  const cliTools = await CliDetector.checkAll();
4242
5429
  const installableTools = CliDetector.filterInstallable(cliTools);
4243
5430
  for (const tool of cliTools) {
4244
- const status = tool.isInstalled ? chalk2.green("\u2713 Installed") : chalk2.yellow("\u2717 Not installed");
4245
- const version = tool.version ? chalk2.gray(` (${tool.version})`) : "";
4246
- console.log(` ${status} ${chalk2.cyan(tool.displayName)}${version}`);
5431
+ const status = tool.installed ? chalk3.green("\u2713 Installed") : chalk3.yellow("\u2717 Not installed");
5432
+ const version = tool.version ? chalk3.gray(` (${tool.version})`) : "";
5433
+ console.log(` ${status} ${chalk3.cyan(tool.displayName)}${version}`);
4247
5434
  }
4248
5435
  if (installableTools.length > 0) {
4249
5436
  console.log();
4250
- const { action } = await inquirer.prompt([
5437
+ const { action } = await inquirer2.prompt([
4251
5438
  {
4252
5439
  type: "list",
4253
5440
  name: "action",
@@ -4287,7 +5474,7 @@ program.command("init").description("Initialize AIKit configuration").option("-g
4287
5474
  console.log();
4288
5475
  logger.success("\u2713 CLI tools installed");
4289
5476
  } else {
4290
- const { installTools } = await inquirer.prompt([
5477
+ const { installTools } = await inquirer2.prompt([
4291
5478
  {
4292
5479
  type: "checkbox",
4293
5480
  name: "installTools",
@@ -4331,16 +5518,16 @@ program.command("init").description("Initialize AIKit configuration").option("-g
4331
5518
  }
4332
5519
  const opencodePath = paths.opencodeConfig();
4333
5520
  await installToOpenCode(opencodePath);
4334
- console.log(chalk2.bold("\n\u2728 AIKit is ready!\n"));
5521
+ console.log(chalk3.bold("\n\u2728 AIKit is ready!\n"));
4335
5522
  console.log("Usage in OpenCode:");
4336
- console.log(chalk2.cyan(" /skills") + " - List all available skills");
4337
- console.log(chalk2.cyan(" /plan") + " - Create implementation plan");
4338
- console.log(chalk2.cyan(" /tdd") + " - Test-driven development");
4339
- console.log(chalk2.cyan(" /debug") + " - Systematic debugging");
4340
- console.log(chalk2.cyan(" /review") + " - Code review checklist");
4341
- console.log(chalk2.cyan(" /git") + " - Git workflow");
4342
- console.log(chalk2.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
4343
- console.log("\nPress " + chalk2.bold("Ctrl+K") + " in OpenCode to see all commands.\n");
5523
+ console.log(chalk3.cyan(" /skills") + " - List all available skills");
5524
+ console.log(chalk3.cyan(" /plan") + " - Create implementation plan");
5525
+ console.log(chalk3.cyan(" /tdd") + " - Test-driven development");
5526
+ console.log(chalk3.cyan(" /debug") + " - Systematic debugging");
5527
+ console.log(chalk3.cyan(" /review") + " - Code review checklist");
5528
+ console.log(chalk3.cyan(" /git") + " - Git workflow");
5529
+ console.log(chalk3.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
5530
+ console.log("\nPress " + chalk3.bold("Ctrl+K") + " in OpenCode to see all commands.\n");
4344
5531
  }
4345
5532
  } catch (error) {
4346
5533
  logger.error("Failed to initialize AIKit:", error);
@@ -4358,6 +5545,32 @@ program.command("install").description("Install AIKit to OpenCode configuration"
4358
5545
  process.exit(1);
4359
5546
  }
4360
5547
  });
5548
+ program.command("sync [subcommand]").description("Update AIKit to latest version").option("--dry-run", "Preview changes without applying").option("-f, --force", "Skip confirmation prompts").option("--no-backup", "Skip creating backup").action(async (subcommand, options) => {
5549
+ const config = await loadConfig();
5550
+ const syncEngine = new SyncEngine(config);
5551
+ if (!subcommand) {
5552
+ await syncEngine.applyUpdate(options);
5553
+ } else {
5554
+ switch (subcommand) {
5555
+ case "check":
5556
+ await syncEngine.checkForUpdates();
5557
+ break;
5558
+ case "preview":
5559
+ await syncEngine.previewUpdate();
5560
+ break;
5561
+ case "apply":
5562
+ await syncEngine.applyUpdate(options);
5563
+ break;
5564
+ case "rollback":
5565
+ await syncEngine.rollback();
5566
+ break;
5567
+ default:
5568
+ logger.error(`Unknown subcommand: ${subcommand}`);
5569
+ console.log(chalk3.gray("Available subcommands: check, preview, apply, rollback"));
5570
+ process.exit(1);
5571
+ }
5572
+ }
5573
+ });
4361
5574
  var skillsCmd = program.command("skills").description("Manage skills");
4362
5575
  skillsCmd.command("list").description("List available skills and tools with their configuration status").action(async () => {
4363
5576
  const config = await loadConfig();
@@ -4366,31 +5579,31 @@ skillsCmd.command("list").description("List available skills and tools with thei
4366
5579
  const { ToolConfigManager: ToolConfigManager2 } = await Promise.resolve().then(() => (init_tool_config(), tool_config_exports));
4367
5580
  const toolConfigManager = new ToolConfigManager2(config);
4368
5581
  const tools = await toolConfigManager.listTools();
4369
- console.log(chalk2.bold("\n\u{1F4DA} Available Skills:\n"));
5582
+ console.log(chalk3.bold("\n\u{1F4DA} Available Skills:\n"));
4370
5583
  for (const skill of skills) {
4371
- console.log(` ${chalk2.cyan(skill.name)} - ${skill.description}`);
5584
+ console.log(` ${chalk3.cyan(skill.name)} - ${skill.description}`);
4372
5585
  }
4373
- console.log(chalk2.bold("\n\u{1F527} Available Tools:\n"));
5586
+ console.log(chalk3.bold("\n\u{1F527} Available Tools:\n"));
4374
5587
  for (const tool of tools) {
4375
5588
  let statusIcon = " ";
4376
5589
  let statusText = "";
4377
5590
  if (tool.status === "ready") {
4378
- statusIcon = chalk2.green("\u2713");
4379
- statusText = chalk2.gray("(ready)");
5591
+ statusIcon = chalk3.green("\u2713");
5592
+ statusText = chalk3.gray("(ready)");
4380
5593
  } else if (tool.status === "needs_config") {
4381
- statusIcon = chalk2.yellow("\u26A0");
4382
- statusText = chalk2.yellow("(needs config)");
5594
+ statusIcon = chalk3.yellow("\u26A0");
5595
+ statusText = chalk3.yellow("(needs config)");
4383
5596
  } else if (tool.status === "error") {
4384
- statusIcon = chalk2.red("\u2717");
4385
- statusText = chalk2.red("(error)");
5597
+ statusIcon = chalk3.red("\u2717");
5598
+ statusText = chalk3.red("(error)");
4386
5599
  }
4387
- console.log(` ${statusIcon} ${chalk2.cyan(tool.name)} - ${tool.description} ${statusText}`);
5600
+ console.log(` ${statusIcon} ${chalk3.cyan(tool.name)} - ${tool.description} ${statusText}`);
4388
5601
  if (tool.errorMessage) {
4389
- console.log(` ${chalk2.red("Error:")} ${tool.errorMessage}`);
5602
+ console.log(` ${chalk3.red("Error:")} ${tool.errorMessage}`);
4390
5603
  }
4391
5604
  }
4392
5605
  console.log();
4393
- console.log(chalk2.gray('Tip: Use "aikit skills <tool-name> config" to configure a tool\n'));
5606
+ console.log(chalk3.gray('Tip: Use "aikit skills <tool-name> config" to configure a tool\n'));
4394
5607
  });
4395
5608
  skillsCmd.command("show <name>").description("Show skill details").action(async (name) => {
4396
5609
  const config = await loadConfig();
@@ -4400,11 +5613,11 @@ skillsCmd.command("show <name>").description("Show skill details").action(async
4400
5613
  logger.error(`Skill not found: ${name}`);
4401
5614
  process.exit(1);
4402
5615
  }
4403
- console.log(chalk2.bold(`
5616
+ console.log(chalk3.bold(`
4404
5617
  \u{1F4D6} Skill: ${skill.name}
4405
5618
  `));
4406
- console.log(chalk2.gray(skill.description));
4407
- console.log(chalk2.bold("\nWorkflow:"));
5619
+ console.log(chalk3.gray(skill.description));
5620
+ console.log(chalk3.bold("\nWorkflow:"));
4408
5621
  console.log(skill.content);
4409
5622
  });
4410
5623
  skillsCmd.command("create <name>").description("Create a new skill").action(async (name) => {
@@ -4420,11 +5633,11 @@ skillsCmd.command("sync").description("Sync global skills to project").action(as
4420
5633
  if (result.count === 0) {
4421
5634
  logger.info("Skills already in sync or no global skills to sync");
4422
5635
  } else {
4423
- console.log(chalk2.bold(`
5636
+ console.log(chalk3.bold(`
4424
5637
  \u2713 Synced ${result.count} skills to project:
4425
5638
  `));
4426
5639
  for (const skill of result.synced) {
4427
- console.log(` ${chalk2.cyan("\u2022")} ${skill}`);
5640
+ console.log(` ${chalk3.cyan("\u2022")} ${skill}`);
4428
5641
  }
4429
5642
  console.log();
4430
5643
  }
@@ -4436,18 +5649,18 @@ skillsCmd.command("config <tool-name>").description("Configure a tool (e.g., con
4436
5649
  const tool = await toolConfigManager.getToolConfig(toolName);
4437
5650
  if (!tool) {
4438
5651
  logger.error(`Tool not found: ${toolName}`);
4439
- console.log(chalk2.gray("\nAvailable tools:"));
5652
+ console.log(chalk3.gray("\nAvailable tools:"));
4440
5653
  const tools = await toolConfigManager.listTools();
4441
5654
  for (const t of tools) {
4442
- console.log(` - ${chalk2.cyan(t.name)}`);
5655
+ console.log(` - ${chalk3.cyan(t.name)}`);
4443
5656
  }
4444
5657
  console.log();
4445
5658
  process.exit(1);
4446
5659
  }
4447
- console.log(chalk2.bold(`
5660
+ console.log(chalk3.bold(`
4448
5661
  \u{1F527} Configuring: ${tool.name}
4449
5662
  `));
4450
- console.log(chalk2.gray(tool.description));
5663
+ console.log(chalk3.gray(tool.description));
4451
5664
  console.log();
4452
5665
  if (tool.configMethod === "oauth") {
4453
5666
  if (toolName === "figma-analysis") {
@@ -4455,12 +5668,12 @@ skillsCmd.command("config <tool-name>").description("Configure a tool (e.g., con
4455
5668
  const oauth = new FigmaOAuth2(toolConfigManager);
4456
5669
  try {
4457
5670
  const token = await oauth.authenticate();
4458
- console.log(chalk2.gray("\nValidating token..."));
5671
+ console.log(chalk3.gray("\nValidating token..."));
4459
5672
  const isValid = await oauth.validateToken(token);
4460
5673
  if (isValid) {
4461
5674
  logger.success(`
4462
5675
  \u2705 ${tool.name} configured successfully!`);
4463
- console.log(chalk2.gray("\nYou can now use the /analyze-figma command in OpenCode.\n"));
5676
+ console.log(chalk3.gray("\nYou can now use the /analyze-figma command in OpenCode.\n"));
4464
5677
  } else {
4465
5678
  await toolConfigManager.updateToolConfig(toolName, {
4466
5679
  status: "error",
@@ -4499,20 +5712,20 @@ skillsCmd.command("*").description("Configure a tool (e.g., figma-analysis confi
4499
5712
  const tool = await toolConfigManager.getToolConfig(toolName);
4500
5713
  if (!tool) {
4501
5714
  logger.error(`Tool not found: ${toolName}`);
4502
- console.log(chalk2.gray("\nAvailable tools:"));
5715
+ console.log(chalk3.gray("\nAvailable tools:"));
4503
5716
  const tools = await toolConfigManager.listTools();
4504
5717
  for (const t of tools) {
4505
- console.log(` - ${chalk2.cyan(t.name)}`);
5718
+ console.log(` - ${chalk3.cyan(t.name)}`);
4506
5719
  }
4507
5720
  console.log();
4508
- console.log(chalk2.gray("Tip: If you meant to show a skill, use: aikit skills show <name>"));
5721
+ console.log(chalk3.gray("Tip: If you meant to show a skill, use: aikit skills show <name>"));
4509
5722
  console.log();
4510
5723
  process.exit(1);
4511
5724
  }
4512
- console.log(chalk2.bold(`
5725
+ console.log(chalk3.bold(`
4513
5726
  \u{1F527} Configuring: ${tool.name}
4514
5727
  `));
4515
- console.log(chalk2.gray(tool.description));
5728
+ console.log(chalk3.gray(tool.description));
4516
5729
  console.log();
4517
5730
  if (tool.configMethod === "oauth") {
4518
5731
  if (toolName === "figma-analysis") {
@@ -4520,12 +5733,12 @@ skillsCmd.command("*").description("Configure a tool (e.g., figma-analysis confi
4520
5733
  const oauth = new FigmaOAuth2(toolConfigManager);
4521
5734
  try {
4522
5735
  const token = await oauth.authenticate();
4523
- console.log(chalk2.gray("\nValidating token..."));
5736
+ console.log(chalk3.gray("\nValidating token..."));
4524
5737
  const isValid = await oauth.validateToken(token);
4525
5738
  if (isValid) {
4526
5739
  logger.success(`
4527
5740
  \u2705 ${tool.name} configured successfully!`);
4528
- console.log(chalk2.gray("\nYou can now use the /analyze-figma command in OpenCode.\n"));
5741
+ console.log(chalk3.gray("\nYou can now use the /analyze-figma command in OpenCode.\n"));
4529
5742
  } else {
4530
5743
  await toolConfigManager.updateToolConfig(toolName, {
4531
5744
  status: "error",
@@ -4554,7 +5767,7 @@ skillsCmd.command("*").description("Configure a tool (e.g., figma-analysis confi
4554
5767
  }
4555
5768
  } else {
4556
5769
  logger.error(`Unknown command: ${toolName || "unknown"} ${action || ""}`);
4557
- console.log(chalk2.gray("\nAvailable commands:"));
5770
+ console.log(chalk3.gray("\nAvailable commands:"));
4558
5771
  console.log(" aikit skills list - List all skills and tools");
4559
5772
  console.log(" aikit skills show <name> - Show skill details");
4560
5773
  console.log(" aikit skills config <tool-name> - Configure a tool");
@@ -4568,10 +5781,10 @@ agentsCmd.command("list").description("List available agents").action(async () =
4568
5781
  const config = await loadConfig();
4569
5782
  const manager = new AgentManager(config);
4570
5783
  const agents = manager.listAgents();
4571
- console.log(chalk2.bold("\n\u{1F916} Available Agents:\n"));
5784
+ console.log(chalk3.bold("\n\u{1F916} Available Agents:\n"));
4572
5785
  for (const agent of agents) {
4573
- console.log(` ${chalk2.cyan(`@${agent.name}`)} - ${agent.description}`);
4574
- console.log(chalk2.gray(` Use when: ${agent.useWhen}`));
5786
+ console.log(` ${chalk3.cyan(`@${agent.name}`)} - ${agent.description}`);
5787
+ console.log(chalk3.gray(` Use when: ${agent.useWhen}`));
4575
5788
  }
4576
5789
  console.log();
4577
5790
  });
@@ -4580,13 +5793,13 @@ commandsCmd.command("list").description("List available commands").action(async
4580
5793
  const config = await loadConfig();
4581
5794
  const runner = new CommandRunner(config);
4582
5795
  const commands = await runner.listCommands();
4583
- console.log(chalk2.bold("\n\u26A1 Available Commands:\n"));
5796
+ console.log(chalk3.bold("\n\u26A1 Available Commands:\n"));
4584
5797
  const groups = groupBy(commands, (c) => c.category);
4585
5798
  for (const [category, cmds] of Object.entries(groups)) {
4586
- console.log(chalk2.bold.yellow(`
5799
+ console.log(chalk3.bold.yellow(`
4587
5800
  ${category}:`));
4588
5801
  for (const cmd of cmds) {
4589
- console.log(` ${chalk2.cyan(`/${cmd.name}`)} - ${cmd.description}`);
5802
+ console.log(` ${chalk3.cyan(`/${cmd.name}`)} - ${cmd.description}`);
4590
5803
  }
4591
5804
  }
4592
5805
  console.log();
@@ -4596,9 +5809,9 @@ toolsCmd.command("list").description("List available tools").action(async () =>
4596
5809
  const config = await loadConfig();
4597
5810
  const registry = new ToolRegistry(config);
4598
5811
  const tools = await registry.listTools();
4599
- console.log(chalk2.bold("\n\u{1F527} Available Tools:\n"));
5812
+ console.log(chalk3.bold("\n\u{1F527} Available Tools:\n"));
4600
5813
  for (const tool of tools) {
4601
- console.log(` ${chalk2.cyan(tool.name)} - ${tool.description}`);
5814
+ console.log(` ${chalk3.cyan(tool.name)} - ${tool.description}`);
4602
5815
  }
4603
5816
  console.log();
4604
5817
  });
@@ -4607,10 +5820,10 @@ pluginsCmd.command("list").description("List available plugins").action(async ()
4607
5820
  const config = await loadConfig();
4608
5821
  const system = new PluginSystem(config);
4609
5822
  const plugins = await system.listPlugins();
4610
- console.log(chalk2.bold("\n\u{1F50C} Available Plugins:\n"));
5823
+ console.log(chalk3.bold("\n\u{1F50C} Available Plugins:\n"));
4611
5824
  for (const plugin of plugins) {
4612
- const status = plugin.enabled ? chalk2.green("\u2713") : chalk2.gray("\u25CB");
4613
- console.log(` ${status} ${chalk2.cyan(plugin.name)} - ${plugin.description}`);
5825
+ const status = plugin.enabled ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
5826
+ console.log(` ${status} ${chalk3.cyan(plugin.name)} - ${plugin.description}`);
4614
5827
  }
4615
5828
  console.log();
4616
5829
  });
@@ -4619,10 +5832,10 @@ memoryCmd.command("list").description("List memory entries").action(async () =>
4619
5832
  const config = await loadConfig();
4620
5833
  const memory = new MemoryManager(config);
4621
5834
  const entries = await memory.list();
4622
- console.log(chalk2.bold("\n\u{1F9E0} Memory Entries:\n"));
5835
+ console.log(chalk3.bold("\n\u{1F9E0} Memory Entries:\n"));
4623
5836
  for (const entry of entries) {
4624
- console.log(` ${chalk2.cyan(entry.key)} - ${entry.summary}`);
4625
- console.log(chalk2.gray(` Updated: ${entry.updatedAt}`));
5837
+ console.log(` ${chalk3.cyan(entry.key)} - ${entry.summary}`);
5838
+ console.log(chalk3.gray(` Updated: ${entry.updatedAt}`));
4626
5839
  }
4627
5840
  console.log();
4628
5841
  });
@@ -4640,19 +5853,19 @@ var beadsCmd = program.command("beads").description("Beads task management integ
4640
5853
  beadsCmd.command("status").description("Show current Beads status").action(async () => {
4641
5854
  const beads = new BeadsIntegration();
4642
5855
  const status = await beads.getStatus();
4643
- console.log(chalk2.bold("\n\u{1F4FF} Beads Status:\n"));
5856
+ console.log(chalk3.bold("\n\u{1F4FF} Beads Status:\n"));
4644
5857
  console.log(` Active tasks: ${status.activeTasks}`);
4645
5858
  console.log(` Completed: ${status.completedTasks}`);
4646
5859
  console.log(` Current: ${status.currentTask || "None"}`);
4647
5860
  console.log();
4648
5861
  });
4649
5862
  program.command("status").description("Show AIKit status").action(async () => {
4650
- console.log(chalk2.bold(`
5863
+ console.log(chalk3.bold(`
4651
5864
  \u{1F680} AIKit v${getVersion}
4652
5865
  `));
4653
5866
  try {
4654
5867
  const config = await loadConfig();
4655
- console.log(chalk2.green("\u2713 Configuration loaded"));
5868
+ console.log(chalk3.green("\u2713 Configuration loaded"));
4656
5869
  const skillEngine = new SkillEngine(config);
4657
5870
  const skills = await skillEngine.listSkills();
4658
5871
  console.log(` Skills: ${skills.length}`);
@@ -4667,15 +5880,15 @@ program.command("status").description("Show AIKit status").action(async () => {
4667
5880
  console.log(` Tools: ${tools.length}`);
4668
5881
  const beads = new BeadsIntegration();
4669
5882
  const beadsStatus = await beads.isInstalled();
4670
- console.log(` Beads: ${beadsStatus ? chalk2.green("Installed") : chalk2.yellow("Not installed")}`);
5883
+ console.log(` Beads: ${beadsStatus ? chalk3.green("Installed") : chalk3.yellow("Not installed")}`);
4671
5884
  } catch (error) {
4672
- console.log(chalk2.yellow('\u26A0 AIKit not initialized. Run "aikit init" to get started.'));
5885
+ console.log(chalk3.yellow('\u26A0 AIKit not initialized. Run "aikit init" to get started.'));
4673
5886
  }
4674
5887
  console.log();
4675
5888
  });
4676
5889
  async function initializeConfig(configDir, _isGlobal) {
4677
- const { mkdir: mkdir9, writeFile: writeFile9 } = await import("fs/promises");
4678
- const { join: join14 } = await import("path");
5890
+ const { mkdir: mkdir11, writeFile: writeFile13 } = await import("fs/promises");
5891
+ const { join: join18 } = await import("path");
4679
5892
  const dirs = [
4680
5893
  "",
4681
5894
  "skills",
@@ -4694,7 +5907,7 @@ async function initializeConfig(configDir, _isGlobal) {
4694
5907
  "memory/research"
4695
5908
  ];
4696
5909
  for (const dir of dirs) {
4697
- await mkdir9(join14(configDir, dir), { recursive: true });
5910
+ await mkdir11(join18(configDir, dir), { recursive: true });
4698
5911
  }
4699
5912
  const defaultConfig = {
4700
5913
  version: getVersion,
@@ -4707,8 +5920,8 @@ async function initializeConfig(configDir, _isGlobal) {
4707
5920
  beads: { enabled: true },
4708
5921
  antiHallucination: { enabled: true }
4709
5922
  };
4710
- await writeFile9(
4711
- join14(configDir, "aikit.json"),
5923
+ await writeFile13(
5924
+ join18(configDir, "aikit.json"),
4712
5925
  JSON.stringify(defaultConfig, null, 2)
4713
5926
  );
4714
5927
  const agentsMd = `# AIKit Agent Rules
@@ -4731,26 +5944,26 @@ async function initializeConfig(configDir, _isGlobal) {
4731
5944
  ## Project-Specific Rules
4732
5945
  Add your project-specific rules here.
4733
5946
  `;
4734
- await writeFile9(join14(configDir, "AGENTS.md"), agentsMd);
5947
+ await writeFile13(join18(configDir, "AGENTS.md"), agentsMd);
4735
5948
  }
4736
5949
  async function configureMcpServer(projectPath) {
4737
- const { mkdir: mkdir9, writeFile: writeFile9, readFile: readFile8 } = await import("fs/promises");
4738
- const { join: join14 } = await import("path");
5950
+ const { mkdir: mkdir11, writeFile: writeFile13, readFile: readFile12 } = await import("fs/promises");
5951
+ const { join: join18 } = await import("path");
4739
5952
  const { existsSync: existsSync5 } = await import("fs");
4740
5953
  const { homedir: homedir3 } = await import("os");
4741
5954
  const { fileURLToPath: fileURLToPath3 } = await import("url");
4742
- const { dirname: dirname2 } = await import("path");
5955
+ const { dirname: dirname4 } = await import("path");
4743
5956
  const currentFile = fileURLToPath3(import.meta.url);
4744
- const currentDir = dirname2(currentFile);
4745
- const aikitPath = join14(currentDir, "..");
4746
- const mcpServerPath = join14(aikitPath, "dist", "mcp-server.js");
5957
+ const currentDir = dirname4(currentFile);
5958
+ const aikitPath = join18(currentDir, "..");
5959
+ const mcpServerPath = join18(aikitPath, "dist", "mcp-server.js");
4747
5960
  const configLocations = [
4748
5961
  // Global config (most common)
4749
- join14(homedir3(), ".config", "opencode", "opencode.json"),
5962
+ join18(homedir3(), ".config", "opencode", "opencode.json"),
4750
5963
  // Project-level config
4751
- join14(projectPath, ".opencode", "opencode.json"),
5964
+ join18(projectPath, ".opencode", "opencode.json"),
4752
5965
  // Alternative global location
4753
- join14(homedir3(), ".opencode", "opencode.json")
5966
+ join18(homedir3(), ".opencode", "opencode.json")
4754
5967
  ];
4755
5968
  const mcpServerConfig = {
4756
5969
  type: "local",
@@ -4759,12 +5972,12 @@ async function configureMcpServer(projectPath) {
4759
5972
  };
4760
5973
  for (const configPath of configLocations) {
4761
5974
  try {
4762
- const configDir = join14(configPath, "..");
4763
- await mkdir9(configDir, { recursive: true });
5975
+ const configDir = join18(configPath, "..");
5976
+ await mkdir11(configDir, { recursive: true });
4764
5977
  let config = {};
4765
5978
  if (existsSync5(configPath)) {
4766
5979
  try {
4767
- const existing = await readFile8(configPath, "utf-8");
5980
+ const existing = await readFile12(configPath, "utf-8");
4768
5981
  config = JSON.parse(existing);
4769
5982
  } catch {
4770
5983
  config = {};
@@ -4774,7 +5987,7 @@ async function configureMcpServer(projectPath) {
4774
5987
  config.mcp = {};
4775
5988
  }
4776
5989
  config.mcp.aikit = mcpServerConfig;
4777
- await writeFile9(configPath, JSON.stringify(config, null, 2));
5990
+ await writeFile13(configPath, JSON.stringify(config, null, 2));
4778
5991
  logger.success(`
4779
5992
  \u2705 MCP server configured: ${configPath}`);
4780
5993
  logger.info(` Server: node ${mcpServerPath}`);
@@ -4783,9 +5996,9 @@ async function configureMcpServer(projectPath) {
4783
5996
  continue;
4784
5997
  }
4785
5998
  }
4786
- const instructionsPath = join14(projectPath, ".opencode", "MCP_SETUP.md");
4787
- await mkdir9(join14(projectPath, ".opencode"), { recursive: true });
4788
- await writeFile9(instructionsPath, `# AIKit MCP Server Configuration
5999
+ const instructionsPath = join18(projectPath, ".opencode", "MCP_SETUP.md");
6000
+ await mkdir11(join18(projectPath, ".opencode"), { recursive: true });
6001
+ await writeFile13(instructionsPath, `# AIKit MCP Server Configuration
4789
6002
 
4790
6003
  ## Automatic Setup Failed
4791
6004
 
@@ -4848,15 +6061,15 @@ async function installCliTool(tool) {
4848
6061
  }
4849
6062
  }
4850
6063
  async function installToOpenCode(_opencodePath) {
4851
- const { mkdir: mkdir9, writeFile: writeFile9, access: access5 } = await import("fs/promises");
4852
- const { join: join14 } = await import("path");
6064
+ const { mkdir: mkdir11, writeFile: writeFile13, access: access5 } = await import("fs/promises");
6065
+ const { join: join18 } = await import("path");
4853
6066
  const projectPath = process.cwd();
4854
- const opencodeCommandDir = join14(projectPath, ".opencode", "command");
4855
- const aikitDir = join14(projectPath, ".aikit");
4856
- const opencodeAgentDir = join14(paths.opencodeConfig(), "agent");
4857
- await mkdir9(opencodeCommandDir, { recursive: true });
4858
- await mkdir9(join14(aikitDir, "skills"), { recursive: true });
4859
- await mkdir9(opencodeAgentDir, { recursive: true });
6067
+ const opencodeCommandDir = join18(projectPath, ".opencode", "command");
6068
+ const aikitDir = join18(projectPath, ".aikit");
6069
+ const opencodeAgentDir = join18(paths.opencodeConfig(), "agent");
6070
+ await mkdir11(opencodeCommandDir, { recursive: true });
6071
+ await mkdir11(join18(aikitDir, "skills"), { recursive: true });
6072
+ await mkdir11(opencodeAgentDir, { recursive: true });
4860
6073
  const agentFiles = {
4861
6074
  agent: `---
4862
6075
  description: General-purpose default agent (OpenCode compatibility).
@@ -4925,14 +6138,60 @@ tools:
4925
6138
  "*": true
4926
6139
  ---
4927
6140
 
4928
- Use to interpret visual assets (components, layout, colors, typography) and translate to tasks.`
6141
+ Use to interpret visual assets (components, layout, colors, typography) and translate to tasks.`,
6142
+ "one-shot": `---
6143
+ description: End-to-end autonomous task execution (beta). Complete tasks from start to finish.
6144
+ mode: subagent
6145
+ tools:
6146
+ "*": true
6147
+ ---
6148
+
6149
+ \u26A0\uFE0F BETA: This mode is experimental. Use for straightforward tasks first.
6150
+
6151
+ ## One-Shot Mode - Autonomous Task Execution
6152
+
6153
+ Execute tasks end-to-end with minimal intervention:
6154
+
6155
+ ### Workflow Phases
6156
+ 1. **REQUIREMENTS** - Gather task type, scope, dependencies, success criteria
6157
+ 2. **PLANNING** - Create detailed plan, recommend skills/tools, create tracking bead
6158
+ 3. **COMPLEXITY** - Auto-split if: >30min, >10 files, >500 lines, >2 sub-systems
6159
+ 4. **EXECUTION** - Parallel tasks (max 3), dynamic agent delegation
6160
+ 5. **TESTING** - Run until pass: typecheck \u2192 test \u2192 lint \u2192 build (max 3 retries)
6161
+ 6. **VERIFICATION** - Quality gates \u2713 \u2192 Manual verification \u2192 Deployment approval
6162
+ 7. **COMPLETION** - Generate proof, update tracking, collect feedback
6163
+
6164
+ ### Quality Gates (ALL must pass)
6165
+ - \`npm run typecheck\` - No type errors
6166
+ - \`npm run test\` - All tests pass
6167
+ - \`npm run lint\` - No lint errors
6168
+ - \`npm run build\` - Build succeeds
6169
+
6170
+ ### Error Recovery (3 Levels)
6171
+ - **Level 1**: Auto-fix (type errors, lint --fix)
6172
+ - **Level 2**: Alternative approach via @review
6173
+ - **Level 3**: User intervention + follow-up task
6174
+
6175
+ ### Delegates To
6176
+ @planner for planning, @build for implementation, @review for code review,
6177
+ @scout for research, @explore for navigation, @vision for visual analysis.
6178
+
6179
+ ### Best Use Cases
6180
+ - Straightforward features with clear scope
6181
+ - Bug fixes with known reproduction steps
6182
+ - Refactoring with defined boundaries
6183
+
6184
+ ### Consider Alternatives For
6185
+ - Complex multi-system features \u2192 Use /plan + /implement
6186
+ - Exploratory research \u2192 Use /research first
6187
+ - Critical production changes \u2192 Manual with /review`
4929
6188
  };
4930
6189
  for (const [name, content] of Object.entries(agentFiles)) {
4931
- const filePath = join14(opencodeAgentDir, `${name}.md`);
6190
+ const filePath = join18(opencodeAgentDir, `${name}.md`);
4932
6191
  try {
4933
6192
  await access5(filePath);
4934
6193
  } catch {
4935
- await writeFile9(filePath, content, "utf8");
6194
+ await writeFile13(filePath, content, "utf8");
4936
6195
  }
4937
6196
  }
4938
6197
  const config = await loadConfig();
@@ -5185,8 +6444,8 @@ ${cmd.content}
5185
6444
  }
5186
6445
  let count = 0;
5187
6446
  for (const [name, content] of Object.entries(opencodeCommands)) {
5188
- const filePath = join14(opencodeCommandDir, `${name}.md`);
5189
- await writeFile9(filePath, content.trim());
6447
+ const filePath = join18(opencodeCommandDir, `${name}.md`);
6448
+ await writeFile13(filePath, content.trim());
5190
6449
  logger.info(` \u2713 Created /${name} command`);
5191
6450
  count++;
5192
6451
  }