@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/CHANGELOG.md +9 -0
- package/dist/cli.js +2800 -358
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +1446 -109
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1446 -109
- package/dist/mcp-server.js.map +1 -1
- package/package.json +5 -1
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:
|
|
379
|
-
const files = await
|
|
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
|
|
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
|
|
1567
|
-
import { join as
|
|
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 =
|
|
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
|
|
1679
|
-
const content = await
|
|
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 =
|
|
1690
|
-
await
|
|
1691
|
-
await
|
|
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:
|
|
1739
|
-
const { token } = await
|
|
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:
|
|
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
|
|
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
|
-
|
|
2411
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
2867
|
-
description: "
|
|
2868
|
-
category: "
|
|
2869
|
-
usage: "/
|
|
2870
|
-
examples: [
|
|
2871
|
-
|
|
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
|
-
|
|
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: "
|
|
3081
|
-
description: "
|
|
3082
|
-
category: "
|
|
3083
|
-
usage: "/
|
|
3084
|
-
examples: ["/
|
|
3085
|
-
content: `
|
|
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
|
|
3558
|
+
Optional target branch: $ARGUMENTS
|
|
3090
3559
|
|
|
3091
|
-
1.
|
|
3092
|
-
2.
|
|
3093
|
-
3.
|
|
3094
|
-
4.
|
|
3095
|
-
5.
|
|
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
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
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:
|
|
4653
|
-
const { promisify:
|
|
4654
|
-
const
|
|
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
|
|
6419
|
+
await execAsync3(`osascript -e 'display notification "${summary}" with title "OpenCode Session Complete"'`);
|
|
4659
6420
|
} else if (platform === "linux") {
|
|
4660
|
-
await
|
|
6421
|
+
await execAsync3(`notify-send "OpenCode Session Complete" "${summary}"`);
|
|
4661
6422
|
} else if (platform === "win32") {
|
|
4662
|
-
await
|
|
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
|
|
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 =
|
|
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 (
|
|
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
|
|
4832
|
-
import { mkdir as
|
|
4833
|
-
import { join as
|
|
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
|
|
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
|
|
4873
|
-
|
|
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
|
|
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 =
|
|
4902
|
-
const mcpServerPath =
|
|
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
|
-
|
|
6713
|
+
join14(homedir3(), ".config", "opencode", "opencode.json"),
|
|
4906
6714
|
// Project-level config
|
|
4907
|
-
|
|
6715
|
+
join14(projectPath, ".opencode", "opencode.json"),
|
|
4908
6716
|
// Alternative global location
|
|
4909
|
-
|
|
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 =
|
|
4919
|
-
await
|
|
6726
|
+
const configDir = join14(configPath, "..");
|
|
6727
|
+
await mkdir9(configDir, { recursive: true });
|
|
4920
6728
|
let config = {};
|
|
4921
|
-
if (
|
|
6729
|
+
if (existsSync6(configPath)) {
|
|
4922
6730
|
try {
|
|
4923
|
-
const existing = await
|
|
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
|
|
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 =
|
|
4943
|
-
await
|
|
4944
|
-
await
|
|
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
|
-
|
|
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 =
|
|
5187
|
-
const aikitDir =
|
|
5188
|
-
const opencodeAgentDir =
|
|
5189
|
-
await
|
|
5190
|
-
await
|
|
5191
|
-
await
|
|
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 =
|
|
7012
|
+
const filePath = join14(opencodeAgentDir, `${name}.md`);
|
|
5194
7013
|
try {
|
|
5195
|
-
await
|
|
5196
|
-
const existingContent = await
|
|
7014
|
+
await access5(filePath);
|
|
7015
|
+
const existingContent = await readFile8(filePath, "utf8");
|
|
5197
7016
|
if (!existingContent.includes("mode: subagent")) {
|
|
5198
|
-
const
|
|
5199
|
-
const { data: frontmatter, content: body } =
|
|
7017
|
+
const matter5 = await import("gray-matter");
|
|
7018
|
+
const { data: frontmatter, content: body } = matter5.default(existingContent);
|
|
5200
7019
|
frontmatter.mode = "subagent";
|
|
5201
|
-
const updatedContent =
|
|
5202
|
-
await
|
|
7020
|
+
const updatedContent = matter5.default.stringify(body, frontmatter);
|
|
7021
|
+
await writeFile9(filePath, updatedContent, "utf8");
|
|
5203
7022
|
}
|
|
5204
7023
|
} catch {
|
|
5205
|
-
await
|
|
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 =
|
|
5298
|
-
await
|
|
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
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
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: "
|
|
5389
|
-
name: "
|
|
5390
|
-
message: "
|
|
5391
|
-
|
|
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 (
|
|
5400
|
-
|
|
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
|
|
5432
|
-
|
|
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
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
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
|
-
|
|
7809
|
+
import inquirer2 from "inquirer";
|
|
7810
|
+
init_config();
|
|
5455
7811
|
function registerInstallCommand(program2) {
|
|
5456
|
-
program2.command("install").description("Install AIKit to
|
|
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
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
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
|
|
5477
|
-
import { join as
|
|
5478
|
-
import
|
|
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
|
|
5486
|
-
import { join as
|
|
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 =
|
|
7910
|
+
const versionPath = join17(paths.globalConfig(), ".version.json");
|
|
5498
7911
|
try {
|
|
5499
|
-
const content = await
|
|
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(
|
|
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 =
|
|
7981
|
+
const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
|
|
5569
7982
|
try {
|
|
5570
|
-
const installedData = await
|
|
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
|
|
8031
|
+
const files = await readdir8(dir);
|
|
5619
8032
|
for (const file of files) {
|
|
5620
|
-
const filePath =
|
|
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
|
|
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 =
|
|
8080
|
+
const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
|
|
5668
8081
|
try {
|
|
5669
|
-
await
|
|
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 =
|
|
5691
|
-
await
|
|
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
|
|
5707
|
-
import { join as
|
|
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 =
|
|
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
|
|
8136
|
+
await mkdir12(this.backupsDir, { recursive: true });
|
|
5724
8137
|
const backupId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
5725
|
-
const backupPath =
|
|
5726
|
-
await
|
|
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 =
|
|
5748
|
-
await
|
|
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 =
|
|
5762
|
-
const targetPath =
|
|
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
|
|
5768
|
-
const entries = await
|
|
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
|
|
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
|
|
5793
|
-
await
|
|
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
|
|
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
|
|
8224
|
+
const entries = await readdir9(this.backupsDir);
|
|
5812
8225
|
const backups = [];
|
|
5813
8226
|
for (const entry of entries) {
|
|
5814
|
-
const backupPath =
|
|
5815
|
-
const manifestPath =
|
|
8227
|
+
const backupPath = join18(this.backupsDir, entry);
|
|
8228
|
+
const manifestPath = join18(backupPath, "backup-manifest.json");
|
|
5816
8229
|
try {
|
|
5817
|
-
const manifestContent = await
|
|
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
|
|
8256
|
+
const entries = await readdir9(dir);
|
|
5844
8257
|
for (const entry of entries) {
|
|
5845
|
-
const entryPath =
|
|
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 =
|
|
5878
|
-
const targetPath =
|
|
5879
|
-
await
|
|
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 =
|
|
5895
|
-
await
|
|
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 =
|
|
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
|
|
8334
|
+
const entries = await readdir9(backup.path);
|
|
5922
8335
|
for (const entry of entries) {
|
|
5923
|
-
const entryPath =
|
|
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
|
|
8355
|
+
const entries = await readdir9(dirPath);
|
|
5943
8356
|
for (const entry of entries) {
|
|
5944
|
-
const entryPath =
|
|
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
|
|
5991
|
-
import { join as
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
8441
|
+
const migrationHistoryPath = join19(this.configPath, ".migration-history.json");
|
|
6029
8442
|
try {
|
|
6030
|
-
const content = await
|
|
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 =
|
|
8529
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6117
8530
|
try {
|
|
6118
8531
|
let history = [];
|
|
6119
8532
|
try {
|
|
6120
|
-
const content = await
|
|
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
|
|
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 =
|
|
8547
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6135
8548
|
try {
|
|
6136
|
-
const content = await
|
|
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
|
|
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 =
|
|
8563
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6151
8564
|
try {
|
|
6152
|
-
const content = await
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
6462
|
-
const targetPath =
|
|
6463
|
-
await
|
|
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 =
|
|
6471
|
-
const targetPath =
|
|
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
|
|
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
|
|
6483
|
-
await
|
|
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
|
|
6715
|
-
import { join as
|
|
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
|
|
9191
|
+
const configData = JSON.parse(await readFile15(join22(configPath, "aikit.json"), "utf-8"));
|
|
6779
9192
|
configData.mode = mode;
|
|
6780
|
-
await
|
|
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
|
|
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
|