@tdsoft-tech/aikit 0.1.17 → 0.1.18

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
@@ -122,6 +122,34 @@ var init_paths = __esm({
122
122
  */
123
123
  memory(configPath) {
124
124
  return join(configPath, "memory");
125
+ },
126
+ /**
127
+ * Get the Claude Code CLI configuration directory
128
+ */
129
+ claudeConfig(scope) {
130
+ if (scope === "project") {
131
+ return join(process.cwd(), ".claude");
132
+ }
133
+ const base = process.platform === "win32" ? process.env.APPDATA || join(homedir(), "AppData", "Roaming") : join(homedir(), ".claude");
134
+ return base;
135
+ },
136
+ /**
137
+ * Get Claude Code CLI commands directory
138
+ */
139
+ claudeCommands(project) {
140
+ return join(this.claudeConfig(project ? "project" : "user"), "commands");
141
+ },
142
+ /**
143
+ * Get Claude Code CLI skills directory
144
+ */
145
+ claudeSkills(project) {
146
+ return join(this.claudeConfig(project ? "project" : "user"), "skills");
147
+ },
148
+ /**
149
+ * Get Claude Code CLI agents directory
150
+ */
151
+ claudeAgents(project) {
152
+ return join(this.claudeConfig(project ? "project" : "user"), "agents");
125
153
  }
126
154
  };
127
155
  }
@@ -375,8 +403,8 @@ var init_memory = __esm({
375
403
  for (const subDir of subDirs) {
376
404
  const dirPath = join6(memoryPath, subDir);
377
405
  try {
378
- const { readdir: readdir10 } = await import("fs/promises");
379
- const files = await readdir10(dirPath);
406
+ const { readdir: readdir11 } = await import("fs/promises");
407
+ const files = await readdir11(dirPath);
380
408
  for (const file of files) {
381
409
  if (!file.endsWith(".md")) continue;
382
410
  const content = await readFile4(join6(dirPath, file), "utf-8");
@@ -1113,6 +1141,7 @@ __export(beads_exports, {
1113
1141
  BeadsIntegration: () => BeadsIntegration
1114
1142
  });
1115
1143
  import { readFile as readFile6, writeFile as writeFile5, readdir as readdir4, access as access3, constants as constants3, mkdir as mkdir5 } from "fs/promises";
1144
+ import { existsSync as existsSync4 } from "fs";
1116
1145
  import { join as join9 } from "path";
1117
1146
  import { exec } from "child_process";
1118
1147
  import { promisify } from "util";
@@ -1228,11 +1257,15 @@ bd init
1228
1257
  }
1229
1258
  }
1230
1259
  /**
1231
- * Setup git hooks for Beads integration
1260
+ * Setup git hooks
1232
1261
  */
1233
1262
  async setupGitHooks() {
1234
1263
  try {
1235
1264
  const gitHooksDir = join9(this.projectPath, ".git", "hooks");
1265
+ if (!existsSync4(gitHooksDir)) {
1266
+ logger.info("Not a git repository, skipping git hooks setup");
1267
+ return true;
1268
+ }
1236
1269
  const preCommitHook = join9(gitHooksDir, "pre-commit");
1237
1270
  const hookContent = `#!/bin/sh
1238
1271
  #
@@ -1558,13 +1591,437 @@ type: ${type}
1558
1591
  }
1559
1592
  });
1560
1593
 
1594
+ // src/core/sessions.ts
1595
+ var sessions_exports = {};
1596
+ __export(sessions_exports, {
1597
+ SessionManager: () => SessionManager,
1598
+ formatSession: () => formatSession
1599
+ });
1600
+ import { readFile as readFile7, writeFile as writeFile8, readdir as readdir7, mkdir as mkdir8 } from "fs/promises";
1601
+ import { join as join13 } from "path";
1602
+ import matter3 from "gray-matter";
1603
+ import { exec as exec2 } from "child_process";
1604
+ import { promisify as promisify2 } from "util";
1605
+ function formatSession(session) {
1606
+ const startDate = new Date(session.startTime);
1607
+ const endDate = session.endTime ? new Date(session.endTime) : null;
1608
+ return `
1609
+ ${session.id}
1610
+ Name: ${session.name}
1611
+ Status: ${session.status}
1612
+ Started: ${startDate.toLocaleString()}
1613
+ ${endDate ? `Ended: ${endDate.toLocaleString()}` : ""}
1614
+ Goals: ${session.goals.length}
1615
+ Updates: ${session.updates.length}
1616
+ `;
1617
+ }
1618
+ var execAsync2, SessionManager;
1619
+ var init_sessions = __esm({
1620
+ "src/core/sessions.ts"() {
1621
+ "use strict";
1622
+ init_esm_shims();
1623
+ execAsync2 = promisify2(exec2);
1624
+ SessionManager = class {
1625
+ sessionsDir;
1626
+ projectPath;
1627
+ constructor(projectPath) {
1628
+ this.projectPath = projectPath || process.cwd();
1629
+ this.sessionsDir = join13(this.projectPath, ".aikit", "sessions");
1630
+ }
1631
+ /**
1632
+ * Initialize sessions directory
1633
+ */
1634
+ async init() {
1635
+ await mkdir8(this.sessionsDir, { recursive: true });
1636
+ }
1637
+ /**
1638
+ * Start a new session
1639
+ */
1640
+ async startSession(name, goals) {
1641
+ await this.init();
1642
+ const now = /* @__PURE__ */ new Date();
1643
+ const date = now.toISOString().split("T")[0].replace(/-/g, "");
1644
+ const time = now.toTimeString().split(" ")[0].replace(/:/g, "");
1645
+ const nameSuffix = name ? `-${name.replace(/\s+/g, "-").toLowerCase()}` : "";
1646
+ const id = `${date}-${time}${nameSuffix}`;
1647
+ const session = {
1648
+ id,
1649
+ name: name || "Untitled Session",
1650
+ startTime: now.toISOString(),
1651
+ goals: goals || [],
1652
+ updates: [],
1653
+ status: "active"
1654
+ };
1655
+ const gitState = await this.getGitState();
1656
+ session.updates.push({
1657
+ timestamp: now.toISOString(),
1658
+ notes: name ? `Started session: ${name}` : "Started new session",
1659
+ gitBranch: gitState.branch,
1660
+ gitCommits: 0
1661
+ });
1662
+ await this.saveSession(session);
1663
+ await this.setActiveSession(id);
1664
+ return session;
1665
+ }
1666
+ /**
1667
+ * Update current session with notes
1668
+ */
1669
+ async updateSession(notes) {
1670
+ const sessionId = await this.getActiveSessionId();
1671
+ if (!sessionId) {
1672
+ throw new Error("No active session. Use startSession() first.");
1673
+ }
1674
+ const session = await this.getSession(sessionId);
1675
+ if (!session) {
1676
+ throw new Error(`Session not found: ${sessionId}`);
1677
+ }
1678
+ const gitState = await this.getGitState();
1679
+ const modifiedFiles = await this.getModifiedFiles();
1680
+ const update = {
1681
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1682
+ notes: notes || "Session updated",
1683
+ gitBranch: gitState.branch,
1684
+ gitCommits: gitState.commits || 0,
1685
+ modifiedFiles
1686
+ };
1687
+ const beadsTask = await this.getCurrentBeadsTask();
1688
+ if (beadsTask) {
1689
+ update.beadsTask = beadsTask;
1690
+ }
1691
+ session.updates.push(update);
1692
+ await this.saveSession(session);
1693
+ return session;
1694
+ }
1695
+ /**
1696
+ * End current session and generate summary
1697
+ */
1698
+ async endSession() {
1699
+ const sessionId = await this.getActiveSessionId();
1700
+ if (!sessionId) {
1701
+ throw new Error("No active session. Use startSession() first.");
1702
+ }
1703
+ const session = await this.getSession(sessionId);
1704
+ if (!session) {
1705
+ throw new Error(`Session not found: ${sessionId}`);
1706
+ }
1707
+ session.endTime = (/* @__PURE__ */ new Date()).toISOString();
1708
+ session.status = "ended";
1709
+ const gitState = await this.getGitState();
1710
+ const modifiedFiles = await this.getModifiedFiles();
1711
+ session.updates.push({
1712
+ timestamp: session.endTime,
1713
+ notes: "Session ended",
1714
+ gitBranch: gitState.branch,
1715
+ gitCommits: gitState.commits || 0,
1716
+ modifiedFiles
1717
+ });
1718
+ await this.saveSession(session);
1719
+ await this.clearActiveSession();
1720
+ return session;
1721
+ }
1722
+ /**
1723
+ * Get current active session
1724
+ */
1725
+ async getCurrentSession() {
1726
+ const sessionId = await this.getActiveSessionId();
1727
+ if (!sessionId) return null;
1728
+ return this.getSession(sessionId);
1729
+ }
1730
+ /**
1731
+ * Get all sessions
1732
+ */
1733
+ async listSessions() {
1734
+ try {
1735
+ const files = await readdir7(this.sessionsDir);
1736
+ const sessions = [];
1737
+ for (const file of files) {
1738
+ if (file === ".current-session" || !file.endsWith(".md")) continue;
1739
+ const sessionId = file.replace(".md", "");
1740
+ const session = await this.getSession(sessionId);
1741
+ if (session) {
1742
+ sessions.push(session);
1743
+ }
1744
+ }
1745
+ return sessions.sort(
1746
+ (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
1747
+ );
1748
+ } catch {
1749
+ return [];
1750
+ }
1751
+ }
1752
+ /**
1753
+ * Get specific session
1754
+ */
1755
+ async getSession(id) {
1756
+ const filePath = join13(this.sessionsDir, `${id}.md`);
1757
+ try {
1758
+ const content = await readFile7(filePath, "utf-8");
1759
+ const { data, content: body } = matter3(content);
1760
+ const updates = this.parseUpdates(body);
1761
+ return {
1762
+ id: data.id || id,
1763
+ name: data.name || "Untitled",
1764
+ startTime: data.startTime,
1765
+ endTime: data.endTime,
1766
+ goals: data.goals || [],
1767
+ updates,
1768
+ status: data.status || "active"
1769
+ };
1770
+ } catch {
1771
+ return null;
1772
+ }
1773
+ }
1774
+ /**
1775
+ * Search sessions by keyword
1776
+ */
1777
+ async searchSessions(query) {
1778
+ const sessions = await this.listSessions();
1779
+ const lowerQuery = query.toLowerCase();
1780
+ return sessions.filter(
1781
+ (session) => session.name.toLowerCase().includes(lowerQuery) || session.id.toLowerCase().includes(lowerQuery) || session.goals.some((g) => g.toLowerCase().includes(lowerQuery)) || session.updates.some((u) => u.notes?.toLowerCase().includes(lowerQuery))
1782
+ );
1783
+ }
1784
+ /**
1785
+ * Get active session ID
1786
+ */
1787
+ async getActiveSessionId() {
1788
+ const trackerPath = join13(this.sessionsDir, ".current-session");
1789
+ try {
1790
+ const content = await readFile7(trackerPath, "utf-8");
1791
+ return content.trim();
1792
+ } catch {
1793
+ return null;
1794
+ }
1795
+ }
1796
+ /**
1797
+ * Set active session
1798
+ */
1799
+ async setActiveSession(id) {
1800
+ const trackerPath = join13(this.sessionsDir, ".current-session");
1801
+ await writeFile8(trackerPath, id);
1802
+ }
1803
+ /**
1804
+ * Clear active session
1805
+ */
1806
+ async clearActiveSession() {
1807
+ const trackerPath = join13(this.sessionsDir, ".current-session");
1808
+ try {
1809
+ await writeFile8(trackerPath, "");
1810
+ } catch {
1811
+ }
1812
+ }
1813
+ /**
1814
+ * Save session to file
1815
+ */
1816
+ async saveSession(session) {
1817
+ const filePath = join13(this.sessionsDir, `${session.id}.md`);
1818
+ const updatesMarkdown = session.updates.map((update) => {
1819
+ const date = new Date(update.timestamp);
1820
+ const dateStr = date.toLocaleString();
1821
+ const sections = [`### ${dateStr}`];
1822
+ if (update.notes) {
1823
+ sections.push(update.notes);
1824
+ }
1825
+ if (update.gitBranch) {
1826
+ sections.push(`**Git Branch:** ${update.gitBranch}`);
1827
+ }
1828
+ if (update.modifiedFiles && update.modifiedFiles.length > 0) {
1829
+ sections.push(
1830
+ `**Modified Files:** ${update.modifiedFiles.length} files`,
1831
+ update.modifiedFiles.map((f) => ` - ${f}`).join("\n")
1832
+ );
1833
+ }
1834
+ if (update.beadsTask) {
1835
+ sections.push(`**Beads Task:** ${update.beadsTask.id} (${update.beadsTask.status})`);
1836
+ }
1837
+ return sections.join("\n");
1838
+ }).join("\n\n");
1839
+ const frontmatter = {
1840
+ id: session.id,
1841
+ name: session.name,
1842
+ startTime: session.startTime,
1843
+ status: session.status,
1844
+ goals: session.goals
1845
+ };
1846
+ if (session.endTime) {
1847
+ frontmatter.endTime = session.endTime;
1848
+ }
1849
+ const content = `# Development Session - ${session.name}
1850
+
1851
+ **Started:** ${new Date(session.startTime).toLocaleString()}
1852
+ **Status:** ${session.status}
1853
+ ${session.endTime ? `**Ended:** ${new Date(session.endTime).toLocaleString()}` : ""}
1854
+
1855
+ ## Goals
1856
+ ${session.goals.map((g, i) => `- [ ] ${g}`).join("\n")}
1857
+
1858
+ ## Progress
1859
+
1860
+ ${updatesMarkdown}
1861
+
1862
+ ## Summary
1863
+ ${this.generateSummary(session)}
1864
+ `;
1865
+ const fileContent = matter3.stringify(content, frontmatter);
1866
+ await writeFile8(filePath, fileContent);
1867
+ }
1868
+ /**
1869
+ * Generate session summary
1870
+ */
1871
+ generateSummary(session) {
1872
+ if (session.status === "active") {
1873
+ return "*Session in progress...*";
1874
+ }
1875
+ const duration = session.endTime ? new Date(session.endTime).getTime() - new Date(session.startTime).getTime() : 0;
1876
+ const durationMinutes = Math.floor(duration / 6e4);
1877
+ const hours = Math.floor(durationMinutes / 60);
1878
+ const minutes = durationMinutes % 60;
1879
+ let summary = `**Duration:** ${hours}h ${minutes}m
1880
+
1881
+ `;
1882
+ const totalGoals = session.goals.length;
1883
+ summary += `**Goals:** ${totalGoals} defined
1884
+
1885
+ `;
1886
+ summary += `**Updates:** ${session.updates.length} progress notes
1887
+
1888
+ `;
1889
+ const lastUpdate = session.updates[session.updates.length - 1];
1890
+ if (lastUpdate?.gitCommits !== void 0) {
1891
+ summary += `**Git Commits:** ${lastUpdate.gitCommits} commits
1892
+
1893
+ `;
1894
+ }
1895
+ if (lastUpdate?.modifiedFiles && lastUpdate.modifiedFiles.length > 0) {
1896
+ summary += `**Files Modified:** ${lastUpdate.modifiedFiles.length} files
1897
+
1898
+ `;
1899
+ }
1900
+ summary += `**Total Updates:** ${session.updates.length}`;
1901
+ return summary;
1902
+ }
1903
+ /**
1904
+ * Parse updates from markdown body
1905
+ */
1906
+ parseUpdates(body) {
1907
+ const updates = [];
1908
+ const lines = body.split("\n");
1909
+ let currentUpdate = null;
1910
+ let notesLines = [];
1911
+ for (const line of lines) {
1912
+ const updateMatch = line.match(/^### (\d{4}-\d{2}-\d{2} \d{2}:\d{2})/);
1913
+ if (updateMatch) {
1914
+ if (currentUpdate) {
1915
+ currentUpdate.notes = notesLines.join("\n").trim();
1916
+ updates.push(currentUpdate);
1917
+ }
1918
+ currentUpdate = {
1919
+ timestamp: updateMatch[1]
1920
+ };
1921
+ notesLines = [];
1922
+ continue;
1923
+ }
1924
+ if (!currentUpdate) continue;
1925
+ const gitBranchMatch = line.match(/\*\*Git Branch:\*\* (.+)/);
1926
+ if (gitBranchMatch) {
1927
+ currentUpdate.gitBranch = gitBranchMatch[1];
1928
+ continue;
1929
+ }
1930
+ const commitsMatch = line.match(/\*\*Git Commits:\*\* (\d+)/);
1931
+ if (commitsMatch) {
1932
+ currentUpdate.gitCommits = parseInt(commitsMatch[1], 10);
1933
+ continue;
1934
+ }
1935
+ if (line.includes("**Modified Files:**")) {
1936
+ continue;
1937
+ }
1938
+ if (line.trim().startsWith("- ") && currentUpdate) {
1939
+ if (!currentUpdate.modifiedFiles) {
1940
+ currentUpdate.modifiedFiles = [];
1941
+ }
1942
+ currentUpdate.modifiedFiles.push(line.trim().substring(2));
1943
+ continue;
1944
+ }
1945
+ const beadsMatch = line.match(/\*\*Beads Task:\*\* ([\w-]+) \((\w+)\)/);
1946
+ if (beadsMatch) {
1947
+ currentUpdate.beadsTask = {
1948
+ id: beadsMatch[1],
1949
+ status: beadsMatch[2]
1950
+ };
1951
+ continue;
1952
+ }
1953
+ if (!line.startsWith("**") && !line.startsWith("#")) {
1954
+ notesLines.push(line);
1955
+ }
1956
+ }
1957
+ if (currentUpdate) {
1958
+ currentUpdate.notes = notesLines.join("\n").trim();
1959
+ updates.push(currentUpdate);
1960
+ }
1961
+ return updates;
1962
+ }
1963
+ /**
1964
+ * Get git state
1965
+ */
1966
+ async getGitState() {
1967
+ try {
1968
+ const { stdout: branch } = await execAsync2("git rev-parse --abbrev-ref HEAD");
1969
+ const { stdout: log } = await execAsync2("git log --oneline | wc -l");
1970
+ return {
1971
+ branch: branch.trim(),
1972
+ commits: parseInt(log.trim(), 10)
1973
+ };
1974
+ } catch {
1975
+ return { branch: "main" };
1976
+ }
1977
+ }
1978
+ /**
1979
+ * Get modified files
1980
+ */
1981
+ async getModifiedFiles() {
1982
+ try {
1983
+ const { stdout } = await execAsync2("git status --porcelain");
1984
+ const lines = stdout.trim().split("\n");
1985
+ return lines.filter((line) => line.trim()).map((line) => line.substring(3));
1986
+ } catch {
1987
+ return [];
1988
+ }
1989
+ }
1990
+ /**
1991
+ * Get current Beads task
1992
+ */
1993
+ async getCurrentBeadsTask() {
1994
+ const beadsDir = join13(this.projectPath, ".beads");
1995
+ try {
1996
+ const files = await readdir7(beadsDir);
1997
+ const beadFiles = files.filter((f) => f.startsWith("bead-") && f.endsWith(".md"));
1998
+ for (const file of beadFiles) {
1999
+ const content = await readFile7(join13(beadsDir, file), "utf-8");
2000
+ const statusMatch = content.match(/^status:\s*(\w+)/m);
2001
+ const id = file.replace(".md", "");
2002
+ if (statusMatch && (statusMatch[1] === "in-progress" || statusMatch[1] === "todo")) {
2003
+ return {
2004
+ id,
2005
+ status: statusMatch[1]
2006
+ };
2007
+ }
2008
+ }
2009
+ return null;
2010
+ } catch {
2011
+ return null;
2012
+ }
2013
+ }
2014
+ };
2015
+ }
2016
+ });
2017
+
1561
2018
  // src/core/tool-config.ts
1562
2019
  var tool_config_exports = {};
1563
2020
  __export(tool_config_exports, {
1564
2021
  ToolConfigManager: () => ToolConfigManager
1565
2022
  });
1566
- import { readFile as readFile12, writeFile as writeFile13, mkdir as mkdir11, access as access5, constants as constants4 } from "fs/promises";
1567
- import { join as join18 } from "path";
2023
+ import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir14, access as access7, constants as constants4 } from "fs/promises";
2024
+ import { join as join21 } from "path";
1568
2025
  import { z as z3 } from "zod";
1569
2026
  var ToolConfigSchema, REGISTERED_TOOLS, ToolConfigManager;
1570
2027
  var init_tool_config = __esm({
@@ -1592,7 +2049,7 @@ var init_tool_config = __esm({
1592
2049
  toolsConfigPath;
1593
2050
  constructor(config) {
1594
2051
  this.config = config;
1595
- this.toolsConfigPath = join18(this.config.configPath, "config", "tools.json");
2052
+ this.toolsConfigPath = join21(this.config.configPath, "config", "tools.json");
1596
2053
  }
1597
2054
  /**
1598
2055
  * Get all registered tools with their current status
@@ -1675,8 +2132,8 @@ var init_tool_config = __esm({
1675
2132
  */
1676
2133
  async loadConfigs() {
1677
2134
  try {
1678
- await access5(this.toolsConfigPath, constants4.R_OK);
1679
- const content = await readFile12(this.toolsConfigPath, "utf-8");
2135
+ await access7(this.toolsConfigPath, constants4.R_OK);
2136
+ const content = await readFile14(this.toolsConfigPath, "utf-8");
1680
2137
  return JSON.parse(content);
1681
2138
  } catch {
1682
2139
  return {};
@@ -1686,9 +2143,9 @@ var init_tool_config = __esm({
1686
2143
  * Save configurations
1687
2144
  */
1688
2145
  async saveConfigs(configs) {
1689
- const configDir = join18(this.config.configPath, "config");
1690
- await mkdir11(configDir, { recursive: true });
1691
- await writeFile13(this.toolsConfigPath, JSON.stringify(configs, null, 2));
2146
+ const configDir = join21(this.config.configPath, "config");
2147
+ await mkdir14(configDir, { recursive: true });
2148
+ await writeFile16(this.toolsConfigPath, JSON.stringify(configs, null, 2));
1692
2149
  }
1693
2150
  };
1694
2151
  }
@@ -1735,8 +2192,8 @@ var init_figma_oauth = __esm({
1735
2192
  console.log('3. Give it a name (e.g., "AIKit")');
1736
2193
  console.log("4. Copy the token (you won't see it again!)");
1737
2194
  console.log("5. Paste it here when prompted\n");
1738
- const { default: inquirer3 } = await import("inquirer");
1739
- const { token } = await inquirer3.prompt([
2195
+ const { default: inquirer4 } = await import("inquirer");
2196
+ const { token } = await inquirer4.prompt([
1740
2197
  {
1741
2198
  type: "password",
1742
2199
  name: "token",
@@ -1766,14 +2223,14 @@ var init_figma_oauth = __esm({
1766
2223
  * Alternative: Manual token input
1767
2224
  */
1768
2225
  async authenticateManual() {
1769
- const { default: inquirer3 } = await import("inquirer");
2226
+ const { default: inquirer4 } = await import("inquirer");
1770
2227
  console.log("\n\u{1F510} Figma Authentication (Manual)\n");
1771
2228
  console.log("To get your Figma Personal Access Token:");
1772
2229
  console.log("1. Visit: https://www.figma.com/developers/api#access-tokens");
1773
2230
  console.log('2. Scroll to "Personal access tokens"');
1774
2231
  console.log('3. Click "Create new token"');
1775
2232
  console.log("4. Copy the token and paste it below\n");
1776
- const { token } = await inquirer3.prompt([
2233
+ const { token } = await inquirer4.prompt([
1777
2234
  {
1778
2235
  type: "password",
1779
2236
  name: "token",
@@ -1828,7 +2285,7 @@ init_esm_shims();
1828
2285
 
1829
2286
  // src/cli/index.ts
1830
2287
  init_esm_shims();
1831
- import { Command } from "commander";
2288
+ import { Command as Command3 } from "commander";
1832
2289
 
1833
2290
  // src/index.ts
1834
2291
  init_esm_shims();
@@ -2403,12 +2860,20 @@ ${agent.delegatesTo.map((a) => `- @${a}`).join("\n")}` : ""}
2403
2860
 
2404
2861
  // src/core/commands.ts
2405
2862
  init_esm_shims();
2863
+
2864
+ // src/core/commands/index.ts
2865
+ init_esm_shims();
2406
2866
  init_paths();
2407
2867
  import { readFile as readFile3, readdir as readdir2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2408
2868
  import { join as join5, basename as basename2, extname as extname2 } from "path";
2409
2869
  import matter2 from "gray-matter";
2410
- var DEFAULT_COMMANDS = [
2411
- // Core Workflow Commands (Beads integration)
2870
+
2871
+ // src/core/commands/types.ts
2872
+ init_esm_shims();
2873
+
2874
+ // src/core/commands/core.ts
2875
+ init_esm_shims();
2876
+ var CORE_COMMANDS = [
2412
2877
  {
2413
2878
  name: "create",
2414
2879
  description: "Create a new Beads task for tracking",
@@ -2660,8 +3125,12 @@ Task description: $ARGUMENTS
2660
3125
  \u2713 Use for straightforward tasks first
2661
3126
  \u2713 Consider /plan + /implement for complex features
2662
3127
  \u2713 Review changes before final approval`
2663
- },
2664
- // Quick Actions
3128
+ }
3129
+ ];
3130
+
3131
+ // src/core/commands/quick.ts
3132
+ init_esm_shims();
3133
+ var QUICK_COMMANDS = [
2665
3134
  {
2666
3135
  name: "fix",
2667
3136
  description: "Quick fix for an issue",
@@ -2756,7 +3225,47 @@ Optional PR title: $ARGUMENTS
2756
3225
  - Screenshots if UI changes
2757
3226
  3. Create PR via GitHub CLI or provide URL`
2758
3227
  },
2759
- // Research & Analysis
3228
+ {
3229
+ name: "refactor",
3230
+ description: "Refactor code to improve structure without changing behavior",
3231
+ category: "quick",
3232
+ usage: "/refactor [file or pattern]",
3233
+ examples: ["/refactor src/utils.ts", "/refactor duplicate code"],
3234
+ content: `Refactor code following best practices.
3235
+
3236
+ ## Workflow
3237
+
3238
+ Optional file or pattern: $ARGUMENTS
3239
+
3240
+ 1. Ensure tests are in place
3241
+ 2. Identify refactoring opportunities
3242
+ 3. Apply refactoring incrementally
3243
+ 4. Run tests after each change
3244
+ 5. Verify no behavior changes`
3245
+ },
3246
+ {
3247
+ name: "lint",
3248
+ description: "Run linter and fix issues",
3249
+ category: "quick",
3250
+ usage: "/lint [--fix]",
3251
+ examples: ["/lint", "/lint --fix"],
3252
+ content: `Run linter and optionally fix issues.
3253
+
3254
+ ## Workflow
3255
+
3256
+ Optional flags: $ARGUMENTS
3257
+
3258
+ 1. Run linter: \`npm run lint\`
3259
+ 2. Parse errors and warnings
3260
+ 3. If --fix flag, run auto-fix
3261
+ 4. Report remaining issues
3262
+ 5. Suggest manual fixes if needed`
3263
+ }
3264
+ ];
3265
+
3266
+ // src/core/commands/research.ts
3267
+ init_esm_shims();
3268
+ var RESEARCH_COMMANDS = [
2760
3269
  {
2761
3270
  name: "research",
2762
3271
  description: "Deep research on a topic",
@@ -2817,8 +3326,12 @@ Optional path: $ARGUMENTS
2817
3326
  - Test coverage gaps
2818
3327
  3. Prioritize findings
2819
3328
  4. Suggest improvements`
2820
- },
2821
- // Design & Planning
3329
+ }
3330
+ ];
3331
+
3332
+ // src/core/commands/design.ts
3333
+ init_esm_shims();
3334
+ var DESIGN_COMMANDS = [
2822
3335
  {
2823
3336
  name: "design",
2824
3337
  description: "Design a feature or system",
@@ -2861,90 +3374,20 @@ Problem to brainstorm: $ARGUMENTS
2861
3374
  4. Evaluate feasibility
2862
3375
  5. Select top candidates`
2863
3376
  },
2864
- // Git & Version Control
2865
3377
  {
2866
- name: "branch",
2867
- description: "Create a new feature branch",
2868
- category: "git",
2869
- usage: "/branch <name>",
2870
- examples: ["/branch feat/auth", "/branch fix/navigation-bug"],
2871
- content: `Create and switch to a new branch.
3378
+ name: "analyze-figma",
3379
+ description: "Analyze Figma design and extract design tokens using Figma API",
3380
+ category: "design",
3381
+ usage: "/analyze-figma <figma-url>",
3382
+ examples: [
3383
+ "/analyze-figma https://www.figma.com/design/...",
3384
+ "/analyze-figma [figma-url]"
3385
+ ],
3386
+ content: `Analyze a Figma design and extract all design tokens automatically using Figma API.
2872
3387
 
2873
3388
  ## Workflow
2874
3389
 
2875
- Branch name: $ARGUMENTS
2876
-
2877
- 1. Ensure clean working directory
2878
- 2. Pull latest main/master
2879
- 3. Create branch with naming convention:
2880
- - feat/* for features
2881
- - fix/* for bug fixes
2882
- - refactor/* for refactoring
2883
- - docs/* for documentation
2884
- 4. Switch to new branch`
2885
- },
2886
- {
2887
- name: "merge",
2888
- description: "Merge current branch to target",
2889
- category: "git",
2890
- usage: "/merge [target]",
2891
- examples: ["/merge", "/merge main"],
2892
- content: `Merge current branch to target.
2893
-
2894
- ## Workflow
2895
-
2896
- Optional target branch: $ARGUMENTS
2897
-
2898
- 1. Run quality gates first
2899
- 2. Commit any pending changes
2900
- 3. Switch to target branch
2901
- 4. Pull latest
2902
- 5. Merge feature branch
2903
- 6. Resolve conflicts if any
2904
- 7. Push`
2905
- },
2906
- // Utilities
2907
- {
2908
- name: "status",
2909
- description: "Show current status overview",
2910
- category: "utility",
2911
- usage: "/status",
2912
- examples: ["/status"],
2913
- content: `Display comprehensive status.
2914
-
2915
- ## Shows
2916
- - Current task (from Beads)
2917
- - Git status
2918
- - Active branch
2919
- - Pending changes
2920
- - Test status
2921
- - Recent activity`
2922
- },
2923
- {
2924
- name: "help",
2925
- description: "Show available commands",
2926
- category: "utility",
2927
- usage: "/help [command]",
2928
- examples: ["/help", "/help plan"],
2929
- content: `Display help information.
2930
-
2931
- If no command specified, list all available commands.
2932
- If command specified, show detailed help for that command.`
2933
- },
2934
- {
2935
- name: "analyze-figma",
2936
- description: "Analyze Figma design and extract design tokens using Figma API",
2937
- category: "design",
2938
- usage: "/analyze-figma <figma-url>",
2939
- examples: [
2940
- "/analyze-figma https://www.figma.com/design/...",
2941
- "/analyze-figma [figma-url]"
2942
- ],
2943
- content: `Analyze a Figma design and extract all design tokens automatically using Figma API.
2944
-
2945
- ## Workflow
2946
-
2947
- **Step 1: Extract URL from User Input**
3390
+ **Step 1: Extract URL from User Input**
2948
3391
 
2949
3392
  The Figma URL is provided in the SAME message as the command. Extract it:
2950
3393
  - Check the full user input message
@@ -3075,24 +3518,179 @@ Summarize what was extracted:
3075
3518
  - If the tool returns an error about access, verify the file is accessible with your token
3076
3519
 
3077
3520
  The analysis will be saved automatically for later reference.`
3521
+ }
3522
+ ];
3523
+
3524
+ // src/core/commands/git.ts
3525
+ init_esm_shims();
3526
+ var GIT_COMMANDS = [
3527
+ {
3528
+ name: "branch",
3529
+ description: "Create a new feature branch",
3530
+ category: "git",
3531
+ usage: "/branch <name>",
3532
+ examples: ["/branch feat/auth", "/branch fix/navigation-bug"],
3533
+ content: `Create and switch to a new branch.
3534
+
3535
+ ## Workflow
3536
+
3537
+ Branch name: $ARGUMENTS
3538
+
3539
+ 1. Ensure clean working directory
3540
+ 2. Pull latest main/master
3541
+ 3. Create branch with naming convention:
3542
+ - feat/* for features
3543
+ - fix/* for bug fixes
3544
+ - refactor/* for refactoring
3545
+ - docs/* for documentation
3546
+ 4. Switch to new branch`
3078
3547
  },
3079
3548
  {
3080
- name: "refactor",
3081
- description: "Refactor code to improve structure without changing behavior",
3082
- category: "quick",
3083
- usage: "/refactor [file or pattern]",
3084
- examples: ["/refactor src/utils.ts", "/refactor duplicate code"],
3085
- content: `Refactor code following best practices.
3549
+ name: "merge",
3550
+ description: "Merge current branch to target",
3551
+ category: "git",
3552
+ usage: "/merge [target]",
3553
+ examples: ["/merge", "/merge main"],
3554
+ content: `Merge current branch to target.
3086
3555
 
3087
3556
  ## Workflow
3088
3557
 
3089
- Optional file or pattern: $ARGUMENTS
3558
+ Optional target branch: $ARGUMENTS
3090
3559
 
3091
- 1. Ensure tests are in place
3092
- 2. Identify refactoring opportunities
3093
- 3. Apply refactoring incrementally
3094
- 4. Run tests after each change
3095
- 5. Verify no behavior changes`
3560
+ 1. Run quality gates first
3561
+ 2. Commit any pending changes
3562
+ 3. Switch to target branch
3563
+ 4. Pull latest
3564
+ 5. Merge feature branch
3565
+ 6. Resolve conflicts if any
3566
+ 7. Push`
3567
+ },
3568
+ {
3569
+ name: "git:ignore-init",
3570
+ description: "Initialize AI-safe .gitignore patterns",
3571
+ category: "git",
3572
+ usage: "/git:ignore-init",
3573
+ examples: ["/git:ignore-init"],
3574
+ content: `Initialize AI-safe .gitignore patterns to prevent AI from accessing sensitive files.
3575
+
3576
+ ## Workflow
3577
+
3578
+ 1. **Check Existing .gitignore**: See if .gitignore exists
3579
+ 2. **Backup**: Create .gitignore.backup if file exists
3580
+ 3. **Append Patterns**: Add AI-specific ignore patterns
3581
+ 4. **Verify**: Confirm patterns added successfully
3582
+
3583
+ ## Patterns Added
3584
+
3585
+ **AI-Sensitive Files:**
3586
+ \`\`\`
3587
+ # AIKit - AI Agent Protection
3588
+ .env
3589
+ .env.local
3590
+ .env.*.local
3591
+ *.key
3592
+ *.pem
3593
+ secrets/
3594
+ credentials/
3595
+ .aws/
3596
+ .ssh/
3597
+ config/secrets.json
3598
+
3599
+ # AI Working Directories
3600
+ .aikit/memory/
3601
+ .aikit/checkpoints/
3602
+ .aikit/sessions/
3603
+
3604
+ # Claude Code
3605
+ .claude/settings.json
3606
+ .claude/local_history.json
3607
+
3608
+ # OpenCode
3609
+ .opencode/config.json
3610
+ .opencode/state.json
3611
+
3612
+ # Agent-Specific
3613
+ .agentignore
3614
+ .aiignore
3615
+
3616
+ # Logs and Debug
3617
+ *.log
3618
+ logs/
3619
+ debug.log
3620
+ npm-debug.log*
3621
+ yarn-debug.log*
3622
+ yarn-error.log*
3623
+
3624
+ # Temporary Files
3625
+ *.tmp
3626
+ *.temp
3627
+ .cache/
3628
+ temp/
3629
+ tmp/
3630
+ \`\`\`
3631
+
3632
+ **Explanation of Each Pattern:**
3633
+ - **Credentials**: API keys, tokens, certificates
3634
+ - **Config**: Sensitive configuration files
3635
+ - **Memory**: AI conversation history and context
3636
+ - **Sessions**: Active AI session data
3637
+ - **Logs**: Debug and error logs
3638
+ - **Temp**: Temporary processing files
3639
+
3640
+ **Why These Patterns?**
3641
+ - Prevent AI from reading API keys and secrets
3642
+ - Avoid exposing sensitive user data
3643
+ - Reduce AI context noise (logs, cache)
3644
+ - Protect privacy
3645
+ - Comply with security best practices
3646
+
3647
+ ## Verification
3648
+
3649
+ **After Running Command:**
3650
+ \`\`\`
3651
+ \u2713 AI-safe patterns added to .gitignore
3652
+ \u2713 Backup created: .gitignore.backup
3653
+ \u2713 Protected: API keys, secrets, memory, logs
3654
+ \u2713 Safe to commit code
3655
+ \`\`\`
3656
+
3657
+ ## Notes
3658
+ - Patterns appended to existing .gitignore
3659
+ - Doesn't remove existing patterns
3660
+ - Can be manually customized after creation
3661
+ - Recommend reviewing before committing`
3662
+ }
3663
+ ];
3664
+
3665
+ // src/core/commands/utility.ts
3666
+ init_esm_shims();
3667
+ var UTILITY_COMMANDS = [
3668
+ {
3669
+ name: "status",
3670
+ description: "Show current status overview",
3671
+ category: "utility",
3672
+ usage: "/status",
3673
+ examples: ["/status"],
3674
+ content: `Display comprehensive status.
3675
+
3676
+ ## Shows
3677
+ - Current task (from Beads)
3678
+ - Git status
3679
+ - Active branch
3680
+ - Pending changes
3681
+ - Test status
3682
+ - Recent activity`
3683
+ },
3684
+ {
3685
+ name: "help",
3686
+ description: "Show available commands",
3687
+ category: "utility",
3688
+ usage: "/help [command]",
3689
+ examples: ["/help", "/help plan"],
3690
+ content: `Display help information.
3691
+
3692
+ If no command specified, list all available commands.
3693
+ If command specified, show detailed help for that command.`
3096
3694
  },
3097
3695
  {
3098
3696
  name: "test",
@@ -3111,24 +3709,6 @@ Optional pattern: $ARGUMENTS
3111
3709
  3. Show coverage if available
3112
3710
  4. Highlight failures
3113
3711
  5. Suggest fixes for failures`
3114
- },
3115
- {
3116
- name: "lint",
3117
- description: "Run linter and fix issues",
3118
- category: "quick",
3119
- usage: "/lint [--fix]",
3120
- examples: ["/lint", "/lint --fix"],
3121
- content: `Run linter and optionally fix issues.
3122
-
3123
- ## Workflow
3124
-
3125
- Optional flags: $ARGUMENTS
3126
-
3127
- 1. Run linter: \`npm run lint\`
3128
- 2. Parse errors and warnings
3129
- 3. If --fix flag, run auto-fix
3130
- 4. Report remaining issues
3131
- 5. Suggest manual fixes if needed`
3132
3712
  },
3133
3713
  {
3134
3714
  name: "deploy",
@@ -3176,15 +3756,1196 @@ Optional version: $ARGUMENTS
3176
3756
 
3177
3757
  ## Workflow
3178
3758
 
3179
- Optional flags: $ARGUMENTS
3759
+ Optional flags: $ARGUMENTS
3760
+
3761
+ 1. Determine log location
3762
+ 2. Apply filters if specified
3763
+ 3. Display logs
3764
+ 4. If --follow, stream updates
3765
+ 5. Format for readability`
3766
+ },
3767
+ {
3768
+ name: "create-agent",
3769
+ description: "Create a custom AI agent with specific capabilities",
3770
+ category: "utility",
3771
+ usage: "/create-agent <name> [description]",
3772
+ examples: ['/create-agent security "Security audit agent"', "/create-agent writer"],
3773
+ content: `Create a custom AI agent for specialized tasks.
3774
+
3775
+ ## Workflow
3776
+
3777
+ Agent name: $ARGUMENTS
3778
+
3779
+ 1. **Determine Agent Purpose**: Ask user clarifying questions:
3780
+ - What specific tasks will this agent handle?
3781
+ - What expertise should it have?
3782
+ - What tools should it have access to?
3783
+ - Any specific behaviors or constraints?
3784
+
3785
+ 2. **Generate Agent Configuration**:
3786
+ - System prompt with instructions
3787
+ - Recommended tools/skills
3788
+ - Preferred models
3789
+ - Interaction patterns
3790
+
3791
+ 3. **Create Agent File**: Save to .aikit/agents/<name>.md
3792
+ - Frontmatter with metadata
3793
+ - System prompt
3794
+ - Tool recommendations
3795
+ - Usage examples
3796
+
3797
+ 4. **Verify Creation**: Confirm agent created successfully
3798
+
3799
+ ## Agent Template
3800
+
3801
+ **Frontmatter:**
3802
+ \`\`\`yaml
3803
+ ---
3804
+ name: <agent-name>
3805
+ description: <what this agent does>
3806
+ useWhen: <when to use this agent>
3807
+ mode: subagent
3808
+ tools: [list of tools]
3809
+ skills: [list of skills]
3810
+ ---
3811
+ \`\`\`
3812
+
3813
+ **System Prompt:**
3814
+ \`\`\`
3815
+ # Agent Name
3816
+
3817
+ You are a specialized AI agent for <specific domain>.
3818
+
3819
+ ## Your Expertise
3820
+ - Expertise area 1
3821
+ - Expertise area 2
3822
+ - Expertise area 3
3823
+
3824
+ ## Your Role
3825
+ 1. Primary responsibility
3826
+ 2. Secondary tasks
3827
+ 3. Collaboration with other agents
3828
+
3829
+ ## Guidelines
3830
+ - How to approach tasks
3831
+ - What to focus on
3832
+ - What to avoid
3833
+
3834
+ ## Tools You Have Access To
3835
+ - Tool 1: description
3836
+ - Tool 2: description
3837
+
3838
+ ## Output Format
3839
+ - Preferred response format
3840
+ - Code style (if applicable)
3841
+ - Explanation style
3842
+ \`\`\`
3843
+
3844
+ ## Example Agents
3845
+
3846
+ **Security Agent:**
3847
+ - Focuses on code security vulnerabilities
3848
+ - Tools: static analysis, dependency checker
3849
+ - Skills: security-audit, code-review
3850
+
3851
+ **Performance Agent:**
3852
+ - Focuses on optimization
3853
+ - Tools: profiler, benchmark
3854
+ - Skills: performance-optimization
3855
+
3856
+ **Documentation Agent:**
3857
+ - Focuses on writing clear docs
3858
+ - Tools: markdown formatter
3859
+ - Skills: documentation
3860
+
3861
+ ## Notes
3862
+ - Agents are saved as markdown files
3863
+ - Can be customized after creation
3864
+ - Used with /agent or agent delegation
3865
+ - Appear in agent selector in OpenCode`
3866
+ },
3867
+ {
3868
+ name: "list-agents",
3869
+ description: "List all available custom agents",
3870
+ category: "utility",
3871
+ usage: "/list-agents",
3872
+ examples: ["/list-agents"],
3873
+ content: `List all available custom agents with descriptions.
3874
+
3875
+ ## Workflow
3876
+
3877
+ 1. **Scan Agents Directory**: Find all agent files in .aikit/agents/
3878
+ 2. **Parse Metadata**: Extract agent descriptions and use cases
3879
+ 3. **Categorize**: Group by type/purpose
3880
+ 4. **Display**: Show formatted list with details
3881
+
3882
+ ## Output Format
3883
+
3884
+ \`\`\`
3885
+ Available Agents:
3886
+
3887
+ ### Development Agents
3888
+ \u2022 security - Security vulnerability scanner
3889
+ Use when: Reviewing code for security issues
3890
+ Skills: security-audit, code-review
3891
+ Tools: static-analysis, dependency-checker
3892
+
3893
+ \u2022 performance - Performance optimization specialist
3894
+ Use when: Optimizing slow code or databases
3895
+ Skills: performance-optimization, database-design
3896
+ Tools: profiler, query-analyzer
3897
+
3898
+ ### Documentation Agents
3899
+ \u2022 writer - Technical documentation writer
3900
+ Use when: Creating or updating docs
3901
+ Skills: documentation
3902
+ Tools: markdown-formatter
3903
+
3904
+ ### Design Agents
3905
+ \u2022 ui-ux - UI/UX design reviewer
3906
+ Use when: Reviewing interface designs
3907
+ Skills: accessibility, frontend-aesthetics
3908
+
3909
+ Total: 4 agents
3910
+
3911
+ Create a new agent: /create-agent <name>
3912
+ \`\`\`
3913
+
3914
+ ## Agent Information Shown
3915
+ - Agent name
3916
+ - Description
3917
+ - When to use it
3918
+ - Required skills
3919
+ - Available tools
3920
+ - Category/type
3921
+
3922
+ ## Notes
3923
+ - Built-in agents (plan, build, review, etc.) also shown
3924
+ - Custom agents appear after built-in ones
3925
+ - Use /agent <name> to invoke specific agent
3926
+ - Can view full agent file for details`
3927
+ }
3928
+ ];
3929
+
3930
+ // src/core/commands/checkpoint.ts
3931
+ init_esm_shims();
3932
+ var CHECKPOINT_COMMANDS = [
3933
+ {
3934
+ name: "checkpoint:create",
3935
+ description: "Save current state as a checkpoint",
3936
+ category: "checkpoint",
3937
+ usage: "/checkpoint:create [message]",
3938
+ examples: ["/checkpoint:create", '/checkpoint:create "Before refactoring"'],
3939
+ content: `Create a checkpoint of the current working state.
3940
+
3941
+ ## Workflow
3942
+
3943
+ Optional message: $ARGUMENTS
3944
+
3945
+ 1. **Check Git Status**: Verify clean or staged state
3946
+ 2. **Create Checkpoint**:
3947
+ - Generate checkpoint ID (timestamp-based)
3948
+ - Save git diff or uncommitted changes
3949
+ - Save current branch name
3950
+ - Save list of modified files
3951
+ - Save user's message (if provided)
3952
+ 3. **Store Checkpoint**: Save to .aikit/checkpoints/checkpoint-{id}.json
3953
+ 4. **Confirm**: Display checkpoint ID and summary
3954
+
3955
+ ## Checkpoint Contents
3956
+ - Timestamp
3957
+ - Git branch
3958
+ - Git commit hash (if any)
3959
+ - Uncommitted changes (diff)
3960
+ - Modified files list
3961
+ - User message
3962
+ - Beads task state (if active)
3963
+
3964
+ ## Example Output
3965
+ \`\`\`
3966
+ Checkpoint created: checkpoint-20250102-143022
3967
+ Message: Before refactoring
3968
+ Files modified: 5 files
3969
+ \`\`\`
3970
+
3971
+ ## Notes
3972
+ - Checkpoints are stored locally in .aikit/checkpoints/
3973
+ - Git changes are preserved (not committed)
3974
+ - Use for experimentation - safely restore if things go wrong
3975
+ - Checkpoints include full state, not just git`
3976
+ },
3977
+ {
3978
+ name: "checkpoint:restore",
3979
+ description: "Restore to a previous checkpoint",
3980
+ category: "checkpoint",
3981
+ usage: "/checkpoint:restore [checkpoint-id]",
3982
+ examples: ["/checkpoint:restore", "/checkpoint:restore checkpoint-20250102-143022", "/checkpoint:restore latest"],
3983
+ content: `Restore the project state from a checkpoint.
3984
+
3985
+ ## Workflow
3986
+
3987
+ Checkpoint ID: $ARGUMENTS (default: latest)
3988
+
3989
+ 1. **Find Checkpoint**:
3990
+ - If no ID provided, find latest checkpoint
3991
+ - Verify checkpoint file exists
3992
+ 2. **Display Summary**: Show what will be restored
3993
+ 3. **Confirm with User**: Ask for confirmation before proceeding
3994
+ 4. **Restore State**:
3995
+ - Clean working directory (remove uncommitted changes)
3996
+ - Checkout git commit from checkpoint
3997
+ - Apply uncommitted changes from checkpoint
3998
+ - Restore Beads task state if available
3999
+ 5. **Verify**: Confirm restoration successful
4000
+
4001
+ ## Safety Checks
4002
+ - Warn if current changes will be lost
4003
+ - Show diff between current and checkpoint
4004
+ - Require explicit user confirmation
4005
+ - Backup current state before restoring
4006
+
4007
+ ## Example Output
4008
+ \`\`\`
4009
+ Restoring checkpoint: checkpoint-20250102-143022
4010
+ Message: Before refactoring
4011
+ Files modified: 5 files
4012
+
4013
+ \u26A0\uFE0F Warning: Uncommitted changes will be lost
4014
+ Proceed? (yes/no)
4015
+
4016
+ \u2713 Restored successfully
4017
+ \`\`\`
4018
+
4019
+ ## Notes
4020
+ - Current uncommitted changes will be lost
4021
+ - Git history is preserved
4022
+ - Beads tasks will be restored to checkpointed state`
4023
+ },
4024
+ {
4025
+ name: "checkpoint:list",
4026
+ description: "List all available checkpoints",
4027
+ category: "checkpoint",
4028
+ usage: "/checkpoint:list",
4029
+ examples: ["/checkpoint:list"],
4030
+ content: `List all saved checkpoints with details.
4031
+
4032
+ ## Workflow
4033
+
4034
+ 1. **Scan Checkpoints Directory**: Find all checkpoint files in .aikit/checkpoints/
4035
+ 2. **Sort by Date**: Most recent first
4036
+ 3. **Display Summary**: Show table/list of checkpoints
4037
+
4038
+ ## Output Format
4039
+ \`\`\`
4040
+ Available Checkpoints:
4041
+
4042
+ 1. checkpoint-20250102-143022
4043
+ Date: 2025-01-02 14:30:22
4044
+ Message: Before refactoring
4045
+ Branch: feature/user-auth
4046
+ Files: 5 modified
4047
+ Size: 2.3MB
4048
+
4049
+ 2. checkpoint-20250102-120815
4050
+ Date: 2025-01-02 12:08:15
4051
+ Message: Initial implementation
4052
+ Branch: main
4053
+ Files: 12 modified
4054
+ Size: 5.1MB
4055
+
4056
+ Total: 2 checkpoints
4057
+ \`\`\`
4058
+
4059
+ ## Filtering Options (future)
4060
+ - Filter by branch
4061
+ - Filter by date range
4062
+ - Filter by message content
4063
+ - Show only checkpoints with specific files
4064
+
4065
+ ## Notes
4066
+ - Checkpoints are stored in .aikit/checkpoints/
4067
+ - Older checkpoints can be manually deleted
4068
+ - Use /checkpoint:restore <id> to restore
4069
+ - Use /checkpoint:restore latest for most recent`
4070
+ }
4071
+ ];
4072
+
4073
+ // src/core/commands/sessions.ts
4074
+ init_esm_shims();
4075
+ var SESSION_COMMANDS = [
4076
+ {
4077
+ name: "session:start",
4078
+ description: "Start a new development session",
4079
+ category: "session",
4080
+ usage: "/session:start [name]",
4081
+ examples: [
4082
+ "/session:start",
4083
+ "/session:start authentication-refactor",
4084
+ '/session:start "Add user profile feature"'
4085
+ ],
4086
+ content: `Start a new development session to track your work.
4087
+
4088
+ ## Workflow
4089
+
4090
+ Session name: $ARGUMENTS
4091
+
4092
+ 1. **Create Session:**
4093
+ - Generate session ID with timestamp
4094
+ - Create session file in .aikit/sessions/
4095
+ - Track active session in .current-session
4096
+ - Capture initial git state
4097
+
4098
+ 2. **Set Goals:**
4099
+ - Ask user for session goals if not provided
4100
+ - Document what you want to accomplish
4101
+ - Link to Beads task if active
4102
+
4103
+ 3. **Session Started:**
4104
+ - Session ID: YYYY-MM-DD-HHMM[-name]
4105
+ - Status: active
4106
+ - Ready for updates
4107
+
4108
+ ## What Gets Tracked
4109
+ - Session start time
4110
+ - Git branch and commits
4111
+ - Modified files
4112
+ - Progress notes
4113
+ - Linked Beads task
4114
+
4115
+ ## Session File Location
4116
+ .aikit/sessions/YYYY-MM-DD-HHMM[-name].md
4117
+
4118
+ ## Examples
4119
+
4120
+ Start unnamed session:
4121
+ \`\`\`
4122
+ /session:start
4123
+ \`\`\`
4124
+
4125
+ Start with descriptive name:
4126
+ \`\`\`
4127
+ /session:start auth-refactor
4128
+ \`\`\`
4129
+
4130
+ Start with goal:
4131
+ \`\`\`
4132
+ /session:start "Implement OAuth 2.0"
4133
+ Goals:
4134
+ - Add Google OAuth
4135
+ - Add JWT token handling
4136
+ \`\`\`
4137
+
4138
+ ## Notes
4139
+ - Session files are markdown with frontmatter
4140
+ - Sessions persist across AI conversations
4141
+ - Use /session:update to add progress notes
4142
+ - Use /session:end to close and summarize`
4143
+ },
4144
+ {
4145
+ name: "session:update",
4146
+ description: "Add progress notes to current session",
4147
+ category: "session",
4148
+ usage: "/session:update [notes]",
4149
+ examples: [
4150
+ "/session:update",
4151
+ "/session:update Fixed authentication bug",
4152
+ '/session:update "Added JWT middleware"'
4153
+ ],
4154
+ content: `Update the current session with progress notes.
4155
+
4156
+ ## Workflow
4157
+
4158
+ Progress notes: $ARGUMENTS
4159
+
4160
+ 1. **Check Active Session:**
4161
+ - Verify there's an active session
4162
+ - Load session file
4163
+
4164
+ 2. **Capture Current State:**
4165
+ - Get current git branch
4166
+ - Count git commits
4167
+ - List modified files
4168
+ - Check active Beads task
4169
+
4170
+ 3. **Add Update:**
4171
+ - Add timestamped update entry
4172
+ - Include your notes (or auto-generate)
4173
+ - Include git state
4174
+ - Include Beads task if active
4175
+
4176
+ 4. **Save Session:**
4177
+ - Update session file
4178
+ - Confirm update added
4179
+
4180
+ ## What Gets Captured
4181
+ - Timestamp of update
4182
+ - Your progress notes
4183
+ - Current git branch
4184
+ - Number of commits
4185
+ - List of modified files
4186
+ - Active Beads task (if any)
4187
+
4188
+ ## Examples
4189
+
4190
+ Auto-update (no notes):
4191
+ \`\`\`
4192
+ /session:update
4193
+ \`\`\`
4194
+ *Auto-generates summary of recent work*
4195
+
4196
+ With specific notes:
4197
+ \`\`\`
4198
+ /session:update Fixed Next.js params issue
4199
+ \`\`\`
4200
+
4201
+ With detailed notes:
4202
+ \`\`\`
4203
+ /session:update "Implemented OAuth flow with Google provider. Added callback handler and token validation."
4204
+ \`\`\`
4205
+
4206
+ ## Notes
4207
+ - Must have active session first
4208
+ - Updates are timestamped
4209
+ - Git state automatically captured
4210
+ - Beads task automatically linked`
4211
+ },
4212
+ {
4213
+ name: "session:end",
4214
+ description: "End current session with summary",
4215
+ category: "session",
4216
+ usage: "/session:end",
4217
+ examples: ["/session:end"],
4218
+ content: `End the current session and generate a comprehensive summary.
4219
+
4220
+ ## Workflow
4221
+
4222
+ 1. **Check Active Session:**
4223
+ - Verify there's an active session
4224
+ - Load session data
4225
+
4226
+ 2. **Generate Summary:**
4227
+ - Calculate session duration
4228
+ - Review all progress notes
4229
+ - Check goals completion
4230
+ - Count git commits
4231
+ - List modified files
4232
+ - Identify key accomplishments
4233
+
4234
+ 3. **Create Summary Section:**
4235
+ - Duration
4236
+ - Goals status
4237
+ - Total updates
4238
+ - Git summary
4239
+ - Key accomplishments
4240
+ - Problems solved
4241
+ - Lessons learned
4242
+
4243
+ 4. **Close Session:**
4244
+ - Mark session as ended
4245
+ - Set end time
4246
+ - Save session file
4247
+ - Clear .current-session tracker
4248
+
4249
+ ## Summary Includes
4250
+
4251
+ **Session Info:**
4252
+ - Duration (hours and minutes)
4253
+ - Start and end times
4254
+ - Session name
4255
+
4256
+ **Goals:**
4257
+ - List of all goals
4258
+ - Completion status
4259
+
4260
+ **Progress:**
4261
+ - Number of updates
4262
+ - Key accomplishments
4263
+ - Problems and solutions
4264
+
4265
+ **Git Activity:**
4266
+ - Total commits
4267
+ - Files modified
4268
+ - Branch worked on
4269
+
4270
+ **Beads Task:**
4271
+ - Linked task ID and status
4272
+
4273
+ ## Example Output
4274
+ \`\`\`
4275
+ Session ended: 2025-01-02-1430-auth-refactor
4276
+ Duration: 2h 30m
4277
+
4278
+ Goals:
4279
+ - Refactor OAuth flow \u2705
4280
+ - Add JWT support \u2705
4281
+
4282
+ Updates: 5
4283
+ Commits: 3
4284
+ Files Modified: 7
4285
+
4286
+ Summary:
4287
+ Successfully refactored authentication system with OAuth 2.0
4288
+ and JWT token support. Resolved Next.js 15 async issues.
4289
+
4290
+ Lessons:
4291
+ - Next.js 15 requires await for params
4292
+ - JWT middleware order matters
4293
+ \`\`\`
4294
+
4295
+ ## Notes
4296
+ - Session cannot be updated after ending
4297
+ - Summary is automatically generated
4298
+ - Session file persists for future reference
4299
+ - Can start new session after ending`
4300
+ },
4301
+ {
4302
+ name: "session:current",
4303
+ description: "Show current active session",
4304
+ category: "session",
4305
+ usage: "/session:current",
4306
+ examples: ["/session:current"],
4307
+ content: `Display information about the current active session.
4308
+
4309
+ ## Workflow
4310
+
4311
+ 1. **Check Active Session:**
4312
+ - Read .current-session file
4313
+ - Load session data
4314
+
4315
+ 2. **Display Session Info:**
4316
+ - Session name and ID
4317
+ - How long session has been active
4318
+ - Session goals
4319
+ - Recent updates (last 3)
4320
+ - Current git state
4321
+ - Active Beads task
4322
+
4323
+ 3. **Show Actions:**
4324
+ - Available session commands
4325
+ - Quick reminder to update/end
4326
+
4327
+ ## Example Output
4328
+ \`\`\`
4329
+ \u{1F4CD} Current Session
4330
+
4331
+ Session: authentication-refactor
4332
+ ID: 2025-01-02-1430-auth-refactor
4333
+ Started: 2 hours ago
4334
+
4335
+ Goals:
4336
+ - [ ] Refactor OAuth flow
4337
+ - [x] Add JWT support
4338
+
4339
+ Recent Updates:
4340
+ 15:45 - Implemented OAuth 2.0 with Google
4341
+ 16:20 - Added JWT token generation
4342
+
4343
+ Git:
4344
+ - Branch: feature/auth
4345
+ - Commits: 3
4346
+ - Modified: 5 files
4347
+
4348
+ Beads Task:
4349
+ - bead-001 (in-progress)
4350
+
4351
+ Commands:
4352
+ /session:update [notes] - Add progress
4353
+ /session:end - Close session
4354
+ \`\`\`
4355
+
4356
+ ## Notes
4357
+ - Shows error if no active session
4358
+ - Use to quickly check session status
4359
+ - Displays recent progress`
4360
+ },
4361
+ {
4362
+ name: "session:list",
4363
+ description: "List all sessions",
4364
+ category: "session",
4365
+ usage: "/session:list",
4366
+ examples: ["/session:list"],
4367
+ content: `List all development sessions with summaries.
4368
+
4369
+ ## Workflow
4370
+
4371
+ 1. **Scan Sessions Directory:**
4372
+ - Find all .md files in .aikit/sessions/
4373
+ - Exclude .current-session
4374
+
4375
+ 2. **Sort by Date:**
4376
+ - Newest sessions first
4377
+
4378
+ 3. **Display Summary:**
4379
+ - Session ID and name
4380
+ - Start and end times
4381
+ - Status (active/ended)
4382
+ - Number of updates
4383
+ - Session goals
4384
+
4385
+ ## Example Output
4386
+ \`\`\`
4387
+ \u{1F4DA} All Sessions
4388
+
4389
+ 1. 2025-01-02-1430-auth-refactor
4390
+ Status: Active
4391
+ Started: 2 hours ago
4392
+ Updates: 5
4393
+ Goals: Refactor OAuth, Add JWT
4394
+
4395
+ 2. 2025-01-02-1200-bug-fix
4396
+ Status: Ended
4397
+ Started: Today 12:00
4398
+ Ended: Today 13:30 (1h 30m)
4399
+ Updates: 3
4400
+ Goals: Fix email bounce handling
4401
+
4402
+ 3. 2025-01-01-1530-feature-user-profile
4403
+ Status: Ended
4404
+ Started: Yesterday 15:30
4405
+ Ended: Yesterday 18:45 (3h 15m)
4406
+ Updates: 8
4407
+ Goals: Add user profile page
4408
+
4409
+ Total: 3 sessions
4410
+ \`\`\`
4411
+
4412
+ ## Notes
4413
+ - Shows both active and ended sessions
4414
+ - Most recent sessions first
4415
+ - Active session highlighted
4416
+ - Use /session:show <id> for details`
4417
+ },
4418
+ {
4419
+ name: "session:show",
4420
+ description: "Show details of a specific session",
4421
+ category: "session",
4422
+ usage: "/session:show <session-id>",
4423
+ examples: [
4424
+ "/session:show 2025-01-02-1430",
4425
+ "/session:show 2025-01-02-1430-auth-refactor"
4426
+ ],
4427
+ content: `Display full details of a specific session.
4428
+
4429
+ ## Workflow
4430
+
4431
+ Session ID: $ARGUMENTS
4432
+
4433
+ 1. **Load Session:**
4434
+ - Find session file
4435
+ - Parse session data
4436
+
4437
+ 2. **Display Details:**
4438
+ - Session metadata
4439
+ - All progress notes
4440
+ - Git activity timeline
4441
+ - Summary (if ended)
4442
+
4443
+ 3. **Format Output:**
4444
+ - Readable markdown format
4445
+ - Chronological updates
4446
+ - Key accomplishments
4447
+
4448
+ ## Example Output
4449
+ \`\`\`
4450
+ \u{1F4C4} Session: 2025-01-02-1430-auth-refactor
4451
+
4452
+ Status: Ended
4453
+ Started: 2025-01-02 14:30
4454
+ Ended: 2025-01-02 17:00
4455
+ Duration: 2h 30m
4456
+
4457
+ Goals:
4458
+ - [x] Refactor OAuth flow
4459
+ - [x] Add JWT support
4460
+
4461
+ ## Progress
4462
+
4463
+ ### 2025-01-02 14:30
4464
+ Started session: authentication-refactor
4465
+ Git Branch: feature/auth
4466
+
4467
+ ### 2025-01-02 15:45
4468
+ Implemented OAuth 2.0 flow with Google provider
4469
+ Added callback handler and token validation
4470
+ Git Branch: feature/auth
4471
+
4472
+ ### 2025-01-02 16:20
4473
+ Added JWT token generation and validation
4474
+ Created middleware for protected routes
4475
+ Git Branch: feature/auth
4476
+
4477
+ ### 2025-01-02 17:00
4478
+ Session ended
4479
+
4480
+ ## Summary
4481
+ Duration: 2h 30m
4482
+ Goals: 2
4483
+ Updates: 4
4484
+ Git Commits: 3
4485
+ Files Modified: 7
4486
+
4487
+ Successfully refactored authentication system...
4488
+ \`\`\`
4489
+
4490
+ ## Notes
4491
+ - Use session ID or partial ID
4492
+ - Shows all updates chronologically
4493
+ - Full session details displayed`
4494
+ },
4495
+ {
4496
+ name: "session:search",
4497
+ description: "Search sessions by keyword",
4498
+ category: "session",
4499
+ usage: "/session:search <query>",
4500
+ examples: [
4501
+ "/session:search oauth",
4502
+ '/session:search "jwt"',
4503
+ "/session:search authentication"
4504
+ ],
4505
+ content: `Search for sessions matching a keyword.
4506
+
4507
+ ## Workflow
4508
+
4509
+ Search query: $ARGUMENTS
4510
+
4511
+ 1. **Search Sessions:**
4512
+ - Search in session names
4513
+ - Search in session IDs
4514
+ - Search in goals
4515
+ - Search in update notes
4516
+
4517
+ 2. **Display Results:**
4518
+ - Matching sessions
4519
+ - Highlight match context
4520
+ - Sort by date
4521
+
4522
+ 3. **Show Actions:**
4523
+ - List matching sessions
4524
+ - Suggest /session:show for details
4525
+
4526
+ ## Example Output
4527
+ \`\`\`
4528
+ \u{1F50D} Search Results: "oauth"
4529
+
4530
+ Found 2 sessions:
4531
+
4532
+ 1. 2025-01-02-1430-auth-refactor
4533
+ Match: Name contains "oauth" (case-insensitive)
4534
+ Started: 2 hours ago
4535
+ Status: Active
4536
+ Goals: Refactor OAuth flow, Add JWT
4537
+
4538
+ 2. 2025-01-01-1200-oauth-fix
4539
+ Match: Goals contain "OAuth"
4540
+ Started: Yesterday
4541
+ Status: Ended
4542
+ Goals: Fix OAuth callback
4543
+
4544
+ Total: 2 matching sessions
4545
+ \`\`\`
4546
+
4547
+ ## Notes
4548
+ - Case-insensitive search
4549
+ - Searches name, goals, and notes
4550
+ - Shows matching context
4551
+ - Use partial IDs too`
4552
+ },
4553
+ {
4554
+ name: "session:resume",
4555
+ description: "Resume a past session (load context)",
4556
+ category: "session",
4557
+ usage: "/session:resume <session-id>",
4558
+ examples: [
4559
+ "/session:resume latest",
4560
+ "/session:resume 2025-01-02-1430",
4561
+ "/session:resume 2025-01-02-1430-auth-refactor"
4562
+ ],
4563
+ content: `Load context from a past session to resume work.
4564
+
4565
+ ## Workflow
4566
+
4567
+ Session ID: $ARGUMENTS (or "latest")
4568
+
4569
+ 1. **Find Session:**
4570
+ - If "latest", load most recent session
4571
+ - Otherwise, load specified session
4572
+
4573
+ 2. **Load Context:**
4574
+ - Display session summary
4575
+ - Show what was accomplished
4576
+ - Show what's remaining
4577
+ - List key decisions made
4578
+
4579
+ 3. **Suggest Next Actions:**
4580
+ - Based on session goals
4581
+ - Based on remaining tasks
4582
+ - Based on session end notes
4583
+
4584
+ 4. **Display Session:**
4585
+ - Full session details
4586
+ - All progress notes
4587
+ - Git activity
4588
+ - Summary and lessons
4589
+
4590
+ ## Example Output
4591
+ \`\`\`
4592
+ \u{1F504} Resuming Session: 2025-01-02-1430-auth-refactor
4593
+
4594
+ ## What Was Done
4595
+ \u2713 Refactored OAuth flow
4596
+ \u2713 Added JWT middleware
4597
+ \u2713 Fixed Next.js 15 issues
4598
+
4599
+ ## What Remains
4600
+ \u25CB Add refresh token support
4601
+ \u25CB Write tests for auth module
4602
+ \u25CB Update documentation
4603
+
4604
+ ## Key Decisions
4605
+ - Used next-auth for OAuth
4606
+ - JWT middleware order: auth \u2192 validate \u2192 route
4607
+ - Next.js 15 requires async params
4608
+
4609
+ ## Problems Solved
4610
+ - Next.js 15 params Promise issue
4611
+ - Cookie domain configuration
4612
+ - JWT secret from env var
4613
+
4614
+ ## Suggested Next Steps
4615
+ 1. Add refresh token rotation
4616
+ 2. Write unit tests for auth
4617
+ 3. Update API documentation
4618
+ 4. Deploy to staging for testing
4619
+
4620
+ Session context loaded! Ready to continue.
4621
+ \`\`\`
4622
+
4623
+ ## Notes
4624
+ - Use "latest" for most recent session
4625
+ - Loads full context for continuity
4626
+ - Suggests next actions based on goals
4627
+ - Great for picking up after a break`
4628
+ }
4629
+ ];
4630
+
4631
+ // src/core/commands/drawio.ts
4632
+ init_esm_shims();
4633
+ var DRAWIO_COMMANDS = [
4634
+ {
4635
+ name: "drawio-interact",
4636
+ description: "Create/edit diagrams with AI + Draw.io + auto-sync",
4637
+ category: "design",
4638
+ usage: "/drawio-interact <create|modify|list|start-sync|stop-sync> [diagram-name]",
4639
+ examples: [
4640
+ "/drawio-interact create login-flow",
4641
+ "/drawio-interact modify login-flow",
4642
+ "/drawio-interact list",
4643
+ "/drawio-interact start-sync",
4644
+ "/drawio-interact stop-sync"
4645
+ ],
4646
+ content: `Interactive diagram workflow with AI + Draw.io + background sync.
4647
+
4648
+ **User provided**: $ARGUMENTS
4649
+
4650
+ ## File Locations
4651
+
4652
+ **NEW STRUCTURE**:
4653
+ - **Mermaid files**: \`mermaid/[name].mmd\` (project root, version control)
4654
+ - **Draw.io files**: \`.aikit/assets/drawio/[name].drawio\` (visual editing)
4655
+
4656
+ **Background Sync**:
4657
+ - Auto-syncs changes between both formats
4658
+ - Runs as background service
4659
+ - Detects changes in real-time
4660
+
4661
+ ## Workflow
4662
+
4663
+ ### Step 1: Parse User Intent
4664
+
4665
+ Check if user wants to:
4666
+ - **create** - Generate new diagram and open in Draw.io
4667
+ - **modify** - Manual sync (if background sync not running)
4668
+ - **list** - Show all existing diagrams
4669
+ - **start-sync** - Start background sync service
4670
+ - **stop-sync** - Stop background sync service
4671
+
4672
+ ### Step 2: Create Diagram (if "create")
4673
+
4674
+ **Action**: Generate diagram from description, create files, open in Draw.io
4675
+
4676
+ 1. **Extract diagram name** from arguments
4677
+ - "create login-flow" \u2192 name = "login-flow"
4678
+ - If no name provided, ask user
4679
+
4680
+ 2. **Generate Mermaid code** based on description:
4681
+ - Login/auth \u2192 Flowchart with authentication
4682
+ - Order/purchase \u2192 Flowchart with payment
4683
+ - API/request \u2192 Sequence diagram
4684
+ - Generic \u2192 Basic flowchart
4685
+
4686
+ 3. **Create files**:
4687
+ - \`mermaid/[name].mmd\` - Mermaid source
4688
+ - \`.aikit/assets/drawio/[name].drawio\` - Draw.io XML
4689
+
4690
+ 4. **Open in Draw.io with auto-sync**:
4691
+ - Use lifecycle manager for automatic sync start/stop
4692
+ - Sync starts when Draw.io opens
4693
+ - Sync stops when Draw.io closes
4694
+ - No manual intervention needed!
4695
+
4696
+ **Implementation**: Use lifecycle manager
4697
+
4698
+ \`\`\`javascript
4699
+ import { openDrawioWithAutoSync } from '.aikit/tools/drawio-sync/lifecycle-manager.js';
4700
+ import { join } from 'path';
4701
+
4702
+ const projectRoot = process.cwd();
4703
+ const drawioPath = join(projectRoot, '.aikit/assets/drawio', \`\${name}.drawio\`);
4704
+
4705
+ // This will:
4706
+ // 1. Start sync service automatically
4707
+ // 2. Open Draw.io app
4708
+ // 3. Monitor Draw.io process
4709
+ // 4. Stop sync when Draw.io closes
4710
+ await openDrawioWithAutoSync(drawioPath);
4711
+ \`\`\`
4712
+
4713
+ **What happens**:
4714
+ - \u2705 Sync service starts automatically
4715
+ - \u2705 Draw.io opens
4716
+ - \u2705 Files stay in sync while editing
4717
+ - \u2705 Sync stops automatically when Draw.io closes
4718
+ - \u2705 Zero manual intervention!
4719
+
4720
+ 5. **Report success**:
4721
+ - Show generated Mermaid code
4722
+ - Confirm file locations
4723
+ - Confirm Draw.io opened with auto-sync
4724
+ - Inform user: "Sync will stop automatically when you close Draw.io"
4725
+
4726
+ ### Step 3: Modify Diagram (if "modify")
4727
+
4728
+ **Action**: Manual one-time sync (use if background sync not running)
4729
+
4730
+ 1. **Extract diagram name**
4731
+ 2. **Read files**:
4732
+ - \`mermaid/[name].mmd\`
4733
+ - \`.aikit/assets/drawio/[name].drawio\`
4734
+
4735
+ 3. **Convert Draw.io \u2192 Mermaid**
4736
+ 4. **Detect changes**
4737
+ 5. **Update Mermaid file**
4738
+ 6. **Report changes**
4739
+
4740
+ **Note**: If background sync is running, this is automatic!
4741
+
4742
+ ### Step 4: List Diagrams (if "list")
4743
+
4744
+ **Action**: Show all diagrams
4745
+
4746
+ \`\`\`bash
4747
+ ls mermaid/*.mmd 2>/dev/null | sed 's/mermaid\\///' | sed 's/.mmd$//'
4748
+ \`\`\`
4749
+
4750
+ Format as numbered list with file info.
4751
+
4752
+ ### Step 5: Start Sync (if "start-sync")
4753
+
4754
+ **Action**: Start background sync service
4755
+
4756
+ 1. **Check if service already running**
4757
+ 2. **Start Chokidar file watcher**:
4758
+ - Watch \`mermaid/*.mmd\`
4759
+ - Watch \`.aikit/assets/drawio/*.drawio\`
4760
+ 3. **Auto-sync on change**:
4761
+ - Debounce: 500ms
4762
+ - Lock files during sync to prevent loops
4763
+ - Log all changes
4764
+ 4. **Report**: "Background sync running"
4765
+
4766
+ **Implementation**: Use .aikit/tools/drawio-sync/sync-service.js
4767
+
4768
+ \`\`\`javascript
4769
+ import { startSyncService } from '.aikit/tools/drawio-sync/sync-service.js';
4770
+ startSyncService();
4771
+ \`\`\`
4772
+
4773
+ ### Step 6: Stop Sync (if "stop-sync")
4774
+
4775
+ **Action**: Stop background sync service
4776
+
4777
+ \`\`\`javascript
4778
+ import { stopSyncService } from '.aikit/tools/drawio-sync/sync-service.js';
4779
+ stopSyncService();
4780
+ \`\`\`
4781
+
4782
+ ## Conversion Tools
4783
+
4784
+ **Location**: \`.aikit/tools/drawio-sync/\`
4785
+
4786
+ **Modules**:
4787
+ - \`mermaid-to-drawio.js\` - Mermaid \u2192 Draw.io conversion
4788
+ - \`drawio-to-mermaid.js\` - Draw.io \u2192 Mermaid conversion
4789
+ - \`sync-service.js\` - Background sync service
4790
+ - \`lifecycle-manager.js\` - **NEW!** Automatic lifecycle (start/stop sync with Draw.io)
4791
+
4792
+ **Lifecycle Manager Usage** (recommended for "create" command):
4793
+ \`\`\`javascript
4794
+ import { openDrawioWithAutoSync } from '.aikit/tools/drawio-sync/lifecycle-manager.js';
4795
+ import { join } from 'path';
4796
+
4797
+ const drawioPath = join(process.cwd(), '.aikit/assets/drawio', name + '.drawio');
4798
+
4799
+ // Automatically:
4800
+ // - Starts sync when Draw.io opens
4801
+ // - Stops sync when Draw.io closes
4802
+ await openDrawioWithAutoSync(drawioPath);
4803
+ \`\`\`
4804
+
4805
+ **Manual Conversion** (for "modify" command):
4806
+ \`\`\`javascript
4807
+ import { convertMermaidToDrawio } from '.aikit/tools/drawio-sync/mermaid-to-drawio.js';
4808
+ import { convertDrawioToMermaid } from '.aikit/tools/drawio-sync/drawio-to-mermaid.js';
4809
+
4810
+ // Mermaid \u2192 Draw.io
4811
+ const result = convertMermaidToDrawio(mermaidCode, diagramName);
4812
+ fs.writeFileSync('.aikit/assets/drawio/name.drawio', result.xml, 'utf-8');
4813
+
4814
+ // Draw.io \u2192 Mermaid
4815
+ const result = convertDrawioToMermaid(drawioXML);
4816
+ fs.writeFileSync('mermaid/name.mmd', result.code, 'utf-8');
4817
+ \`\`\`
4818
+
4819
+ ## Error Handling
4820
+
4821
+ **If sync fails**:
4822
+ 1. Log error to console
4823
+ 2. Show notification: "Sync failed for [name]"
4824
+ 3. **Ask user**:
4825
+ - Ignore this error?
4826
+ - Retry sync?
4827
+ - Let AI fix it?
4828
+
4829
+ **AI Fix Option**:
4830
+ - Analyze error
4831
+ - Attempt to fix common issues:
4832
+ - Malformed Mermaid syntax
4833
+ - Invalid XML characters
4834
+ - Encoding issues
4835
+ - Missing nodes
4836
+ - Retry sync after fix
4837
+ - Report result
4838
+
4839
+ ## Example Session
4840
+
4841
+ \`\`\`
4842
+ User: /drawio-interact create user-authentication
4843
+
4844
+ AI: Creating diagram: user-authentication
4845
+
4846
+ \u{1F4C4} Generated Mermaid Code:
4847
+ graph TD
4848
+ User[User] -->|Login| Login[Login Page]
4849
+ Login -->|Success| Dashboard[Dashboard]
4850
+
4851
+ \u2705 Files created:
4852
+ - mermaid/user-authentication.mmd
4853
+ - .aikit/assets/drawio/user-authentication.drawio
4854
+
4855
+ \u{1F504} Starting background sync service...
4856
+ \u2705 Sync service running
4857
+
4858
+ \u{1F3A8} Opening Draw.io...
4859
+ \u{1F440} Monitoring Draw.io app (sync will stop when Draw.io closes)
4860
+
4861
+ ---
4862
+
4863
+ [User edits in Draw.io, adds "Password Recovery", saves]
4864
+
4865
+ \u{1F504} Background sync detected changes:
4866
+ \u2022 Added nodes: Recovery, ResetEmail
4867
+ \u2022 Modified connections: Login \u2192 Recovery
4868
+
4869
+ \u2705 Updated: mermaid/user-authentication.mmd
4870
+
4871
+ [Or user edits mermaid/user-authentication.mmd directly]
4872
+
4873
+ \u{1F504} Background sync detected changes:
4874
+ \u2022 Modified Mermaid syntax
4875
+
4876
+ \u2705 Updated: .aikit/assets/drawio/user-authentication.drawio
4877
+
4878
+ ---
4879
+
4880
+ [User closes Draw.io app]
4881
+
4882
+ \u{1F3A8} Draw.io closed - stopping sync service
4883
+ \u2705 Sync service stopped
4884
+ \`\`\`
4885
+
4886
+ **Key Point**: Sync starts automatically when Draw.io opens, and stops automatically when Draw.io closes. No manual commands needed!
4887
+
4888
+ ## Important Notes
4889
+
4890
+ - **Auto-sync lifecycle** - Sync starts when Draw.io opens, stops when it closes
4891
+ - **Zero manual intervention** - No need to run start/stop commands
4892
+ - **Draw.io app** opens automatically on "create"
4893
+ - **Both formats** stay in sync automatically while Draw.io is open
4894
+ - **Mermaid files** are in project root for version control
4895
+ - **Draw.io files** are in .aikit/assets (can be .gitignored)
4896
+ - **Manual commands** (start-sync/stop-sync) only needed for special cases
4897
+
4898
+ ## Auto-Open Commands
4899
+
4900
+ **IMPORTANT**: Always use absolute paths!
4901
+
4902
+ **Example code**:
4903
+ \`\`\`javascript
4904
+ const platform = process.platform;
4905
+ const projectRoot = process.cwd(); // Get absolute project root
4906
+ const filePath = join(projectRoot, '.aikit/assets/drawio', name + '.drawio');
4907
+
4908
+ if (platform === 'darwin') {
4909
+ // macOS: Use double quotes for path with spaces
4910
+ execSync('open -a "Draw.io" "' + filePath + '"');
4911
+ } else if (platform === 'linux') {
4912
+ // Linux
4913
+ execSync('xdg-open "' + filePath + '"');
4914
+ } else if (platform === 'win32') {
4915
+ // Windows
4916
+ execSync('start "" "' + filePath + '"', { shell: true });
4917
+ }
4918
+ \`\`\`
4919
+
4920
+ **Why absolute paths?**
4921
+ - Relative paths depend on current working directory
4922
+ - Claude/AI might execute from wrong directory
4923
+ - Absolute paths always work correctly
4924
+
4925
+ **Fallback**: If Draw.io app not found, open https://app.diagrams.net/
4926
+
4927
+ ## Directory Setup
3180
4928
 
3181
- 1. Determine log location
3182
- 2. Apply filters if specified
3183
- 3. Display logs
3184
- 4. If --follow, stream updates
3185
- 5. Format for readability`
4929
+ Ensure directories exist:
4930
+ \`\`\`bash
4931
+ mkdir -p mermaid
4932
+ mkdir -p .aikit/assets/drawio
4933
+ \`\`\``
3186
4934
  }
3187
4935
  ];
4936
+
4937
+ // src/core/commands/index.ts
4938
+ var DEFAULT_COMMANDS = [
4939
+ ...CORE_COMMANDS,
4940
+ ...QUICK_COMMANDS,
4941
+ ...RESEARCH_COMMANDS,
4942
+ ...DESIGN_COMMANDS,
4943
+ ...GIT_COMMANDS,
4944
+ ...UTILITY_COMMANDS,
4945
+ ...CHECKPOINT_COMMANDS,
4946
+ ...SESSION_COMMANDS,
4947
+ ...DRAWIO_COMMANDS
4948
+ ];
3188
4949
  var CommandRunner = class {
3189
4950
  config;
3190
4951
  commandsCache = /* @__PURE__ */ new Map();
@@ -4649,17 +6410,17 @@ export default ${toPascalCase(name)}Plugin;
4649
6410
  event: async (event) => {
4650
6411
  if (event.type === "session.idle") {
4651
6412
  try {
4652
- const { exec: exec2 } = await import("child_process");
4653
- const { promisify: promisify2 } = await import("util");
4654
- const execAsync2 = promisify2(exec2);
6413
+ const { exec: exec3 } = await import("child_process");
6414
+ const { promisify: promisify3 } = await import("util");
6415
+ const execAsync3 = promisify3(exec3);
4655
6416
  const platform = process.platform;
4656
6417
  const summary = event.properties?.summary || "Session completed";
4657
6418
  if (platform === "darwin") {
4658
- await execAsync2(`osascript -e 'display notification "${summary}" with title "OpenCode Session Complete"'`);
6419
+ await execAsync3(`osascript -e 'display notification "${summary}" with title "OpenCode Session Complete"'`);
4659
6420
  } else if (platform === "linux") {
4660
- await execAsync2(`notify-send "OpenCode Session Complete" "${summary}"`);
6421
+ await execAsync3(`notify-send "OpenCode Session Complete" "${summary}"`);
4661
6422
  } else if (platform === "win32") {
4662
- await execAsync2(`powershell -Command "New-BurntToastNotification -Text 'OpenCode Session Complete', '${summary}'"`);
6423
+ await execAsync3(`powershell -Command "New-BurntToastNotification -Text 'OpenCode Session Complete', '${summary}'"`);
4663
6424
  }
4664
6425
  } catch (error) {
4665
6426
  logger.warn(`[Notification] Failed to send notification: ${error instanceof Error ? error.message : String(error)}`);
@@ -4710,9 +6471,15 @@ init_beads();
4710
6471
  // src/utils/cli-detector.ts
4711
6472
  init_esm_shims();
4712
6473
  import { execSync } from "child_process";
4713
- import { existsSync as existsSync4 } from "fs";
6474
+ import { existsSync as existsSync5 } from "fs";
4714
6475
  import { join as join12 } from "path";
4715
6476
  import { homedir as homedir2 } from "os";
6477
+ var CliPlatform = /* @__PURE__ */ ((CliPlatform2) => {
6478
+ CliPlatform2["OPENCODE"] = "opencode";
6479
+ CliPlatform2["CLAUDE"] = "claude";
6480
+ CliPlatform2["CODEX"] = "codex";
6481
+ return CliPlatform2;
6482
+ })(CliPlatform || {});
4716
6483
  var CliDetector = class {
4717
6484
  /**
4718
6485
  * Check if OpenCode is installed
@@ -4721,14 +6488,14 @@ var CliDetector = class {
4721
6488
  try {
4722
6489
  const opencodePath = process.platform === "win32" ? process.env.APPDATA || join12(homedir2(), "AppData", "Roaming") : join12(homedir2(), ".config");
4723
6490
  const opencodeConfig = join12(opencodePath, "opencode", "opencode.json");
4724
- let installed = existsSync4(opencodeConfig);
6491
+ let installed = existsSync5(opencodeConfig);
4725
6492
  let version;
4726
6493
  if (installed) {
4727
6494
  try {
4728
6495
  execSync("opencode --version", { stdio: "ignore" });
4729
6496
  version = "installed";
4730
6497
  } catch (error) {
4731
- if (existsSync4(opencodeConfig)) {
6498
+ if (existsSync5(opencodeConfig)) {
4732
6499
  version = "installed (config exists)";
4733
6500
  } else {
4734
6501
  installed = false;
@@ -4820,6 +6587,47 @@ var CliDetector = class {
4820
6587
  static filterInstallable(tools) {
4821
6588
  return tools.filter((t) => t.detected && !t.installed);
4822
6589
  }
6590
+ /**
6591
+ * Detect available platforms
6592
+ */
6593
+ static async detectPlatforms() {
6594
+ const platforms = [];
6595
+ const opencodePath = process.platform === "win32" ? process.env.APPDATA || join12(homedir2(), "AppData", "Roaming") : join12(homedir2(), ".config");
6596
+ platforms.push({
6597
+ platform: "opencode" /* OPENCODE */,
6598
+ displayName: "OpenCode",
6599
+ installed: existsSync5(join12(opencodePath, "opencode", "opencode.json")),
6600
+ configPath: opencodePath
6601
+ });
6602
+ const claudePath = process.platform === "win32" ? process.env.APPDATA || join12(homedir2(), "AppData", "Roaming") : join12(homedir2(), ".claude");
6603
+ platforms.push({
6604
+ platform: "claude" /* CLAUDE */,
6605
+ displayName: "Claude Code CLI",
6606
+ installed: existsSync5(claudePath),
6607
+ configPath: claudePath
6608
+ });
6609
+ return platforms;
6610
+ }
6611
+ /**
6612
+ * Filter installed platforms
6613
+ */
6614
+ static filterInstalledPlatforms(platforms) {
6615
+ return platforms.filter((p) => p.installed);
6616
+ }
6617
+ /**
6618
+ * Match platform name to CliPlatform enum
6619
+ */
6620
+ static matchPlatform(name) {
6621
+ const normalized = name.toLowerCase();
6622
+ if (normalized === "opencode" || normalized === "open-code") {
6623
+ return "opencode" /* OPENCODE */;
6624
+ } else if (normalized === "claude" || normalized === "claude-code" || normalized === "claude-code-cli") {
6625
+ return "claude" /* CLAUDE */;
6626
+ } else if (normalized === "codex") {
6627
+ return "codex" /* CODEX */;
6628
+ }
6629
+ throw new Error(`Unknown platform: ${name}`);
6630
+ }
4823
6631
  };
4824
6632
 
4825
6633
  // src/cli/commands/init.ts
@@ -4828,9 +6636,9 @@ init_paths();
4828
6636
 
4829
6637
  // src/cli/helpers.ts
4830
6638
  init_esm_shims();
4831
- import { existsSync as existsSync5 } from "fs";
4832
- import { mkdir as mkdir8, writeFile as writeFile8, readFile as readFile7, access as access4 } from "fs/promises";
4833
- import { join as join13, dirname as dirname2 } from "path";
6639
+ import { existsSync as existsSync6 } from "fs";
6640
+ import { mkdir as mkdir9, writeFile as writeFile9, readFile as readFile8, access as access5 } from "fs/promises";
6641
+ import { join as join14, dirname as dirname2 } from "path";
4834
6642
  import { homedir as homedir3 } from "os";
4835
6643
  import { fileURLToPath as fileURLToPath3 } from "url";
4836
6644
  import { execSync as execSync2 } from "child_process";
@@ -4856,7 +6664,7 @@ async function initializeConfig(configDir, _isGlobal) {
4856
6664
  "memory/research"
4857
6665
  ];
4858
6666
  for (const dir of dirs) {
4859
- await mkdir8(join13(configDir, dir), { recursive: true });
6667
+ await mkdir9(join14(configDir, dir), { recursive: true });
4860
6668
  }
4861
6669
  const defaultConfig = {
4862
6670
  version: getVersion(),
@@ -4869,8 +6677,8 @@ async function initializeConfig(configDir, _isGlobal) {
4869
6677
  beads: { enabled: true },
4870
6678
  antiHallucination: { enabled: true }
4871
6679
  };
4872
- await writeFile8(
4873
- join13(configDir, "aikit.json"),
6680
+ await writeFile9(
6681
+ join14(configDir, "aikit.json"),
4874
6682
  JSON.stringify(defaultConfig, null, 2)
4875
6683
  );
4876
6684
  const agentsMd = `# AIKit Agent Rules
@@ -4893,20 +6701,20 @@ async function initializeConfig(configDir, _isGlobal) {
4893
6701
  ## Project-Specific Rules
4894
6702
  Add your project-specific rules here.
4895
6703
  `;
4896
- await writeFile8(join13(configDir, "AGENTS.md"), agentsMd);
6704
+ await writeFile9(join14(configDir, "AGENTS.md"), agentsMd);
4897
6705
  }
4898
6706
  async function configureMcpServer(projectPath) {
4899
6707
  const currentFile = fileURLToPath3(import.meta.url);
4900
6708
  const currentDir = dirname2(currentFile);
4901
- const aikitPath = join13(currentDir, "..", "..");
4902
- const mcpServerPath = join13(aikitPath, "dist", "mcp-server.js");
6709
+ const aikitPath = join14(currentDir, "..", "..");
6710
+ const mcpServerPath = join14(aikitPath, "dist", "mcp-server.js");
4903
6711
  const configLocations = [
4904
6712
  // Global config (most common)
4905
- join13(homedir3(), ".config", "opencode", "opencode.json"),
6713
+ join14(homedir3(), ".config", "opencode", "opencode.json"),
4906
6714
  // Project-level config
4907
- join13(projectPath, ".opencode", "opencode.json"),
6715
+ join14(projectPath, ".opencode", "opencode.json"),
4908
6716
  // Alternative global location
4909
- join13(homedir3(), ".opencode", "opencode.json")
6717
+ join14(homedir3(), ".opencode", "opencode.json")
4910
6718
  ];
4911
6719
  const mcpServerConfig = {
4912
6720
  type: "local",
@@ -4915,12 +6723,12 @@ async function configureMcpServer(projectPath) {
4915
6723
  };
4916
6724
  for (const configPath of configLocations) {
4917
6725
  try {
4918
- const configDir = join13(configPath, "..");
4919
- await mkdir8(configDir, { recursive: true });
6726
+ const configDir = join14(configPath, "..");
6727
+ await mkdir9(configDir, { recursive: true });
4920
6728
  let config = {};
4921
- if (existsSync5(configPath)) {
6729
+ if (existsSync6(configPath)) {
4922
6730
  try {
4923
- const existing = await readFile7(configPath, "utf-8");
6731
+ const existing = await readFile8(configPath, "utf-8");
4924
6732
  config = JSON.parse(existing);
4925
6733
  } catch {
4926
6734
  config = {};
@@ -4930,7 +6738,7 @@ async function configureMcpServer(projectPath) {
4930
6738
  config.mcp = {};
4931
6739
  }
4932
6740
  config.mcp.aikit = mcpServerConfig;
4933
- await writeFile8(configPath, JSON.stringify(config, null, 2));
6741
+ await writeFile9(configPath, JSON.stringify(config, null, 2));
4934
6742
  logger.success(`
4935
6743
  \u2705 MCP server configured: ${configPath}`);
4936
6744
  logger.info(` Server: node ${mcpServerPath}`);
@@ -4939,9 +6747,9 @@ async function configureMcpServer(projectPath) {
4939
6747
  continue;
4940
6748
  }
4941
6749
  }
4942
- const instructionsPath = join13(projectPath, ".opencode", "MCP_SETUP.md");
4943
- await mkdir8(join13(projectPath, ".opencode"), { recursive: true });
4944
- await writeFile8(instructionsPath, `# AIKit MCP Server Configuration
6750
+ const instructionsPath = join14(projectPath, ".opencode", "MCP_SETUP.md");
6751
+ await mkdir9(join14(projectPath, ".opencode"), { recursive: true });
6752
+ await writeFile9(instructionsPath, `# AIKit MCP Server Configuration
4945
6753
 
4946
6754
  ## Automatic Setup Failed
4947
6755
 
@@ -4988,13 +6796,24 @@ async function installCliTool(tool) {
4988
6796
  await installToOpenCode(paths.opencodeConfig());
4989
6797
  break;
4990
6798
  case "claude" /* CLAUDE */:
4991
- execSync2("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
6799
+ let platform;
6800
+ try {
6801
+ platform = process.platform;
6802
+ } catch {
6803
+ platform = "darwin";
6804
+ }
6805
+ if (platform === "darwin") {
6806
+ execSync2("curl -fsSL https://claude.ai/install.sh | bash", { stdio: "inherit" });
6807
+ } else if (platform === "win32") {
6808
+ execSync2('powershell -Command "irm https://claude.ai/install.ps1 | iex"', { stdio: "inherit" });
6809
+ } else {
6810
+ execSync2("curl -fsSL https://claude.ai/install.sh | bash", { stdio: "inherit" });
6811
+ }
4992
6812
  break;
4993
6813
  case "github" /* GITHUB */:
4994
6814
  execSync2("npm install -g gh", { stdio: "inherit" });
4995
6815
  break;
4996
6816
  }
4997
- logger.success(`\u2713 ${tool.displayName} installed`);
4998
6817
  return true;
4999
6818
  } catch (error) {
5000
6819
  logger.error(`Failed to install ${tool.displayName}:`, error);
@@ -5183,26 +7002,26 @@ Report what was extracted:
5183
7002
  }
5184
7003
  async function installToOpenCode(_opencodePath) {
5185
7004
  const projectPath = process.cwd();
5186
- const opencodeCommandDir = join13(projectPath, ".opencode", "command");
5187
- const aikitDir = join13(projectPath, ".aikit");
5188
- const opencodeAgentDir = join13(paths.opencodeConfig(), "agent");
5189
- await mkdir8(opencodeCommandDir, { recursive: true });
5190
- await mkdir8(join13(aikitDir, "skills"), { recursive: true });
5191
- await mkdir8(opencodeAgentDir, { recursive: true });
7005
+ const opencodeCommandDir = join14(projectPath, ".opencode", "command");
7006
+ const aikitDir = join14(projectPath, ".aikit");
7007
+ const opencodeAgentDir = join14(paths.opencodeConfig(), "agent");
7008
+ await mkdir9(opencodeCommandDir, { recursive: true });
7009
+ await mkdir9(join14(aikitDir, "skills"), { recursive: true });
7010
+ await mkdir9(opencodeAgentDir, { recursive: true });
5192
7011
  for (const [name, content] of Object.entries(AGENT_FILES)) {
5193
- const filePath = join13(opencodeAgentDir, `${name}.md`);
7012
+ const filePath = join14(opencodeAgentDir, `${name}.md`);
5194
7013
  try {
5195
- await access4(filePath);
5196
- const existingContent = await readFile7(filePath, "utf8");
7014
+ await access5(filePath);
7015
+ const existingContent = await readFile8(filePath, "utf8");
5197
7016
  if (!existingContent.includes("mode: subagent")) {
5198
- const matter3 = await import("gray-matter");
5199
- const { data: frontmatter, content: body } = matter3.default(existingContent);
7017
+ const matter5 = await import("gray-matter");
7018
+ const { data: frontmatter, content: body } = matter5.default(existingContent);
5200
7019
  frontmatter.mode = "subagent";
5201
- const updatedContent = matter3.default.stringify(body, frontmatter);
5202
- await writeFile8(filePath, updatedContent, "utf8");
7020
+ const updatedContent = matter5.default.stringify(body, frontmatter);
7021
+ await writeFile9(filePath, updatedContent, "utf8");
5203
7022
  }
5204
7023
  } catch {
5205
- await writeFile8(filePath, content, "utf8");
7024
+ await writeFile9(filePath, content, "utf8");
5206
7025
  }
5207
7026
  }
5208
7027
  const config = await loadConfig();
@@ -5294,8 +7113,8 @@ ${cmd.content}
5294
7113
  }
5295
7114
  let count = 0;
5296
7115
  for (const [name, content] of Object.entries(opencodeCommands)) {
5297
- const filePath = join13(opencodeCommandDir, `${name}.md`);
5298
- await writeFile8(filePath, content.trim());
7116
+ const filePath = join14(opencodeCommandDir, `${name}.md`);
7117
+ await writeFile9(filePath, content.trim());
5299
7118
  logger.info(` \u2713 Created /${name} command`);
5300
7119
  count++;
5301
7120
  }
@@ -5316,10 +7135,541 @@ function groupBy(array, keyFn) {
5316
7135
  return acc;
5317
7136
  }, {});
5318
7137
  }
7138
+ async function startSession(name, goals) {
7139
+ try {
7140
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7141
+ const manager = new SessionManager2();
7142
+ const session = await manager.startSession(name, goals);
7143
+ logger.success("\u2713 Session started");
7144
+ console.log(` ID: ${session.id}`);
7145
+ console.log(` Name: ${session.name}`);
7146
+ console.log(` Started: ${new Date(session.startTime).toLocaleString()}`);
7147
+ if (session.goals.length > 0) {
7148
+ console.log(` Goals:`);
7149
+ session.goals.forEach((goal) => console.log(` - ${goal}`));
7150
+ }
7151
+ console.log("\nCommands:");
7152
+ console.log(" /session:update [notes] - Add progress notes");
7153
+ console.log(" /session:end - End session with summary");
7154
+ console.log(" /session:current - Show session status\n");
7155
+ } catch (error) {
7156
+ logger.error("Failed to start session:", error);
7157
+ }
7158
+ }
7159
+ async function updateSession(notes) {
7160
+ try {
7161
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7162
+ const manager = new SessionManager2();
7163
+ const session = await manager.updateSession(notes);
7164
+ if (session) {
7165
+ logger.success("\u2713 Session updated");
7166
+ console.log(` Session: ${session.id}`);
7167
+ console.log(` Notes: ${notes || "Auto-generated"}`);
7168
+ console.log(` Time: ${(/* @__PURE__ */ new Date()).toLocaleString()}`);
7169
+ if (session.updates[session.updates.length - 1]?.modifiedFiles) {
7170
+ const files = session.updates[session.updates.length - 1].modifiedFiles;
7171
+ console.log(` Modified: ${files?.length} files`);
7172
+ }
7173
+ console.log();
7174
+ }
7175
+ } catch (error) {
7176
+ if (error instanceof Error && error.message.includes("No active session")) {
7177
+ logger.error("No active session. Use /session:start first");
7178
+ } else {
7179
+ logger.error("Failed to update session:", error);
7180
+ }
7181
+ }
7182
+ }
7183
+ async function endSession() {
7184
+ try {
7185
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7186
+ const manager = new SessionManager2();
7187
+ const session = await manager.endSession();
7188
+ if (session) {
7189
+ const duration = session.endTime ? Math.floor((new Date(session.endTime).getTime() - new Date(session.startTime).getTime()) / 6e4) : 0;
7190
+ logger.success("\u2713 Session ended");
7191
+ console.log(`
7192
+ Session: ${session.id}`);
7193
+ console.log(`Name: ${session.name}`);
7194
+ console.log(`Duration: ${Math.floor(duration / 60)}h ${duration % 60}m`);
7195
+ console.log(`Updates: ${session.updates.length}`);
7196
+ if (session.goals.length > 0) {
7197
+ console.log(`
7198
+ Goals:`);
7199
+ session.goals.forEach((goal) => console.log(` - ${goal}`));
7200
+ }
7201
+ const lastUpdate = session.updates[session.updates.length - 1];
7202
+ if (lastUpdate?.gitCommits) {
7203
+ console.log(`
7204
+ Git Activity:`);
7205
+ console.log(` Commits: ${lastUpdate.gitCommits}`);
7206
+ if (lastUpdate.modifiedFiles && lastUpdate.modifiedFiles.length > 0) {
7207
+ console.log(` Files Modified: ${lastUpdate.modifiedFiles.length}`);
7208
+ }
7209
+ }
7210
+ console.log(`
7211
+ Use /session:show ${session.id} for details
7212
+ `);
7213
+ }
7214
+ } catch (error) {
7215
+ if (error instanceof Error && error.message.includes("No active session")) {
7216
+ logger.error("No active session. Use /session:start first");
7217
+ } else {
7218
+ logger.error("Failed to end session:", error);
7219
+ }
7220
+ }
7221
+ }
7222
+ async function showCurrentSession() {
7223
+ try {
7224
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7225
+ const manager = new SessionManager2();
7226
+ const session = await manager.getCurrentSession();
7227
+ if (!session) {
7228
+ logger.info("No active session");
7229
+ console.log("Start a session: /session:start [name]\n");
7230
+ return;
7231
+ }
7232
+ const duration = Math.floor((Date.now() - new Date(session.startTime).getTime()) / 6e4);
7233
+ console.log("\n\u{1F4CD} Current Session");
7234
+ console.log("\u2501".repeat(60));
7235
+ console.log(`
7236
+ Session: ${session.name}`);
7237
+ console.log(`ID: ${session.id}`);
7238
+ console.log(`Started: ${Math.floor(duration / 60)}h ${duration % 60}m ago`);
7239
+ if (session.goals.length > 0) {
7240
+ console.log(`
7241
+ Goals:`);
7242
+ session.goals.forEach((goal) => console.log(` - ${goal}`));
7243
+ }
7244
+ if (session.updates.length > 0) {
7245
+ console.log(`
7246
+ Recent Updates (last 3):`);
7247
+ const recent = session.updates.slice(-3);
7248
+ recent.forEach((update) => {
7249
+ const date = new Date(update.timestamp);
7250
+ console.log(` ${date.toLocaleTimeString()} - ${update.notes || "Update"}`);
7251
+ });
7252
+ }
7253
+ const lastUpdate = session.updates[session.updates.length - 1];
7254
+ if (lastUpdate?.gitBranch || lastUpdate?.gitCommits) {
7255
+ console.log(`
7256
+ Git:`);
7257
+ if (lastUpdate.gitBranch) console.log(` Branch: ${lastUpdate.gitBranch}`);
7258
+ if (lastUpdate.gitCommits) console.log(` Commits: ${lastUpdate.gitCommits}`);
7259
+ if (lastUpdate.modifiedFiles && lastUpdate.modifiedFiles.length > 0) {
7260
+ console.log(` Modified: ${lastUpdate.modifiedFiles.length} files`);
7261
+ }
7262
+ }
7263
+ if (lastUpdate?.beadsTask) {
7264
+ console.log(`
7265
+ Beads Task:`);
7266
+ console.log(` ${lastUpdate.beadsTask.id} (${lastUpdate.beadsTask.status})`);
7267
+ }
7268
+ console.log("\nCommands:");
7269
+ console.log(" /session:update [notes] - Add progress");
7270
+ console.log(" /session:end - Close session");
7271
+ console.log("\u2501".repeat(60) + "\n");
7272
+ } catch (error) {
7273
+ logger.error("Failed to show current session:", error);
7274
+ }
7275
+ }
7276
+ async function listSessions() {
7277
+ try {
7278
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7279
+ const manager = new SessionManager2();
7280
+ const sessions = await manager.listSessions();
7281
+ if (sessions.length === 0) {
7282
+ logger.info("No sessions found");
7283
+ console.log("Start a session: /session:start [name]\n");
7284
+ return;
7285
+ }
7286
+ console.log("\n\u{1F4DA} All Sessions");
7287
+ console.log("\u2501".repeat(60));
7288
+ sessions.forEach((session, index) => {
7289
+ const startDate = new Date(session.startTime);
7290
+ const endDate = session.endTime ? new Date(session.endTime) : null;
7291
+ const duration = endDate ? Math.floor((endDate.getTime() - startDate.getTime()) / 6e4) : null;
7292
+ console.log(`
7293
+ ${index + 1}. ${session.id}`);
7294
+ console.log(` Status: ${session.status === "active" ? "\u{1F7E2} Active" : "Ended"}`);
7295
+ console.log(` Name: ${session.name}`);
7296
+ console.log(` Started: ${startDate.toLocaleString()}`);
7297
+ if (endDate && duration) {
7298
+ console.log(` Ended: ${endDate.toLocaleString()} (${Math.floor(duration / 60)}h ${duration % 60}m)`);
7299
+ }
7300
+ if (session.goals.length > 0) {
7301
+ console.log(` Goals: ${session.goals.slice(0, 2).join(", ")}${session.goals.length > 2 ? "..." : ""}`);
7302
+ }
7303
+ console.log(` Updates: ${session.updates.length}`);
7304
+ });
7305
+ console.log("\n" + "\u2501".repeat(60));
7306
+ console.log(`
7307
+ Total: ${sessions.length} session${sessions.length > 1 ? "s" : ""}
7308
+ `);
7309
+ console.log("Commands:");
7310
+ console.log(" /session:show <id> - View session details");
7311
+ console.log(" /session:resume <id> - Resume session");
7312
+ console.log(" /session:search <query> - Search sessions\n");
7313
+ } catch (error) {
7314
+ logger.error("Failed to list sessions:", error);
7315
+ }
7316
+ }
7317
+ async function showSession(sessionId) {
7318
+ try {
7319
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7320
+ const manager = new SessionManager2();
7321
+ const sessions = await manager.listSessions();
7322
+ const session = sessions.find((s) => s.id.startsWith(sessionId) || s.id === sessionId);
7323
+ if (!session) {
7324
+ logger.error(`Session not found: ${sessionId}`);
7325
+ console.log("Use /session:list to see all sessions\n");
7326
+ return;
7327
+ }
7328
+ const startDate = new Date(session.startTime);
7329
+ const endDate = session.endTime ? new Date(session.endTime) : null;
7330
+ const duration = endDate ? Math.floor((endDate.getTime() - startDate.getTime()) / 6e4) : null;
7331
+ console.log("\n\u{1F4C4} Session: " + session.id);
7332
+ console.log("\u2501".repeat(60));
7333
+ console.log(`
7334
+ Status: ${session.status === "active" ? "\u{1F7E2} Active" : "Ended"}`);
7335
+ console.log(`Name: ${session.name}`);
7336
+ console.log(`Started: ${startDate.toLocaleString()}`);
7337
+ if (endDate && duration) {
7338
+ console.log(`Ended: ${endDate.toLocaleString()}`);
7339
+ console.log(`Duration: ${Math.floor(duration / 60)}h ${duration % 60}m`);
7340
+ }
7341
+ if (session.goals.length > 0) {
7342
+ console.log(`
7343
+ Goals:`);
7344
+ session.goals.forEach((goal) => console.log(` ${session.status === "ended" ? "\u2713" : "\u25CB"} ${goal}`));
7345
+ }
7346
+ console.log(`
7347
+ ## Progress (${session.updates.length} updates)`);
7348
+ session.updates.forEach((update) => {
7349
+ const date = new Date(update.timestamp);
7350
+ console.log(`
7351
+ ### ${date.toLocaleString()}`);
7352
+ if (update.notes) console.log(`${update.notes}`);
7353
+ if (update.gitBranch) console.log(`**Git Branch:** ${update.gitBranch}`);
7354
+ if (update.modifiedFiles && update.modifiedFiles.length > 0) {
7355
+ console.log(`**Modified Files:** ${update.modifiedFiles.length} files`);
7356
+ }
7357
+ if (update.beadsTask) {
7358
+ console.log(`**Beads Task:** ${update.beadsTask.id} (${update.beadsTask.status})`);
7359
+ }
7360
+ });
7361
+ if (session.status === "ended") {
7362
+ console.log(`
7363
+ ## Summary`);
7364
+ console.log(`Duration: ${duration ? Math.floor(duration / 60) + "h " + duration % 60 + "m" : "N/A"}`);
7365
+ console.log(`Updates: ${session.updates.length}`);
7366
+ if (session.updates[session.updates.length - 1]?.gitCommits) {
7367
+ console.log(`Git Commits: ${session.updates[session.updates.length - 1].gitCommits}`);
7368
+ }
7369
+ }
7370
+ console.log("\n" + "\u2501".repeat(60) + "\n");
7371
+ } catch (error) {
7372
+ logger.error("Failed to show session:", error);
7373
+ }
7374
+ }
7375
+ async function searchSessions(query) {
7376
+ try {
7377
+ const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
7378
+ const manager = new SessionManager2();
7379
+ const sessions = await manager.searchSessions(query);
7380
+ if (sessions.length === 0) {
7381
+ logger.info(`No sessions found matching: ${query}`);
7382
+ console.log("Use /session:list to see all sessions\n");
7383
+ return;
7384
+ }
7385
+ console.log(`
7386
+ \u{1F50D} Search Results: "${query}"`);
7387
+ console.log("\u2501".repeat(60));
7388
+ console.log(`
7389
+ Found ${sessions.length} session${sessions.length > 1 ? "s" : ""}:
7390
+ `);
7391
+ sessions.forEach((session, index) => {
7392
+ const startDate = new Date(session.startTime);
7393
+ console.log(`${index + 1}. ${session.id}`);
7394
+ console.log(` Name: ${session.name}`);
7395
+ console.log(` Started: ${startDate.toLocaleString()}`);
7396
+ console.log(` Status: ${session.status === "active" ? "\u{1F7E2} Active" : "Ended"}`);
7397
+ if (session.goals.length > 0) {
7398
+ console.log(` Goals: ${session.goals.slice(0, 2).join(", ")}${session.goals.length > 2 ? "..." : ""}`);
7399
+ }
7400
+ console.log();
7401
+ });
7402
+ console.log("\u2501".repeat(60));
7403
+ console.log(`
7404
+ Total: ${sessions.length} matching session${sessions.length > 1 ? "s" : ""}
7405
+ `);
7406
+ console.log("Commands:");
7407
+ console.log(" /session:show <id> - View session details");
7408
+ console.log(" /session:resume <id> - Resume session\n");
7409
+ } catch (error) {
7410
+ logger.error("Failed to search sessions:", error);
7411
+ }
7412
+ }
7413
+
7414
+ // src/platform/adapters.ts
7415
+ init_esm_shims();
7416
+
7417
+ // src/platform/opencode-adapter.ts
7418
+ init_esm_shims();
7419
+ init_paths();
7420
+ import { readFile as readFile9, writeFile as writeFile10, mkdir as mkdir10, access as access6 } from "fs/promises";
7421
+ import { join as join15 } from "path";
7422
+ var OpenCodeAdapter = class {
7423
+ platform = "opencode" /* OPENCODE */;
7424
+ displayName = "OpenCode";
7425
+ getCommandsDir() {
7426
+ return join15(process.cwd(), ".opencode", "command");
7427
+ }
7428
+ getSkillsDir() {
7429
+ return join15(process.cwd(), ".opencode", "skill");
7430
+ }
7431
+ getAgentsDir() {
7432
+ return join15(paths.opencodeConfig(), "agent");
7433
+ }
7434
+ async transformCommand(command) {
7435
+ const name = `ak_cm_${command.name}`;
7436
+ const content = this.generateCommandContent(command);
7437
+ return { name, content };
7438
+ }
7439
+ async transformSkill(skill) {
7440
+ const skillName = `ak_sk_${skill.name}`;
7441
+ const skillContent = this.generateSkillContent(skill);
7442
+ const result = {
7443
+ name: skillName,
7444
+ directory: "",
7445
+ files: { [`${skillName}.md`]: skillContent }
7446
+ };
7447
+ return result;
7448
+ }
7449
+ async transformAgent(agent) {
7450
+ const name = agent.name === "build" || agent.name === "planner" ? `aikit${agent.name}` : agent.name;
7451
+ const content = this.generateAgentContent(agent, name);
7452
+ return { name, content };
7453
+ }
7454
+ async installCommand(name, content) {
7455
+ const dir = this.getCommandsDir();
7456
+ await mkdir10(dir, { recursive: true });
7457
+ await writeFile10(join15(dir, `${name}.md`), content);
7458
+ }
7459
+ async installSkill(_name, directory, files) {
7460
+ const baseDir = this.getSkillsDir();
7461
+ const targetDir = directory ? join15(baseDir, directory) : baseDir;
7462
+ await mkdir10(targetDir, { recursive: true });
7463
+ for (const [filename, content] of Object.entries(files)) {
7464
+ await writeFile10(join15(targetDir, filename), content);
7465
+ }
7466
+ }
7467
+ async installAgent(name, content) {
7468
+ const dir = this.getAgentsDir();
7469
+ await mkdir10(dir, { recursive: true });
7470
+ const filePath = join15(dir, `${name}.md`);
7471
+ try {
7472
+ await access6(filePath);
7473
+ const existingContent = await readFile9(filePath, "utf-8");
7474
+ if (!existingContent.includes("mode: subagent")) {
7475
+ const matter5 = await import("gray-matter");
7476
+ const { data: frontmatter, content: body } = matter5.default(existingContent);
7477
+ frontmatter.mode = "subagent";
7478
+ const updatedContent = matter5.default.stringify(body, frontmatter);
7479
+ await writeFile10(filePath, updatedContent, "utf-8");
7480
+ }
7481
+ } catch {
7482
+ await writeFile10(filePath, content, "utf-8");
7483
+ }
7484
+ }
7485
+ generateCommandContent(command) {
7486
+ const examples = command.examples.map((e) => {
7487
+ const prefixed = e.replace(/\//g, "/ak_cm_");
7488
+ return `- \`${prefixed}\``;
7489
+ }).join("\n");
7490
+ return `# Command: /ak_cm_${command.name}
7491
+
7492
+ ## Description
7493
+ ${command.description}
7494
+
7495
+ ## Usage
7496
+ \`${command.usage.replace(/\//g, "/ak_cm_")}\`
7497
+
7498
+ ## Examples
7499
+ ${examples}
7500
+
7501
+ ## \u26A0\uFE0F CRITICAL: The User Has Already Provided Arguments!
7502
+
7503
+ **The user has provided arguments with this command!**
7504
+
7505
+ The arguments are available in this command response - look at the command workflow below, which now includes explicit instructions to use the provided arguments.
7506
+
7507
+ **YOUR JOB**:
7508
+ 1. Follow the command workflow steps
7509
+ 2. The workflow will tell you to look at "Arguments Provided" section
7510
+ 3. Use those arguments - do NOT ask the user for this information!
7511
+ 4. They have already provided it - extract and use it!
7512
+
7513
+ **Example Scenario**:
7514
+ - User runs: \`/ak_cm_${command.name} snake game with html & css\`
7515
+ - Command: \`/ak_cm_${command.name}\`
7516
+ - Arguments to use: \`snake game with html & css\`
7517
+ - You must use "snake game with html & css" as provided in the workflow!
7518
+
7519
+ **DO NOT**: Ask "Please provide a task description"
7520
+ **DO**: Follow the workflow and use the arguments provided in it!
7521
+
7522
+ ## Workflow
7523
+ ${command.content}
7524
+
7525
+ **Category**: ${command.category}`;
7526
+ }
7527
+ generateSkillContent(skill) {
7528
+ const relativePath = skill.filePath.startsWith(process.cwd()) ? skill.filePath.replace(process.cwd(), "").replace(/\\/g, "/").replace(/^\//, "") : `.aikit/skills/${skill.name}.md`;
7529
+ return `Use the **${skill.name} skill** ${skill.useWhen.toLowerCase()}.
7530
+
7531
+ READ ${relativePath}
7532
+
7533
+ ## Description
7534
+ ${skill.description}
7535
+
7536
+ ## When to Use
7537
+ ${skill.useWhen}
7538
+
7539
+ ## Workflow
7540
+ ${skill.content.split("\n").slice(0, 20).join("\n")}${skill.content.split("\n").length > 20 ? "\n\n... (see full skill file for complete workflow)" : ""}
7541
+
7542
+ **IMPORTANT**: Follow this skill's workflow step by step. Do not skip steps.
7543
+ Complete the checklist at the end of the skill.`;
7544
+ }
7545
+ generateAgentContent(agent, nameOverride) {
7546
+ return `---
7547
+ name: ${nameOverride || agent.name}
7548
+ mode: subagent
7549
+ ---
7550
+
7551
+ ${agent.systemPrompt}`;
7552
+ }
7553
+ };
7554
+
7555
+ // src/platform/claude-adapter.ts
7556
+ init_esm_shims();
7557
+ init_paths();
7558
+ import { writeFile as writeFile11, mkdir as mkdir11 } from "fs/promises";
7559
+ import { join as join16 } from "path";
7560
+ import matter4 from "gray-matter";
7561
+ var ClaudeAdapter = class {
7562
+ platform = "claude" /* CLAUDE */;
7563
+ displayName = "Claude Code CLI";
7564
+ getCommandsDir() {
7565
+ return paths.claudeCommands(true);
7566
+ }
7567
+ getSkillsDir() {
7568
+ return paths.claudeSkills(true);
7569
+ }
7570
+ getAgentsDir() {
7571
+ return paths.claudeAgents(true);
7572
+ }
7573
+ async transformCommand(command) {
7574
+ const name = command.name;
7575
+ const content = this.generateCommandContent(command);
7576
+ return { name, content };
7577
+ }
7578
+ async transformSkill(skill) {
7579
+ const name = skill.name;
7580
+ const content = this.generateSkillContent(skill);
7581
+ return {
7582
+ name,
7583
+ directory: name,
7584
+ files: { "SKILL.md": content }
7585
+ };
7586
+ }
7587
+ async transformAgent(agent) {
7588
+ const name = agent.name;
7589
+ const content = this.generateAgentContent(agent);
7590
+ return { name, content };
7591
+ }
7592
+ async installCommand(name, content) {
7593
+ const dir = this.getCommandsDir();
7594
+ await mkdir11(dir, { recursive: true });
7595
+ await writeFile11(join16(dir, `${name}.md`), content);
7596
+ }
7597
+ async installSkill(_name, directory, files) {
7598
+ const baseDir = this.getSkillsDir();
7599
+ const targetDir = join16(baseDir, directory);
7600
+ await mkdir11(targetDir, { recursive: true });
7601
+ for (const [filename, content] of Object.entries(files)) {
7602
+ await writeFile11(join16(targetDir, filename), content);
7603
+ }
7604
+ }
7605
+ async installAgent(name, content) {
7606
+ const dir = this.getAgentsDir();
7607
+ await mkdir11(dir, { recursive: true });
7608
+ await writeFile11(join16(dir, `${name}.md`), content);
7609
+ }
7610
+ generateCommandContent(command) {
7611
+ let workflow = command.content;
7612
+ workflow = workflow.replace(/## ⚠️ CRITICAL: The User Has Already Provided Arguments!.*?(?![\n])?.*/gs, "").replace(/\*\*The user has provided arguments with this command!\*\*/g, "").replace(/\*\*The arguments are available in this command response.*?\*\*/g, "").replace(/\*\*YOUR JOB\*\*:.*/gs, "").replace(/1\. Follow command workflow steps.*?\n2\. The workflow will tell you.*?\n3\. Use those arguments.*?\n4\. They have already provided it.*?\n5\. DO NOT ask.*?\n6\. DO: Follow workflow.*?\n+\**Example Scenario\*\*:.*/gs, "").replace(/\*\*User runs:.*?\*\*:\n.*?\n+- Command:.*?\n+- Arguments to use:.*?\n+- You must use.*?\n+- DO NOT:.*?\n+- DO:.*?\n+\*\*\*/g, "").replace(/\*\*\*/g, "");
7613
+ workflow = workflow.replace(/^# Command: \/ak_cm_[\s-]+\n+/g, "");
7614
+ workflow = workflow.replace(/\$ARGUMENTS/g, "$ARGUMENTS").replace(/\$1/g, "$1").replace(/\$2/g, "$2");
7615
+ const frontmatter = {
7616
+ description: command.description,
7617
+ argumentHint: command.usage.replace(/^\//, "").replace(/<[^>]+>/g, "[args]")
7618
+ };
7619
+ return matter4.stringify(workflow, frontmatter);
7620
+ }
7621
+ generateSkillContent(skill) {
7622
+ const frontmatter = {
7623
+ name: skill.name,
7624
+ description: `${skill.description}. ${skill.useWhen}`
7625
+ };
7626
+ const content = `# ${skill.name}
7627
+
7628
+ ## When to Use
7629
+ ${skill.useWhen}
7630
+
7631
+ ## Description
7632
+ ${skill.description}
7633
+
7634
+ ## Workflow
7635
+ ${skill.content}
7636
+
7637
+ ## Tips
7638
+ - Use this skill when: ${skill.useWhen.toLowerCase()}
7639
+ - Category: ${skill.category}
7640
+ - Tags: ${skill.tags.join(", ")}`;
7641
+ return matter4.stringify(content, frontmatter);
7642
+ }
7643
+ generateAgentContent(agent) {
7644
+ const frontmatter = {
7645
+ name: agent.name,
7646
+ description: agent.useWhen,
7647
+ tools: ["Read", "Edit", "Bash", "Grep", "Glob"]
7648
+ // Default tools
7649
+ };
7650
+ return matter4.stringify(agent.systemPrompt, frontmatter);
7651
+ }
7652
+ };
7653
+
7654
+ // src/platform/adapters.ts
7655
+ function createAdapter(platform) {
7656
+ switch (platform) {
7657
+ case "opencode" /* OPENCODE */:
7658
+ return new OpenCodeAdapter();
7659
+ case "claude" /* CLAUDE */:
7660
+ return new ClaudeAdapter();
7661
+ default:
7662
+ throw new Error(`Unsupported platform: ${platform}`);
7663
+ }
7664
+ }
7665
+ var SUPPORTED_PLATFORMS = [
7666
+ { platform: "opencode" /* OPENCODE */, name: "OpenCode" },
7667
+ { platform: "claude" /* CLAUDE */, name: "Claude Code CLI" }
7668
+ ];
5319
7669
 
5320
7670
  // src/cli/commands/init.ts
5321
7671
  function registerInitCommand(program2) {
5322
- program2.command("init").description("Initialize AIKit configuration").option("-g, --global", "Initialize global configuration").option("-p, --project", "Initialize project-level configuration").action(async (options) => {
7672
+ program2.command("init [platform]").description("Initialize AIKit configuration for a specific platform").option("-g, --global", "Initialize global configuration").option("-p, --project", "Initialize project-level configuration").action(async (platformArg, options) => {
5323
7673
  const configDir = options.global ? paths.globalConfig() : paths.projectConfig();
5324
7674
  console.log(chalk2.bold("\n\u{1F680} AIKit Setup\n"));
5325
7675
  logger.info(`Initializing AIKit in ${configDir}...`);
@@ -5327,91 +7677,54 @@ function registerInitCommand(program2) {
5327
7677
  await initializeConfig(configDir, options.global);
5328
7678
  logger.success("\u2713 Configuration created");
5329
7679
  if (!options.global) {
7680
+ let selectedPlatform;
7681
+ if (platformArg) {
7682
+ selectedPlatform = CliDetector.matchPlatform(platformArg);
7683
+ } else {
7684
+ const platforms = await CliDetector.detectPlatforms();
7685
+ const installed = CliDetector.filterInstalledPlatforms(platforms);
7686
+ console.log(chalk2.bold("\n\u{1F50D} Available CLI Tools\n"));
7687
+ for (const p of platforms) {
7688
+ const status = p.installed ? chalk2.green("\u2713") : chalk2.gray("\u25CB");
7689
+ console.log(` ${status} ${p.displayName}`);
7690
+ }
7691
+ const { platform } = await inquirer.prompt([
7692
+ {
7693
+ type: "list",
7694
+ name: "platform",
7695
+ message: "Which CLI tool do you want to configure AIKit for?",
7696
+ choices: platforms.map((p) => ({
7697
+ name: p.displayName,
7698
+ value: p.platform
7699
+ })),
7700
+ default: installed[0]?.platform || "opencode" /* OPENCODE */
7701
+ }
7702
+ ]);
7703
+ selectedPlatform = platform;
7704
+ }
7705
+ logger.info(`Selected platform: ${selectedPlatform}`);
5330
7706
  const config = await loadConfig();
5331
7707
  const engine = new SkillEngine(config);
5332
7708
  const result = await engine.syncSkillsToProject();
5333
7709
  if (result.count > 0) {
5334
7710
  logger.success(`\u2713 Synced ${result.count} skills`);
5335
7711
  }
5336
- console.log(chalk2.bold("\n\u{1F50D} Checking CLI tools...\n"));
5337
- const cliTools = await CliDetector.checkAll();
5338
- const installableTools = CliDetector.filterInstallable(cliTools);
5339
- for (const tool of cliTools) {
5340
- const status = tool.installed ? chalk2.green("\u2713 Installed") : chalk2.yellow("\u2717 Not installed");
5341
- const version = tool.version ? chalk2.gray(` (${tool.version})`) : "";
5342
- console.log(` ${status} ${chalk2.cyan(tool.displayName)}${version}`);
5343
- }
5344
- if (installableTools.length > 0) {
5345
- console.log();
5346
- const { action } = await inquirer.prompt([
5347
- {
5348
- type: "list",
5349
- name: "action",
5350
- message: "How would you like to proceed?",
5351
- choices: [
5352
- {
5353
- name: "all",
5354
- value: "all",
5355
- short: "a",
5356
- message: "Install all missing CLI tools"
5357
- },
5358
- {
5359
- name: "select",
5360
- value: "select",
5361
- short: "s",
5362
- message: "Select specific tools to install (use space to select, Enter to confirm)"
5363
- },
5364
- {
5365
- name: "skip",
5366
- value: "skip",
5367
- short: "n",
5368
- message: "Skip CLI tool installation"
5369
- }
5370
- ],
5371
- default: "all"
5372
- }
5373
- ]);
5374
- if (action === "skip") {
5375
- console.log();
5376
- logger.info("Skipping CLI tool installation");
5377
- } else if (action === "all") {
5378
- console.log();
5379
- logger.info(`Installing ${installableTools.length} CLI tool(s)...`);
5380
- for (const tool of installableTools) {
5381
- await installCliTool(tool);
5382
- }
5383
- console.log();
5384
- logger.success("\u2713 CLI tools installed");
5385
- } else {
5386
- const { installTools } = await inquirer.prompt([
7712
+ if (selectedPlatform === "claude" /* CLAUDE */) {
7713
+ const cliTools = await CliDetector.checkAll();
7714
+ const claudeTool = cliTools.find((t) => t.name === "claude" /* CLAUDE */);
7715
+ if (claudeTool && !claudeTool.installed) {
7716
+ const { installClaude } = await inquirer.prompt([
5387
7717
  {
5388
- type: "checkbox",
5389
- name: "installTools",
5390
- message: "Select CLI tools to install (press Enter to skip):",
5391
- choices: installableTools.map((tool) => ({
5392
- name: tool.name,
5393
- value: tool,
5394
- checked: true
5395
- // Default to install all
5396
- }))
7718
+ type: "confirm",
7719
+ name: "installClaude",
7720
+ message: "Claude Code CLI is not installed. Install now?",
7721
+ default: true
5397
7722
  }
5398
7723
  ]);
5399
- if (installTools.length > 0) {
5400
- console.log();
5401
- logger.info(`Installing ${installTools.length} CLI tool(s)...`);
5402
- for (const tool of installTools) {
5403
- await installCliTool(tool);
5404
- }
5405
- console.log();
5406
- logger.success("\u2713 CLI tools installed");
5407
- } else {
5408
- console.log();
5409
- logger.info("Skipping CLI tool installation");
7724
+ if (installClaude) {
7725
+ await installCliTool(claudeTool);
5410
7726
  }
5411
7727
  }
5412
- } else {
5413
- console.log();
5414
- logger.success("\u2713 All CLI tools already installed");
5415
7728
  }
5416
7729
  const beads = new BeadsIntegration();
5417
7730
  const beadsStatus = await beads.getStatus();
@@ -5428,18 +7741,15 @@ function registerInitCommand(program2) {
5428
7741
  logger.info("Setting up git hooks...");
5429
7742
  await beads.setupGitHooks();
5430
7743
  logger.success("\u2713 Git hooks configured");
5431
- const opencodePath = paths.opencodeConfig();
5432
- await installToOpenCode(opencodePath);
7744
+ const adapter = createAdapter(selectedPlatform);
7745
+ logger.info(`Installing AIKit for ${adapter.displayName}...`);
7746
+ await installToPlatform(adapter, config);
5433
7747
  console.log(chalk2.bold("\n\u2728 AIKit is ready!\n"));
5434
- console.log("Usage in OpenCode:");
5435
- console.log(chalk2.cyan(" /skills") + " - List all available skills");
5436
- console.log(chalk2.cyan(" /plan") + " - Create implementation plan");
5437
- console.log(chalk2.cyan(" /tdd") + " - Test-driven development");
5438
- console.log(chalk2.cyan(" /debug") + " - Systematic debugging");
5439
- console.log(chalk2.cyan(" /review") + " - Code review checklist");
5440
- console.log(chalk2.cyan(" /git") + " - Git workflow");
5441
- console.log(chalk2.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
5442
- console.log("\nPress " + chalk2.bold("Ctrl+K") + " in OpenCode to see all commands.\n");
7748
+ if (selectedPlatform === "opencode" /* OPENCODE */) {
7749
+ showOpenCodeUsage();
7750
+ } else if (selectedPlatform === "claude" /* CLAUDE */) {
7751
+ showClaudeUsage();
7752
+ }
5443
7753
  }
5444
7754
  } catch (error) {
5445
7755
  logger.error("Failed to initialize AIKit:", error);
@@ -5447,18 +7757,121 @@ function registerInitCommand(program2) {
5447
7757
  }
5448
7758
  });
5449
7759
  }
7760
+ async function installToPlatform(adapter, config) {
7761
+ const skillEngine = new SkillEngine(config);
7762
+ const commandRunner = new CommandRunner(config);
7763
+ const agentManager = new AgentManager(config);
7764
+ const skills = await skillEngine.listSkills();
7765
+ const commands = await commandRunner.listCommands();
7766
+ const agents = await agentManager.listAgents();
7767
+ logger.info(`Installing ${commands.length} commands...`);
7768
+ for (const command of commands) {
7769
+ const { name, content } = await adapter.transformCommand(command);
7770
+ await adapter.installCommand(name, content);
7771
+ logger.info(` \u2713 Created ${name} command`);
7772
+ }
7773
+ logger.info(`Installing ${skills.length} skills...`);
7774
+ for (const skill of skills) {
7775
+ const { name, directory, files } = await adapter.transformSkill(skill);
7776
+ await adapter.installSkill(name, directory, files);
7777
+ logger.info(` \u2713 Created ${name} skill`);
7778
+ }
7779
+ logger.info(`Installing ${agents.length} agents...`);
7780
+ for (const agent of agents) {
7781
+ const { name, content } = await adapter.transformAgent(agent);
7782
+ await adapter.installAgent(name, content);
7783
+ logger.info(` \u2713 Created ${name} agent`);
7784
+ }
7785
+ }
7786
+ function showOpenCodeUsage() {
7787
+ console.log("Usage in OpenCode:");
7788
+ console.log(chalk2.cyan(" /skills") + " - List all available skills");
7789
+ console.log(chalk2.cyan(" /plan") + " - Create implementation plan");
7790
+ console.log(chalk2.cyan(" /tdd") + " - Test-driven development");
7791
+ console.log(chalk2.cyan(" /debug") + " - Systematic debugging");
7792
+ console.log(chalk2.cyan(" /review") + " - Code review checklist");
7793
+ console.log(chalk2.cyan(" /git") + " - Git workflow");
7794
+ console.log(chalk2.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
7795
+ console.log("\nPress " + chalk2.bold("Ctrl+K") + " in OpenCode to see all commands.\n");
7796
+ }
7797
+ function showClaudeUsage() {
7798
+ console.log("Usage in Claude Code CLI:");
7799
+ console.log(chalk2.cyan(" /help") + " - List all available commands");
7800
+ console.log(chalk2.cyan(" /plan") + " - Create implementation plan");
7801
+ console.log(chalk2.cyan(" /implement") + " - Implement a task");
7802
+ console.log(chalk2.cyan(" /test") + " - Run tests");
7803
+ console.log("\nType " + chalk2.bold('"/help"') + " in Claude to see all commands.\n");
7804
+ }
5450
7805
 
5451
7806
  // src/cli/commands/install.ts
5452
7807
  init_esm_shims();
5453
7808
  init_logger();
5454
- init_paths();
7809
+ import inquirer2 from "inquirer";
7810
+ init_config();
5455
7811
  function registerInstallCommand(program2) {
5456
- program2.command("install").description("Install AIKit to OpenCode configuration").action(async () => {
5457
- logger.info("Installing AIKit to OpenCode...");
7812
+ program2.command("install [platform]").description("Install AIKit to specific CLI tool configuration").action(async (platformArg) => {
5458
7813
  try {
5459
- const opencodePath = paths.opencodeConfig();
5460
- await installToOpenCode(opencodePath);
5461
- logger.success("AIKit installed to OpenCode!");
7814
+ let selectedPlatform;
7815
+ if (platformArg) {
7816
+ selectedPlatform = CliDetector.matchPlatform(platformArg);
7817
+ if (!selectedPlatform) {
7818
+ logger.error(`Unknown platform: ${platformArg}`);
7819
+ logger.info(`Supported platforms: ${Object.values(CliPlatform).join(", ")}`);
7820
+ process.exit(1);
7821
+ }
7822
+ } else {
7823
+ const platforms = await CliDetector.detectPlatforms();
7824
+ const installedPlatforms = CliDetector.filterInstalledPlatforms(platforms);
7825
+ const defaultPlatform = installedPlatforms.length > 0 ? installedPlatforms[0].platform : platforms[0]?.platform;
7826
+ const { platform } = await inquirer2.prompt([
7827
+ {
7828
+ type: "list",
7829
+ name: "platform",
7830
+ message: "Which CLI tool do you want to install AIKit for?",
7831
+ choices: platforms.map((p) => ({
7832
+ name: p.displayName,
7833
+ value: p.platform
7834
+ })),
7835
+ default: defaultPlatform
7836
+ }
7837
+ ]);
7838
+ selectedPlatform = platform;
7839
+ }
7840
+ logger.info(`Installing AIKit for ${selectedPlatform}...`);
7841
+ const config = await loadConfig();
7842
+ const adapter = createAdapter(selectedPlatform);
7843
+ const skillEngine = config.skills.enabled ? new SkillEngine(config) : null;
7844
+ const commandRunner = config.commands.enabled ? new CommandRunner(config) : null;
7845
+ const agentManager = config.agents.enabled ? new AgentManager(config) : null;
7846
+ if (commandRunner) {
7847
+ const commands = await commandRunner.listCommands();
7848
+ logger.info(`Installing ${commands.length} commands...`);
7849
+ for (const command of commands) {
7850
+ const { name, content } = await adapter.transformCommand(command);
7851
+ await adapter.installCommand(name, content);
7852
+ logger.info(` \u2713 Created ${name} command`);
7853
+ }
7854
+ }
7855
+ if (skillEngine) {
7856
+ const skills = await skillEngine.listSkills();
7857
+ logger.info(`Installing ${skills.length} skills...`);
7858
+ for (const skill of skills) {
7859
+ const { name, directory, files } = await adapter.transformSkill(skill);
7860
+ await adapter.installSkill(name, directory, files);
7861
+ logger.info(` \u2713 Created ${name} skill`);
7862
+ }
7863
+ }
7864
+ if (agentManager) {
7865
+ const agents = await agentManager.listAgents();
7866
+ logger.info(`Installing ${agents.length} agents...`);
7867
+ for (const agent of agents) {
7868
+ const { name, content } = await adapter.transformAgent(agent);
7869
+ await adapter.installAgent(name, content);
7870
+ logger.info(` \u2713 Created ${name} agent`);
7871
+ }
7872
+ }
7873
+ logger.success(`
7874
+ \u2713 AIKit installed to ${adapter.displayName}!`);
5462
7875
  } catch (error) {
5463
7876
  logger.error("Failed to install:", error);
5464
7877
  process.exit(1);
@@ -5473,17 +7886,17 @@ import chalk4 from "chalk";
5473
7886
 
5474
7887
  // src/core/sync-engine.ts
5475
7888
  init_esm_shims();
5476
- import { readFile as readFile11, writeFile as writeFile12, copyFile, mkdir as mkdir10 } from "fs/promises";
5477
- import { join as join17, dirname as dirname4 } from "path";
5478
- import inquirer2 from "inquirer";
7889
+ import { readFile as readFile13, writeFile as writeFile15, copyFile, mkdir as mkdir13 } from "fs/promises";
7890
+ import { join as join20, dirname as dirname4 } from "path";
7891
+ import inquirer3 from "inquirer";
5479
7892
  import chalk3 from "chalk";
5480
7893
 
5481
7894
  // src/core/version-manager.ts
5482
7895
  init_esm_shims();
5483
7896
  init_paths();
5484
7897
  init_logger();
5485
- import { readFile as readFile8, readdir as readdir7, writeFile as writeFile9, stat } from "fs/promises";
5486
- import { join as join14 } from "path";
7898
+ import { readFile as readFile10, readdir as readdir8, writeFile as writeFile12, stat } from "fs/promises";
7899
+ import { join as join17 } from "path";
5487
7900
  import { createHash } from "crypto";
5488
7901
  var VersionManager = class {
5489
7902
  config;
@@ -5494,9 +7907,9 @@ var VersionManager = class {
5494
7907
  * Get current installed version
5495
7908
  */
5496
7909
  async getCurrentVersion() {
5497
- const versionPath = join14(paths.globalConfig(), ".version.json");
7910
+ const versionPath = join17(paths.globalConfig(), ".version.json");
5498
7911
  try {
5499
- const content = await readFile8(versionPath, "utf-8");
7912
+ const content = await readFile10(versionPath, "utf-8");
5500
7913
  return JSON.parse(content);
5501
7914
  } catch {
5502
7915
  return null;
@@ -5507,7 +7920,7 @@ var VersionManager = class {
5507
7920
  */
5508
7921
  getPackageVersion() {
5509
7922
  try {
5510
- const packageJson = __require(join14(process.cwd(), "package.json"));
7923
+ const packageJson = __require(join17(process.cwd(), "package.json"));
5511
7924
  return packageJson.version || "0.0.0";
5512
7925
  } catch {
5513
7926
  return "0.0.0";
@@ -5565,9 +7978,9 @@ var VersionManager = class {
5565
7978
  const removedSkills = [];
5566
7979
  const conflicts = [];
5567
7980
  const installedSkills = /* @__PURE__ */ new Map();
5568
- const installedPath = join14(paths.globalConfig(), ".installed-skills.json");
7981
+ const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
5569
7982
  try {
5570
- const installedData = await readFile8(installedPath, "utf-8");
7983
+ const installedData = await readFile10(installedPath, "utf-8");
5571
7984
  const installedList = JSON.parse(installedData);
5572
7985
  installedList.forEach((skill) => {
5573
7986
  installedSkills.set(skill.name, skill);
@@ -5615,9 +8028,9 @@ var VersionManager = class {
5615
8028
  const hashes = [];
5616
8029
  try {
5617
8030
  const loadFromDir = async (dir) => {
5618
- const files = await readdir7(dir);
8031
+ const files = await readdir8(dir);
5619
8032
  for (const file of files) {
5620
- const filePath = join14(dir, file);
8033
+ const filePath = join17(dir, file);
5621
8034
  const stats = await stat(filePath);
5622
8035
  if (stats.isDirectory()) {
5623
8036
  await loadFromDir(filePath);
@@ -5643,7 +8056,7 @@ var VersionManager = class {
5643
8056
  */
5644
8057
  async calculateSkillHash(filePath) {
5645
8058
  try {
5646
- const content = await readFile8(filePath, "utf-8");
8059
+ const content = await readFile10(filePath, "utf-8");
5647
8060
  return createHash("sha256").update(content).digest("hex");
5648
8061
  } catch {
5649
8062
  return "";
@@ -5664,9 +8077,9 @@ var VersionManager = class {
5664
8077
  * Save installed skills info
5665
8078
  */
5666
8079
  async saveInstalledSkills(skills) {
5667
- const installedPath = join14(paths.globalConfig(), ".installed-skills.json");
8080
+ const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
5668
8081
  try {
5669
- await writeFile9(installedPath, JSON.stringify(skills, null, 2));
8082
+ await writeFile12(installedPath, JSON.stringify(skills, null, 2));
5670
8083
  } catch (error) {
5671
8084
  logger.error("Failed to save installed skills info:", error);
5672
8085
  }
@@ -5687,8 +8100,8 @@ var VersionManager = class {
5687
8100
  packageVersion: this.getPackageVersion(),
5688
8101
  migrationHistory: migration ? [...current.migrationHistory, migration] : current.migrationHistory
5689
8102
  };
5690
- const versionPath = join14(paths.globalConfig(), ".version.json");
5691
- await writeFile9(versionPath, JSON.stringify(updated, null, 2));
8103
+ const versionPath = join17(paths.globalConfig(), ".version.json");
8104
+ await writeFile12(versionPath, JSON.stringify(updated, null, 2));
5692
8105
  }
5693
8106
  /**
5694
8107
  * Check if migration is needed
@@ -5703,8 +8116,8 @@ var VersionManager = class {
5703
8116
  // src/core/backup-manager.ts
5704
8117
  init_esm_shims();
5705
8118
  init_logger();
5706
- import { readFile as readFile9, writeFile as writeFile10, readdir as readdir8, stat as stat2, unlink, mkdir as mkdir9 } from "fs/promises";
5707
- import { join as join15, dirname as dirname3 } from "path";
8119
+ import { readFile as readFile11, writeFile as writeFile13, readdir as readdir9, stat as stat2, unlink, mkdir as mkdir12 } from "fs/promises";
8120
+ import { join as join18, dirname as dirname3 } from "path";
5708
8121
  import { createHash as createHash2 } from "crypto";
5709
8122
  var BackupManager = class {
5710
8123
  configPath;
@@ -5712,7 +8125,7 @@ var BackupManager = class {
5712
8125
  maxBackups;
5713
8126
  constructor(configPath, maxBackups = 5) {
5714
8127
  this.configPath = configPath;
5715
- this.backupsDir = join15(configPath, ".backups");
8128
+ this.backupsDir = join18(configPath, ".backups");
5716
8129
  this.maxBackups = maxBackups;
5717
8130
  }
5718
8131
  /**
@@ -5720,10 +8133,10 @@ var BackupManager = class {
5720
8133
  */
5721
8134
  async createBackup(fromVersion, toVersion) {
5722
8135
  try {
5723
- await mkdir9(this.backupsDir, { recursive: true });
8136
+ await mkdir12(this.backupsDir, { recursive: true });
5724
8137
  const backupId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
5725
- const backupPath = join15(this.backupsDir, `${backupId}-v${toVersion}`);
5726
- await mkdir9(backupPath, { recursive: true });
8138
+ const backupPath = join18(this.backupsDir, `${backupId}-v${toVersion}`);
8139
+ await mkdir12(backupPath, { recursive: true });
5727
8140
  logger.info(`Creating backup: ${backupPath}`);
5728
8141
  const files = [];
5729
8142
  const backupItems = [
@@ -5744,8 +8157,8 @@ var BackupManager = class {
5744
8157
  files,
5745
8158
  success: true
5746
8159
  };
5747
- const manifestPath = join15(backupPath, "backup-manifest.json");
5748
- await writeFile10(manifestPath, JSON.stringify(manifest, null, 2));
8160
+ const manifestPath = join18(backupPath, "backup-manifest.json");
8161
+ await writeFile13(manifestPath, JSON.stringify(manifest, null, 2));
5749
8162
  await this.cleanupOldBackups();
5750
8163
  logger.success(`\u2713 Backup created: ${backupId}`);
5751
8164
  return backupId;
@@ -5758,20 +8171,20 @@ var BackupManager = class {
5758
8171
  * Backup a file or directory
5759
8172
  */
5760
8173
  async backupItem(sourceDir, item, targetDir) {
5761
- const sourcePath = join15(sourceDir, item);
5762
- const targetPath = join15(targetDir, item);
8174
+ const sourcePath = join18(sourceDir, item);
8175
+ const targetPath = join18(targetDir, item);
5763
8176
  const files = [];
5764
8177
  try {
5765
8178
  const stats = await stat2(sourcePath);
5766
8179
  if (stats.isDirectory()) {
5767
- await mkdir9(targetPath, { recursive: true });
5768
- const entries = await readdir8(sourcePath);
8180
+ await mkdir12(targetPath, { recursive: true });
8181
+ const entries = await readdir9(sourcePath);
5769
8182
  for (const entry of entries) {
5770
8183
  const entryFiles = await this.backupItem(sourcePath, entry, targetPath);
5771
8184
  files.push(...entryFiles);
5772
8185
  }
5773
8186
  } else if (stats.isFile()) {
5774
- await mkdir9(dirname3(targetPath), { recursive: true });
8187
+ await mkdir12(dirname3(targetPath), { recursive: true });
5775
8188
  await this.copyFile(sourcePath, targetPath);
5776
8189
  const hash = await this.calculateHash(targetPath);
5777
8190
  files.push({
@@ -5789,15 +8202,15 @@ var BackupManager = class {
5789
8202
  * Copy file with hash calculation
5790
8203
  */
5791
8204
  async copyFile(source, target) {
5792
- const content = await readFile9(source);
5793
- await writeFile10(target, content);
8205
+ const content = await readFile11(source);
8206
+ await writeFile13(target, content);
5794
8207
  }
5795
8208
  /**
5796
8209
  * Calculate file hash
5797
8210
  */
5798
8211
  async calculateHash(filePath) {
5799
8212
  try {
5800
- const content = await readFile9(filePath);
8213
+ const content = await readFile11(filePath);
5801
8214
  return createHash2("sha256").update(content).digest("hex");
5802
8215
  } catch {
5803
8216
  return "";
@@ -5808,13 +8221,13 @@ var BackupManager = class {
5808
8221
  */
5809
8222
  async listBackups() {
5810
8223
  try {
5811
- const entries = await readdir8(this.backupsDir);
8224
+ const entries = await readdir9(this.backupsDir);
5812
8225
  const backups = [];
5813
8226
  for (const entry of entries) {
5814
- const backupPath = join15(this.backupsDir, entry);
5815
- const manifestPath = join15(backupPath, "backup-manifest.json");
8227
+ const backupPath = join18(this.backupsDir, entry);
8228
+ const manifestPath = join18(backupPath, "backup-manifest.json");
5816
8229
  try {
5817
- const manifestContent = await readFile9(manifestPath, "utf-8");
8230
+ const manifestContent = await readFile11(manifestPath, "utf-8");
5818
8231
  const manifest = JSON.parse(manifestContent);
5819
8232
  const size = await this.calculateBackupSize(backupPath);
5820
8233
  backups.push({
@@ -5840,9 +8253,9 @@ var BackupManager = class {
5840
8253
  let totalSize = 0;
5841
8254
  try {
5842
8255
  const calculate = async (dir) => {
5843
- const entries = await readdir8(dir);
8256
+ const entries = await readdir9(dir);
5844
8257
  for (const entry of entries) {
5845
- const entryPath = join15(dir, entry);
8258
+ const entryPath = join18(dir, entry);
5846
8259
  const stats = await stat2(entryPath);
5847
8260
  if (stats.isDirectory()) {
5848
8261
  await calculate(entryPath);
@@ -5874,9 +8287,9 @@ var BackupManager = class {
5874
8287
  return false;
5875
8288
  }
5876
8289
  for (const file of backup.manifest.files) {
5877
- const sourcePath = join15(backup.path, file.path);
5878
- const targetPath = join15(this.configPath, file.path);
5879
- await mkdir9(dirname3(targetPath), { recursive: true });
8290
+ const sourcePath = join18(backup.path, file.path);
8291
+ const targetPath = join18(this.configPath, file.path);
8292
+ await mkdir12(dirname3(targetPath), { recursive: true });
5880
8293
  await this.copyFile(sourcePath, targetPath);
5881
8294
  }
5882
8295
  logger.success(`\u2713 Backup restored: ${backupId}`);
@@ -5891,10 +8304,10 @@ var BackupManager = class {
5891
8304
  */
5892
8305
  async validateBackup(backup) {
5893
8306
  try {
5894
- const manifestPath = join15(backup.path, "backup-manifest.json");
5895
- await readFile9(manifestPath, "utf-8");
8307
+ const manifestPath = join18(backup.path, "backup-manifest.json");
8308
+ await readFile11(manifestPath, "utf-8");
5896
8309
  for (const file of backup.manifest.files) {
5897
- const filePath = join15(backup.path, file.path);
8310
+ const filePath = join18(backup.path, file.path);
5898
8311
  await stat2(filePath);
5899
8312
  const currentHash = await this.calculateHash(filePath);
5900
8313
  if (currentHash !== file.hash) {
@@ -5918,9 +8331,9 @@ var BackupManager = class {
5918
8331
  if (!backup) {
5919
8332
  return false;
5920
8333
  }
5921
- const entries = await readdir8(backup.path);
8334
+ const entries = await readdir9(backup.path);
5922
8335
  for (const entry of entries) {
5923
- const entryPath = join15(backup.path, entry);
8336
+ const entryPath = join18(backup.path, entry);
5924
8337
  const stats = await stat2(entryPath);
5925
8338
  if (stats.isDirectory()) {
5926
8339
  await this.removeDirectory(entryPath);
@@ -5939,9 +8352,9 @@ var BackupManager = class {
5939
8352
  * Remove directory recursively
5940
8353
  */
5941
8354
  async removeDirectory(dirPath) {
5942
- const entries = await readdir8(dirPath);
8355
+ const entries = await readdir9(dirPath);
5943
8356
  for (const entry of entries) {
5944
- const entryPath = join15(dirPath, entry);
8357
+ const entryPath = join18(dirPath, entry);
5945
8358
  const stats = await stat2(entryPath);
5946
8359
  if (stats.isDirectory()) {
5947
8360
  await this.removeDirectory(entryPath);
@@ -5987,14 +8400,14 @@ var BackupManager = class {
5987
8400
  // src/core/migration-manager.ts
5988
8401
  init_esm_shims();
5989
8402
  init_logger();
5990
- import { readFile as readFile10, writeFile as writeFile11, readdir as readdir9 } from "fs/promises";
5991
- import { join as join16 } from "path";
8403
+ import { readFile as readFile12, writeFile as writeFile14, readdir as readdir10 } from "fs/promises";
8404
+ import { join as join19 } from "path";
5992
8405
  var MigrationManager = class {
5993
8406
  configPath;
5994
8407
  migrationsDir;
5995
8408
  constructor(configPath) {
5996
8409
  this.configPath = configPath;
5997
- this.migrationsDir = join16(process.cwd(), "src/core/migrations");
8410
+ this.migrationsDir = join19(process.cwd(), "src/core/migrations");
5998
8411
  }
5999
8412
  /**
6000
8413
  * Load all available migrations
@@ -6002,11 +8415,11 @@ var MigrationManager = class {
6002
8415
  async loadMigrations() {
6003
8416
  const migrations = [];
6004
8417
  try {
6005
- const files = await readdir9(this.migrationsDir);
8418
+ const files = await readdir10(this.migrationsDir);
6006
8419
  for (const file of files) {
6007
8420
  if (file.endsWith(".js") && file.startsWith("migrate-")) {
6008
8421
  try {
6009
- const module = await import(join16(this.migrationsDir, file));
8422
+ const module = await import(join19(this.migrationsDir, file));
6010
8423
  const migration = module.default || module.migration;
6011
8424
  if (migration) {
6012
8425
  migrations.push(migration);
@@ -6025,9 +8438,9 @@ var MigrationManager = class {
6025
8438
  * Get applied migrations
6026
8439
  */
6027
8440
  async getAppliedMigrations() {
6028
- const migrationHistoryPath = join16(this.configPath, ".migration-history.json");
8441
+ const migrationHistoryPath = join19(this.configPath, ".migration-history.json");
6029
8442
  try {
6030
- const content = await readFile10(migrationHistoryPath, "utf-8");
8443
+ const content = await readFile12(migrationHistoryPath, "utf-8");
6031
8444
  const history = JSON.parse(content);
6032
8445
  return history.filter((m) => m.status === "completed").map((m) => m.to);
6033
8446
  } catch {
@@ -6113,16 +8526,16 @@ var MigrationManager = class {
6113
8526
  * Update migration history
6114
8527
  */
6115
8528
  async updateMigrationHistory(entries) {
6116
- const historyPath = join16(this.configPath, ".migration-history.json");
8529
+ const historyPath = join19(this.configPath, ".migration-history.json");
6117
8530
  try {
6118
8531
  let history = [];
6119
8532
  try {
6120
- const content = await readFile10(historyPath, "utf-8");
8533
+ const content = await readFile12(historyPath, "utf-8");
6121
8534
  history = JSON.parse(content);
6122
8535
  } catch {
6123
8536
  }
6124
8537
  history.push(...entries);
6125
- await writeFile11(historyPath, JSON.stringify(history, null, 2));
8538
+ await writeFile14(historyPath, JSON.stringify(history, null, 2));
6126
8539
  } catch (error) {
6127
8540
  logger.error("Failed to update migration history:", error);
6128
8541
  }
@@ -6131,14 +8544,14 @@ var MigrationManager = class {
6131
8544
  * Update migration history status
6132
8545
  */
6133
8546
  async updateMigrationHistoryStatus(version, status) {
6134
- const historyPath = join16(this.configPath, ".migration-history.json");
8547
+ const historyPath = join19(this.configPath, ".migration-history.json");
6135
8548
  try {
6136
- const content = await readFile10(historyPath, "utf-8");
8549
+ const content = await readFile12(historyPath, "utf-8");
6137
8550
  const history = JSON.parse(content);
6138
8551
  const updated = history.map(
6139
8552
  (m) => m.to === version ? { ...m, status } : m
6140
8553
  );
6141
- await writeFile11(historyPath, JSON.stringify(updated, null, 2));
8554
+ await writeFile14(historyPath, JSON.stringify(updated, null, 2));
6142
8555
  } catch (error) {
6143
8556
  logger.error("Failed to update migration history status:", error);
6144
8557
  }
@@ -6147,9 +8560,9 @@ var MigrationManager = class {
6147
8560
  * Get migration history
6148
8561
  */
6149
8562
  async getMigrationHistory() {
6150
- const historyPath = join16(this.configPath, ".migration-history.json");
8563
+ const historyPath = join19(this.configPath, ".migration-history.json");
6151
8564
  try {
6152
- const content = await readFile10(historyPath, "utf-8");
8565
+ const content = await readFile12(historyPath, "utf-8");
6153
8566
  return JSON.parse(content);
6154
8567
  } catch {
6155
8568
  return [];
@@ -6237,7 +8650,7 @@ var SyncEngine = class {
6237
8650
  }
6238
8651
  await this.displayChanges(changes);
6239
8652
  if (!options.force) {
6240
- const { confirmed } = await inquirer2.prompt([{
8653
+ const { confirmed } = await inquirer3.prompt([{
6241
8654
  type: "confirm",
6242
8655
  name: "confirmed",
6243
8656
  message: "Continue with update?",
@@ -6318,7 +8731,7 @@ var SyncEngine = class {
6318
8731
  console.log(chalk3.yellow("No backups available"));
6319
8732
  return false;
6320
8733
  }
6321
- const { selectedBackup } = await inquirer2.prompt([{
8734
+ const { selectedBackup } = await inquirer3.prompt([{
6322
8735
  type: "list",
6323
8736
  name: "selectedBackup",
6324
8737
  message: "Select backup to restore:",
@@ -6391,7 +8804,7 @@ var SyncEngine = class {
6391
8804
  \u26A0\uFE0F Conflict detected: ${conflict.skillName}
6392
8805
  `));
6393
8806
  console.log(chalk3.yellow("Your version differs from official version."));
6394
- const { action } = await inquirer2.prompt([{
8807
+ const { action } = await inquirer3.prompt([{
6395
8808
  type: "list",
6396
8809
  name: "action",
6397
8810
  message: "Choose action:",
@@ -6458,19 +8871,19 @@ var SyncEngine = class {
6458
8871
  * Install a skill
6459
8872
  */
6460
8873
  async installSkill(sourceDir, skill, targetDir) {
6461
- const sourcePath = join17(sourceDir, skill.category, `${skill.name}.md`);
6462
- const targetPath = join17(targetDir, skill.category, `${skill.name}.md`);
6463
- await mkdir10(dirname4(targetPath), { recursive: true });
8874
+ const sourcePath = join20(sourceDir, skill.category, `${skill.name}.md`);
8875
+ const targetPath = join20(targetDir, skill.category, `${skill.name}.md`);
8876
+ await mkdir13(dirname4(targetPath), { recursive: true });
6464
8877
  await copyFile(sourcePath, targetPath);
6465
8878
  }
6466
8879
  /**
6467
8880
  * Archive a removed skill
6468
8881
  */
6469
8882
  async archiveSkill(targetDir, skill) {
6470
- const sourcePath = join17(targetDir, skill.category, `${skill.name}.md`);
6471
- const targetPath = join17(targetDir, skill.category, `${skill.name}-deprecated.md`);
8883
+ const sourcePath = join20(targetDir, skill.category, `${skill.name}.md`);
8884
+ const targetPath = join20(targetDir, skill.category, `${skill.name}-deprecated.md`);
6472
8885
  try {
6473
- const content = await readFile11(sourcePath, "utf-8");
8886
+ const content = await readFile13(sourcePath, "utf-8");
6474
8887
  const deprecatedNotice = `---
6475
8888
  \u26A0\uFE0F DEPRECATED: This skill has been removed
6476
8889
 
@@ -6479,8 +8892,8 @@ Reason: Check release notes for replacement
6479
8892
  ---
6480
8893
 
6481
8894
  ${content}`;
6482
- await mkdir10(dirname4(targetPath), { recursive: true });
6483
- await writeFile12(targetPath, deprecatedNotice);
8895
+ await mkdir13(dirname4(targetPath), { recursive: true });
8896
+ await writeFile15(targetPath, deprecatedNotice);
6484
8897
  } catch (error) {
6485
8898
  if (error.code === "ENOENT") {
6486
8899
  console.log(chalk3.yellow(` - ${skill.name} (not found, skipping)`));
@@ -6711,8 +9124,8 @@ async function configureToolAction(toolName) {
6711
9124
  // src/cli/commands/misc.ts
6712
9125
  init_esm_shims();
6713
9126
  import chalk6 from "chalk";
6714
- import { readFile as readFile13, writeFile as writeFile14 } from "fs/promises";
6715
- import { join as join19 } from "path";
9127
+ import { readFile as readFile15, writeFile as writeFile17 } from "fs/promises";
9128
+ import { join as join22 } from "path";
6716
9129
  init_config();
6717
9130
  init_memory();
6718
9131
  init_beads();
@@ -6775,9 +9188,9 @@ function registerModeCommand(program2) {
6775
9188
  console.log(chalk6.red(`Invalid mode. Available modes: ${validModes.join(", ")}`));
6776
9189
  return;
6777
9190
  }
6778
- const configData = JSON.parse(await readFile13(join19(configPath, "aikit.json"), "utf-8"));
9191
+ const configData = JSON.parse(await readFile15(join22(configPath, "aikit.json"), "utf-8"));
6779
9192
  configData.mode = mode;
6780
- await writeFile14(join19(configPath, "aikit.json"), JSON.stringify(configData, null, 2));
9193
+ await writeFile17(join22(configPath, "aikit.json"), JSON.stringify(configData, null, 2));
6781
9194
  console.log(chalk6.green(`\u2713 Mode set to: ${mode}`));
6782
9195
  console.log(chalk6.gray(`Configuration updated at: ${configPath}/aikit.json`));
6783
9196
  } catch (error) {
@@ -6883,8 +9296,36 @@ function registerStatusCommand(program2) {
6883
9296
  });
6884
9297
  }
6885
9298
 
9299
+ // src/cli/commands/session.ts
9300
+ init_esm_shims();
9301
+ function registerSessionCommand(program2) {
9302
+ const sessionCmd = program2.command("session").description("Manage development sessions");
9303
+ sessionCmd.command("start [name]").description("Start a new development session").option("-g, --goals <goals...>", "Session goals").action(async (name, options) => {
9304
+ await startSession(name, options.goals);
9305
+ });
9306
+ sessionCmd.command("update [notes]").description("Add progress notes to current session").action(async (notes) => {
9307
+ await updateSession(notes);
9308
+ });
9309
+ sessionCmd.command("end").description("End current session with summary").action(async () => {
9310
+ await endSession();
9311
+ });
9312
+ sessionCmd.command("current").description("Show current active session").action(async () => {
9313
+ await showCurrentSession();
9314
+ });
9315
+ sessionCmd.command("list").description("List all sessions").action(async () => {
9316
+ await listSessions();
9317
+ });
9318
+ sessionCmd.command("show <sessionId>").description("Show details of a specific session").action(async (sessionId) => {
9319
+ await showSession(sessionId);
9320
+ });
9321
+ sessionCmd.command("search <query>").description("Search sessions by keyword").action(async (query) => {
9322
+ await searchSessions(query);
9323
+ });
9324
+ return sessionCmd;
9325
+ }
9326
+
6886
9327
  // src/cli/index.ts
6887
- var program = new Command();
9328
+ var program = new Command3();
6888
9329
  program.name("aikit").description("Open-source AI coding agent toolkit for OpenCode").version(getVersion());
6889
9330
  registerInitCommand(program);
6890
9331
  registerInstallCommand(program);
@@ -6897,6 +9338,7 @@ registerToolsCommand(program);
6897
9338
  registerPluginsCommand(program);
6898
9339
  registerMemoryCommand(program);
6899
9340
  registerBeadsCommand(program);
9341
+ registerSessionCommand(program);
6900
9342
  registerStatusCommand(program);
6901
9343
  program.parse();
6902
9344
  //# sourceMappingURL=cli.js.map