@tdsoft-tech/aikit 0.1.16 → 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/.githooks/pre-commit +70 -0
- package/CHANGELOG.md +9 -0
- package/dist/cli.js +2850 -347
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1502 -107
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1502 -107
- package/dist/mcp-server.js.map +1 -1
- package/package.json +7 -2
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";
|
|
@@ -1227,6 +1256,68 @@ bd init
|
|
|
1227
1256
|
return false;
|
|
1228
1257
|
}
|
|
1229
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Setup git hooks
|
|
1261
|
+
*/
|
|
1262
|
+
async setupGitHooks() {
|
|
1263
|
+
try {
|
|
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
|
+
}
|
|
1269
|
+
const preCommitHook = join9(gitHooksDir, "pre-commit");
|
|
1270
|
+
const hookContent = `#!/bin/sh
|
|
1271
|
+
#
|
|
1272
|
+
# bd (beads) pre-commit hook
|
|
1273
|
+
#
|
|
1274
|
+
# This hook ensures that any pending bd issue changes are flushed to
|
|
1275
|
+
# .beads/issues.jsonl before the commit is created, preventing a
|
|
1276
|
+
# race condition where daemon auto-flush fires after the commit.
|
|
1277
|
+
#
|
|
1278
|
+
|
|
1279
|
+
# Check if bd is available
|
|
1280
|
+
if ! command -v bd >/dev/null 2>&1; then
|
|
1281
|
+
echo "Warning: bd command not found, skipping pre-commit flush" >&2
|
|
1282
|
+
exit 0
|
|
1283
|
+
fi
|
|
1284
|
+
|
|
1285
|
+
# Check if we're in a bd workspace
|
|
1286
|
+
BEADS_DIR=""
|
|
1287
|
+
if [ -d ".beads" ]; then
|
|
1288
|
+
BEADS_DIR=".beads"
|
|
1289
|
+
fi
|
|
1290
|
+
|
|
1291
|
+
if [ -z "$BEADS_DIR" ]; then
|
|
1292
|
+
# Not a bd workspace, nothing to do
|
|
1293
|
+
exit 0
|
|
1294
|
+
fi
|
|
1295
|
+
|
|
1296
|
+
# Check if bd is actually initialized (has beads.db or config.yaml)
|
|
1297
|
+
# This prevents errors if .beads/ exists but bd was never initialized
|
|
1298
|
+
if [ ! -f "$BEADS_DIR/beads.db" ] && [ ! -f "$BEADS_DIR/config.yaml" ]; then
|
|
1299
|
+
# .beads/ exists but bd is not initialized, skip bd operations
|
|
1300
|
+
exit 0
|
|
1301
|
+
fi
|
|
1302
|
+
|
|
1303
|
+
# Flush pending changes to JSONL
|
|
1304
|
+
# Use --flush-only to skip git operations (we're already in a git hook)
|
|
1305
|
+
# Suppress output unless there's an error
|
|
1306
|
+
if ! bd sync --flush-only >/dev/null 2>&1; then
|
|
1307
|
+
echo "Error: Failed to flush bd changes to JSONL" >&2
|
|
1308
|
+
echo "Run 'bd sync --flush-only' manually to diagnose" >&2
|
|
1309
|
+
exit 1
|
|
1310
|
+
fi
|
|
1311
|
+
|
|
1312
|
+
exit 0
|
|
1313
|
+
`;
|
|
1314
|
+
await writeFile5(preCommitHook, hookContent, { mode: 493 });
|
|
1315
|
+
return true;
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
logger.error("Failed to setup git hooks:", error);
|
|
1318
|
+
return false;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1230
1321
|
/**
|
|
1231
1322
|
* Get current status
|
|
1232
1323
|
*/
|
|
@@ -1500,13 +1591,437 @@ type: ${type}
|
|
|
1500
1591
|
}
|
|
1501
1592
|
});
|
|
1502
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
|
+
|
|
1503
2018
|
// src/core/tool-config.ts
|
|
1504
2019
|
var tool_config_exports = {};
|
|
1505
2020
|
__export(tool_config_exports, {
|
|
1506
2021
|
ToolConfigManager: () => ToolConfigManager
|
|
1507
2022
|
});
|
|
1508
|
-
import { readFile as
|
|
1509
|
-
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";
|
|
1510
2025
|
import { z as z3 } from "zod";
|
|
1511
2026
|
var ToolConfigSchema, REGISTERED_TOOLS, ToolConfigManager;
|
|
1512
2027
|
var init_tool_config = __esm({
|
|
@@ -1534,7 +2049,7 @@ var init_tool_config = __esm({
|
|
|
1534
2049
|
toolsConfigPath;
|
|
1535
2050
|
constructor(config) {
|
|
1536
2051
|
this.config = config;
|
|
1537
|
-
this.toolsConfigPath =
|
|
2052
|
+
this.toolsConfigPath = join21(this.config.configPath, "config", "tools.json");
|
|
1538
2053
|
}
|
|
1539
2054
|
/**
|
|
1540
2055
|
* Get all registered tools with their current status
|
|
@@ -1617,8 +2132,8 @@ var init_tool_config = __esm({
|
|
|
1617
2132
|
*/
|
|
1618
2133
|
async loadConfigs() {
|
|
1619
2134
|
try {
|
|
1620
|
-
await
|
|
1621
|
-
const content = await
|
|
2135
|
+
await access7(this.toolsConfigPath, constants4.R_OK);
|
|
2136
|
+
const content = await readFile14(this.toolsConfigPath, "utf-8");
|
|
1622
2137
|
return JSON.parse(content);
|
|
1623
2138
|
} catch {
|
|
1624
2139
|
return {};
|
|
@@ -1628,9 +2143,9 @@ var init_tool_config = __esm({
|
|
|
1628
2143
|
* Save configurations
|
|
1629
2144
|
*/
|
|
1630
2145
|
async saveConfigs(configs) {
|
|
1631
|
-
const configDir =
|
|
1632
|
-
await
|
|
1633
|
-
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));
|
|
1634
2149
|
}
|
|
1635
2150
|
};
|
|
1636
2151
|
}
|
|
@@ -1677,8 +2192,8 @@ var init_figma_oauth = __esm({
|
|
|
1677
2192
|
console.log('3. Give it a name (e.g., "AIKit")');
|
|
1678
2193
|
console.log("4. Copy the token (you won't see it again!)");
|
|
1679
2194
|
console.log("5. Paste it here when prompted\n");
|
|
1680
|
-
const { default:
|
|
1681
|
-
const { token } = await
|
|
2195
|
+
const { default: inquirer4 } = await import("inquirer");
|
|
2196
|
+
const { token } = await inquirer4.prompt([
|
|
1682
2197
|
{
|
|
1683
2198
|
type: "password",
|
|
1684
2199
|
name: "token",
|
|
@@ -1708,14 +2223,14 @@ var init_figma_oauth = __esm({
|
|
|
1708
2223
|
* Alternative: Manual token input
|
|
1709
2224
|
*/
|
|
1710
2225
|
async authenticateManual() {
|
|
1711
|
-
const { default:
|
|
2226
|
+
const { default: inquirer4 } = await import("inquirer");
|
|
1712
2227
|
console.log("\n\u{1F510} Figma Authentication (Manual)\n");
|
|
1713
2228
|
console.log("To get your Figma Personal Access Token:");
|
|
1714
2229
|
console.log("1. Visit: https://www.figma.com/developers/api#access-tokens");
|
|
1715
2230
|
console.log('2. Scroll to "Personal access tokens"');
|
|
1716
2231
|
console.log('3. Click "Create new token"');
|
|
1717
2232
|
console.log("4. Copy the token and paste it below\n");
|
|
1718
|
-
const { token } = await
|
|
2233
|
+
const { token } = await inquirer4.prompt([
|
|
1719
2234
|
{
|
|
1720
2235
|
type: "password",
|
|
1721
2236
|
name: "token",
|
|
@@ -1770,7 +2285,7 @@ init_esm_shims();
|
|
|
1770
2285
|
|
|
1771
2286
|
// src/cli/index.ts
|
|
1772
2287
|
init_esm_shims();
|
|
1773
|
-
import { Command } from "commander";
|
|
2288
|
+
import { Command as Command3 } from "commander";
|
|
1774
2289
|
|
|
1775
2290
|
// src/index.ts
|
|
1776
2291
|
init_esm_shims();
|
|
@@ -2345,12 +2860,20 @@ ${agent.delegatesTo.map((a) => `- @${a}`).join("\n")}` : ""}
|
|
|
2345
2860
|
|
|
2346
2861
|
// src/core/commands.ts
|
|
2347
2862
|
init_esm_shims();
|
|
2863
|
+
|
|
2864
|
+
// src/core/commands/index.ts
|
|
2865
|
+
init_esm_shims();
|
|
2348
2866
|
init_paths();
|
|
2349
2867
|
import { readFile as readFile3, readdir as readdir2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
2350
2868
|
import { join as join5, basename as basename2, extname as extname2 } from "path";
|
|
2351
2869
|
import matter2 from "gray-matter";
|
|
2352
|
-
|
|
2353
|
-
|
|
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 = [
|
|
2354
2877
|
{
|
|
2355
2878
|
name: "create",
|
|
2356
2879
|
description: "Create a new Beads task for tracking",
|
|
@@ -2602,8 +3125,12 @@ Task description: $ARGUMENTS
|
|
|
2602
3125
|
\u2713 Use for straightforward tasks first
|
|
2603
3126
|
\u2713 Consider /plan + /implement for complex features
|
|
2604
3127
|
\u2713 Review changes before final approval`
|
|
2605
|
-
}
|
|
2606
|
-
|
|
3128
|
+
}
|
|
3129
|
+
];
|
|
3130
|
+
|
|
3131
|
+
// src/core/commands/quick.ts
|
|
3132
|
+
init_esm_shims();
|
|
3133
|
+
var QUICK_COMMANDS = [
|
|
2607
3134
|
{
|
|
2608
3135
|
name: "fix",
|
|
2609
3136
|
description: "Quick fix for an issue",
|
|
@@ -2698,7 +3225,47 @@ Optional PR title: $ARGUMENTS
|
|
|
2698
3225
|
- Screenshots if UI changes
|
|
2699
3226
|
3. Create PR via GitHub CLI or provide URL`
|
|
2700
3227
|
},
|
|
2701
|
-
|
|
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 = [
|
|
2702
3269
|
{
|
|
2703
3270
|
name: "research",
|
|
2704
3271
|
description: "Deep research on a topic",
|
|
@@ -2759,8 +3326,12 @@ Optional path: $ARGUMENTS
|
|
|
2759
3326
|
- Test coverage gaps
|
|
2760
3327
|
3. Prioritize findings
|
|
2761
3328
|
4. Suggest improvements`
|
|
2762
|
-
}
|
|
2763
|
-
|
|
3329
|
+
}
|
|
3330
|
+
];
|
|
3331
|
+
|
|
3332
|
+
// src/core/commands/design.ts
|
|
3333
|
+
init_esm_shims();
|
|
3334
|
+
var DESIGN_COMMANDS = [
|
|
2764
3335
|
{
|
|
2765
3336
|
name: "design",
|
|
2766
3337
|
description: "Design a feature or system",
|
|
@@ -2802,76 +3373,6 @@ Problem to brainstorm: $ARGUMENTS
|
|
|
2802
3373
|
3. Group related ideas
|
|
2803
3374
|
4. Evaluate feasibility
|
|
2804
3375
|
5. Select top candidates`
|
|
2805
|
-
},
|
|
2806
|
-
// Git & Version Control
|
|
2807
|
-
{
|
|
2808
|
-
name: "branch",
|
|
2809
|
-
description: "Create a new feature branch",
|
|
2810
|
-
category: "git",
|
|
2811
|
-
usage: "/branch <name>",
|
|
2812
|
-
examples: ["/branch feat/auth", "/branch fix/navigation-bug"],
|
|
2813
|
-
content: `Create and switch to a new branch.
|
|
2814
|
-
|
|
2815
|
-
## Workflow
|
|
2816
|
-
|
|
2817
|
-
Branch name: $ARGUMENTS
|
|
2818
|
-
|
|
2819
|
-
1. Ensure clean working directory
|
|
2820
|
-
2. Pull latest main/master
|
|
2821
|
-
3. Create branch with naming convention:
|
|
2822
|
-
- feat/* for features
|
|
2823
|
-
- fix/* for bug fixes
|
|
2824
|
-
- refactor/* for refactoring
|
|
2825
|
-
- docs/* for documentation
|
|
2826
|
-
4. Switch to new branch`
|
|
2827
|
-
},
|
|
2828
|
-
{
|
|
2829
|
-
name: "merge",
|
|
2830
|
-
description: "Merge current branch to target",
|
|
2831
|
-
category: "git",
|
|
2832
|
-
usage: "/merge [target]",
|
|
2833
|
-
examples: ["/merge", "/merge main"],
|
|
2834
|
-
content: `Merge current branch to target.
|
|
2835
|
-
|
|
2836
|
-
## Workflow
|
|
2837
|
-
|
|
2838
|
-
Optional target branch: $ARGUMENTS
|
|
2839
|
-
|
|
2840
|
-
1. Run quality gates first
|
|
2841
|
-
2. Commit any pending changes
|
|
2842
|
-
3. Switch to target branch
|
|
2843
|
-
4. Pull latest
|
|
2844
|
-
5. Merge feature branch
|
|
2845
|
-
6. Resolve conflicts if any
|
|
2846
|
-
7. Push`
|
|
2847
|
-
},
|
|
2848
|
-
// Utilities
|
|
2849
|
-
{
|
|
2850
|
-
name: "status",
|
|
2851
|
-
description: "Show current status overview",
|
|
2852
|
-
category: "utility",
|
|
2853
|
-
usage: "/status",
|
|
2854
|
-
examples: ["/status"],
|
|
2855
|
-
content: `Display comprehensive status.
|
|
2856
|
-
|
|
2857
|
-
## Shows
|
|
2858
|
-
- Current task (from Beads)
|
|
2859
|
-
- Git status
|
|
2860
|
-
- Active branch
|
|
2861
|
-
- Pending changes
|
|
2862
|
-
- Test status
|
|
2863
|
-
- Recent activity`
|
|
2864
|
-
},
|
|
2865
|
-
{
|
|
2866
|
-
name: "help",
|
|
2867
|
-
description: "Show available commands",
|
|
2868
|
-
category: "utility",
|
|
2869
|
-
usage: "/help [command]",
|
|
2870
|
-
examples: ["/help", "/help plan"],
|
|
2871
|
-
content: `Display help information.
|
|
2872
|
-
|
|
2873
|
-
If no command specified, list all available commands.
|
|
2874
|
-
If command specified, show detailed help for that command.`
|
|
2875
3376
|
},
|
|
2876
3377
|
{
|
|
2877
3378
|
name: "analyze-figma",
|
|
@@ -3017,24 +3518,179 @@ Summarize what was extracted:
|
|
|
3017
3518
|
- If the tool returns an error about access, verify the file is accessible with your token
|
|
3018
3519
|
|
|
3019
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`
|
|
3020
3547
|
},
|
|
3021
3548
|
{
|
|
3022
|
-
name: "
|
|
3023
|
-
description: "
|
|
3024
|
-
category: "
|
|
3025
|
-
usage: "/
|
|
3026
|
-
examples: ["/
|
|
3027
|
-
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.
|
|
3028
3555
|
|
|
3029
3556
|
## Workflow
|
|
3030
3557
|
|
|
3031
|
-
Optional
|
|
3558
|
+
Optional target branch: $ARGUMENTS
|
|
3032
3559
|
|
|
3033
|
-
1.
|
|
3034
|
-
2.
|
|
3035
|
-
3.
|
|
3036
|
-
4.
|
|
3037
|
-
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.`
|
|
3038
3694
|
},
|
|
3039
3695
|
{
|
|
3040
3696
|
name: "test",
|
|
@@ -3053,24 +3709,6 @@ Optional pattern: $ARGUMENTS
|
|
|
3053
3709
|
3. Show coverage if available
|
|
3054
3710
|
4. Highlight failures
|
|
3055
3711
|
5. Suggest fixes for failures`
|
|
3056
|
-
},
|
|
3057
|
-
{
|
|
3058
|
-
name: "lint",
|
|
3059
|
-
description: "Run linter and fix issues",
|
|
3060
|
-
category: "quick",
|
|
3061
|
-
usage: "/lint [--fix]",
|
|
3062
|
-
examples: ["/lint", "/lint --fix"],
|
|
3063
|
-
content: `Run linter and optionally fix issues.
|
|
3064
|
-
|
|
3065
|
-
## Workflow
|
|
3066
|
-
|
|
3067
|
-
Optional flags: $ARGUMENTS
|
|
3068
|
-
|
|
3069
|
-
1. Run linter: \`npm run lint\`
|
|
3070
|
-
2. Parse errors and warnings
|
|
3071
|
-
3. If --fix flag, run auto-fix
|
|
3072
|
-
4. Report remaining issues
|
|
3073
|
-
5. Suggest manual fixes if needed`
|
|
3074
3712
|
},
|
|
3075
3713
|
{
|
|
3076
3714
|
name: "deploy",
|
|
@@ -3118,15 +3756,1196 @@ Optional version: $ARGUMENTS
|
|
|
3118
3756
|
|
|
3119
3757
|
## Workflow
|
|
3120
3758
|
|
|
3121
|
-
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
|
|
3122
4928
|
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
4929
|
+
Ensure directories exist:
|
|
4930
|
+
\`\`\`bash
|
|
4931
|
+
mkdir -p mermaid
|
|
4932
|
+
mkdir -p .aikit/assets/drawio
|
|
4933
|
+
\`\`\``
|
|
3128
4934
|
}
|
|
3129
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
|
+
];
|
|
3130
4949
|
var CommandRunner = class {
|
|
3131
4950
|
config;
|
|
3132
4951
|
commandsCache = /* @__PURE__ */ new Map();
|
|
@@ -4591,17 +6410,17 @@ export default ${toPascalCase(name)}Plugin;
|
|
|
4591
6410
|
event: async (event) => {
|
|
4592
6411
|
if (event.type === "session.idle") {
|
|
4593
6412
|
try {
|
|
4594
|
-
const { exec:
|
|
4595
|
-
const { promisify:
|
|
4596
|
-
const
|
|
6413
|
+
const { exec: exec3 } = await import("child_process");
|
|
6414
|
+
const { promisify: promisify3 } = await import("util");
|
|
6415
|
+
const execAsync3 = promisify3(exec3);
|
|
4597
6416
|
const platform = process.platform;
|
|
4598
6417
|
const summary = event.properties?.summary || "Session completed";
|
|
4599
6418
|
if (platform === "darwin") {
|
|
4600
|
-
await
|
|
6419
|
+
await execAsync3(`osascript -e 'display notification "${summary}" with title "OpenCode Session Complete"'`);
|
|
4601
6420
|
} else if (platform === "linux") {
|
|
4602
|
-
await
|
|
6421
|
+
await execAsync3(`notify-send "OpenCode Session Complete" "${summary}"`);
|
|
4603
6422
|
} else if (platform === "win32") {
|
|
4604
|
-
await
|
|
6423
|
+
await execAsync3(`powershell -Command "New-BurntToastNotification -Text 'OpenCode Session Complete', '${summary}'"`);
|
|
4605
6424
|
}
|
|
4606
6425
|
} catch (error) {
|
|
4607
6426
|
logger.warn(`[Notification] Failed to send notification: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -4652,9 +6471,15 @@ init_beads();
|
|
|
4652
6471
|
// src/utils/cli-detector.ts
|
|
4653
6472
|
init_esm_shims();
|
|
4654
6473
|
import { execSync } from "child_process";
|
|
4655
|
-
import { existsSync as
|
|
6474
|
+
import { existsSync as existsSync5 } from "fs";
|
|
4656
6475
|
import { join as join12 } from "path";
|
|
4657
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 || {});
|
|
4658
6483
|
var CliDetector = class {
|
|
4659
6484
|
/**
|
|
4660
6485
|
* Check if OpenCode is installed
|
|
@@ -4663,14 +6488,14 @@ var CliDetector = class {
|
|
|
4663
6488
|
try {
|
|
4664
6489
|
const opencodePath = process.platform === "win32" ? process.env.APPDATA || join12(homedir2(), "AppData", "Roaming") : join12(homedir2(), ".config");
|
|
4665
6490
|
const opencodeConfig = join12(opencodePath, "opencode", "opencode.json");
|
|
4666
|
-
let installed =
|
|
6491
|
+
let installed = existsSync5(opencodeConfig);
|
|
4667
6492
|
let version;
|
|
4668
6493
|
if (installed) {
|
|
4669
6494
|
try {
|
|
4670
6495
|
execSync("opencode --version", { stdio: "ignore" });
|
|
4671
6496
|
version = "installed";
|
|
4672
6497
|
} catch (error) {
|
|
4673
|
-
if (
|
|
6498
|
+
if (existsSync5(opencodeConfig)) {
|
|
4674
6499
|
version = "installed (config exists)";
|
|
4675
6500
|
} else {
|
|
4676
6501
|
installed = false;
|
|
@@ -4762,6 +6587,47 @@ var CliDetector = class {
|
|
|
4762
6587
|
static filterInstallable(tools) {
|
|
4763
6588
|
return tools.filter((t) => t.detected && !t.installed);
|
|
4764
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
|
+
}
|
|
4765
6631
|
};
|
|
4766
6632
|
|
|
4767
6633
|
// src/cli/commands/init.ts
|
|
@@ -4770,9 +6636,9 @@ init_paths();
|
|
|
4770
6636
|
|
|
4771
6637
|
// src/cli/helpers.ts
|
|
4772
6638
|
init_esm_shims();
|
|
4773
|
-
import { existsSync as
|
|
4774
|
-
import { mkdir as
|
|
4775
|
-
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";
|
|
4776
6642
|
import { homedir as homedir3 } from "os";
|
|
4777
6643
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4778
6644
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -4798,7 +6664,7 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
4798
6664
|
"memory/research"
|
|
4799
6665
|
];
|
|
4800
6666
|
for (const dir of dirs) {
|
|
4801
|
-
await
|
|
6667
|
+
await mkdir9(join14(configDir, dir), { recursive: true });
|
|
4802
6668
|
}
|
|
4803
6669
|
const defaultConfig = {
|
|
4804
6670
|
version: getVersion(),
|
|
@@ -4811,8 +6677,8 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
4811
6677
|
beads: { enabled: true },
|
|
4812
6678
|
antiHallucination: { enabled: true }
|
|
4813
6679
|
};
|
|
4814
|
-
await
|
|
4815
|
-
|
|
6680
|
+
await writeFile9(
|
|
6681
|
+
join14(configDir, "aikit.json"),
|
|
4816
6682
|
JSON.stringify(defaultConfig, null, 2)
|
|
4817
6683
|
);
|
|
4818
6684
|
const agentsMd = `# AIKit Agent Rules
|
|
@@ -4835,20 +6701,20 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
4835
6701
|
## Project-Specific Rules
|
|
4836
6702
|
Add your project-specific rules here.
|
|
4837
6703
|
`;
|
|
4838
|
-
await
|
|
6704
|
+
await writeFile9(join14(configDir, "AGENTS.md"), agentsMd);
|
|
4839
6705
|
}
|
|
4840
6706
|
async function configureMcpServer(projectPath) {
|
|
4841
6707
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
4842
6708
|
const currentDir = dirname2(currentFile);
|
|
4843
|
-
const aikitPath =
|
|
4844
|
-
const mcpServerPath =
|
|
6709
|
+
const aikitPath = join14(currentDir, "..", "..");
|
|
6710
|
+
const mcpServerPath = join14(aikitPath, "dist", "mcp-server.js");
|
|
4845
6711
|
const configLocations = [
|
|
4846
6712
|
// Global config (most common)
|
|
4847
|
-
|
|
6713
|
+
join14(homedir3(), ".config", "opencode", "opencode.json"),
|
|
4848
6714
|
// Project-level config
|
|
4849
|
-
|
|
6715
|
+
join14(projectPath, ".opencode", "opencode.json"),
|
|
4850
6716
|
// Alternative global location
|
|
4851
|
-
|
|
6717
|
+
join14(homedir3(), ".opencode", "opencode.json")
|
|
4852
6718
|
];
|
|
4853
6719
|
const mcpServerConfig = {
|
|
4854
6720
|
type: "local",
|
|
@@ -4857,12 +6723,12 @@ async function configureMcpServer(projectPath) {
|
|
|
4857
6723
|
};
|
|
4858
6724
|
for (const configPath of configLocations) {
|
|
4859
6725
|
try {
|
|
4860
|
-
const configDir =
|
|
4861
|
-
await
|
|
6726
|
+
const configDir = join14(configPath, "..");
|
|
6727
|
+
await mkdir9(configDir, { recursive: true });
|
|
4862
6728
|
let config = {};
|
|
4863
|
-
if (
|
|
6729
|
+
if (existsSync6(configPath)) {
|
|
4864
6730
|
try {
|
|
4865
|
-
const existing = await
|
|
6731
|
+
const existing = await readFile8(configPath, "utf-8");
|
|
4866
6732
|
config = JSON.parse(existing);
|
|
4867
6733
|
} catch {
|
|
4868
6734
|
config = {};
|
|
@@ -4872,7 +6738,7 @@ async function configureMcpServer(projectPath) {
|
|
|
4872
6738
|
config.mcp = {};
|
|
4873
6739
|
}
|
|
4874
6740
|
config.mcp.aikit = mcpServerConfig;
|
|
4875
|
-
await
|
|
6741
|
+
await writeFile9(configPath, JSON.stringify(config, null, 2));
|
|
4876
6742
|
logger.success(`
|
|
4877
6743
|
\u2705 MCP server configured: ${configPath}`);
|
|
4878
6744
|
logger.info(` Server: node ${mcpServerPath}`);
|
|
@@ -4881,9 +6747,9 @@ async function configureMcpServer(projectPath) {
|
|
|
4881
6747
|
continue;
|
|
4882
6748
|
}
|
|
4883
6749
|
}
|
|
4884
|
-
const instructionsPath =
|
|
4885
|
-
await
|
|
4886
|
-
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
|
|
4887
6753
|
|
|
4888
6754
|
## Automatic Setup Failed
|
|
4889
6755
|
|
|
@@ -4930,13 +6796,24 @@ async function installCliTool(tool) {
|
|
|
4930
6796
|
await installToOpenCode(paths.opencodeConfig());
|
|
4931
6797
|
break;
|
|
4932
6798
|
case "claude" /* CLAUDE */:
|
|
4933
|
-
|
|
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
|
+
}
|
|
4934
6812
|
break;
|
|
4935
6813
|
case "github" /* GITHUB */:
|
|
4936
6814
|
execSync2("npm install -g gh", { stdio: "inherit" });
|
|
4937
6815
|
break;
|
|
4938
6816
|
}
|
|
4939
|
-
logger.success(`\u2713 ${tool.displayName} installed`);
|
|
4940
6817
|
return true;
|
|
4941
6818
|
} catch (error) {
|
|
4942
6819
|
logger.error(`Failed to install ${tool.displayName}:`, error);
|
|
@@ -5125,26 +7002,26 @@ Report what was extracted:
|
|
|
5125
7002
|
}
|
|
5126
7003
|
async function installToOpenCode(_opencodePath) {
|
|
5127
7004
|
const projectPath = process.cwd();
|
|
5128
|
-
const opencodeCommandDir =
|
|
5129
|
-
const aikitDir =
|
|
5130
|
-
const opencodeAgentDir =
|
|
5131
|
-
await
|
|
5132
|
-
await
|
|
5133
|
-
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 });
|
|
5134
7011
|
for (const [name, content] of Object.entries(AGENT_FILES)) {
|
|
5135
|
-
const filePath =
|
|
7012
|
+
const filePath = join14(opencodeAgentDir, `${name}.md`);
|
|
5136
7013
|
try {
|
|
5137
|
-
await
|
|
5138
|
-
const existingContent = await
|
|
7014
|
+
await access5(filePath);
|
|
7015
|
+
const existingContent = await readFile8(filePath, "utf8");
|
|
5139
7016
|
if (!existingContent.includes("mode: subagent")) {
|
|
5140
|
-
const
|
|
5141
|
-
const { data: frontmatter, content: body } =
|
|
7017
|
+
const matter5 = await import("gray-matter");
|
|
7018
|
+
const { data: frontmatter, content: body } = matter5.default(existingContent);
|
|
5142
7019
|
frontmatter.mode = "subagent";
|
|
5143
|
-
const updatedContent =
|
|
5144
|
-
await
|
|
7020
|
+
const updatedContent = matter5.default.stringify(body, frontmatter);
|
|
7021
|
+
await writeFile9(filePath, updatedContent, "utf8");
|
|
5145
7022
|
}
|
|
5146
7023
|
} catch {
|
|
5147
|
-
await
|
|
7024
|
+
await writeFile9(filePath, content, "utf8");
|
|
5148
7025
|
}
|
|
5149
7026
|
}
|
|
5150
7027
|
const config = await loadConfig();
|
|
@@ -5236,8 +7113,8 @@ ${cmd.content}
|
|
|
5236
7113
|
}
|
|
5237
7114
|
let count = 0;
|
|
5238
7115
|
for (const [name, content] of Object.entries(opencodeCommands)) {
|
|
5239
|
-
const filePath =
|
|
5240
|
-
await
|
|
7116
|
+
const filePath = join14(opencodeCommandDir, `${name}.md`);
|
|
7117
|
+
await writeFile9(filePath, content.trim());
|
|
5241
7118
|
logger.info(` \u2713 Created /${name} command`);
|
|
5242
7119
|
count++;
|
|
5243
7120
|
}
|
|
@@ -5258,10 +7135,541 @@ function groupBy(array, keyFn) {
|
|
|
5258
7135
|
return acc;
|
|
5259
7136
|
}, {});
|
|
5260
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
|
+
];
|
|
5261
7669
|
|
|
5262
7670
|
// src/cli/commands/init.ts
|
|
5263
7671
|
function registerInitCommand(program2) {
|
|
5264
|
-
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) => {
|
|
5265
7673
|
const configDir = options.global ? paths.globalConfig() : paths.projectConfig();
|
|
5266
7674
|
console.log(chalk2.bold("\n\u{1F680} AIKit Setup\n"));
|
|
5267
7675
|
logger.info(`Initializing AIKit in ${configDir}...`);
|
|
@@ -5269,91 +7677,54 @@ function registerInitCommand(program2) {
|
|
|
5269
7677
|
await initializeConfig(configDir, options.global);
|
|
5270
7678
|
logger.success("\u2713 Configuration created");
|
|
5271
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}`);
|
|
5272
7706
|
const config = await loadConfig();
|
|
5273
7707
|
const engine = new SkillEngine(config);
|
|
5274
7708
|
const result = await engine.syncSkillsToProject();
|
|
5275
7709
|
if (result.count > 0) {
|
|
5276
7710
|
logger.success(`\u2713 Synced ${result.count} skills`);
|
|
5277
7711
|
}
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
const version = tool.version ? chalk2.gray(` (${tool.version})`) : "";
|
|
5284
|
-
console.log(` ${status} ${chalk2.cyan(tool.displayName)}${version}`);
|
|
5285
|
-
}
|
|
5286
|
-
if (installableTools.length > 0) {
|
|
5287
|
-
console.log();
|
|
5288
|
-
const { action } = await inquirer.prompt([
|
|
5289
|
-
{
|
|
5290
|
-
type: "list",
|
|
5291
|
-
name: "action",
|
|
5292
|
-
message: "How would you like to proceed?",
|
|
5293
|
-
choices: [
|
|
5294
|
-
{
|
|
5295
|
-
name: "all",
|
|
5296
|
-
value: "all",
|
|
5297
|
-
short: "a",
|
|
5298
|
-
message: "Install all missing CLI tools"
|
|
5299
|
-
},
|
|
5300
|
-
{
|
|
5301
|
-
name: "select",
|
|
5302
|
-
value: "select",
|
|
5303
|
-
short: "s",
|
|
5304
|
-
message: "Select specific tools to install (use space to select, Enter to confirm)"
|
|
5305
|
-
},
|
|
5306
|
-
{
|
|
5307
|
-
name: "skip",
|
|
5308
|
-
value: "skip",
|
|
5309
|
-
short: "n",
|
|
5310
|
-
message: "Skip CLI tool installation"
|
|
5311
|
-
}
|
|
5312
|
-
],
|
|
5313
|
-
default: "all"
|
|
5314
|
-
}
|
|
5315
|
-
]);
|
|
5316
|
-
if (action === "skip") {
|
|
5317
|
-
console.log();
|
|
5318
|
-
logger.info("Skipping CLI tool installation");
|
|
5319
|
-
} else if (action === "all") {
|
|
5320
|
-
console.log();
|
|
5321
|
-
logger.info(`Installing ${installableTools.length} CLI tool(s)...`);
|
|
5322
|
-
for (const tool of installableTools) {
|
|
5323
|
-
await installCliTool(tool);
|
|
5324
|
-
}
|
|
5325
|
-
console.log();
|
|
5326
|
-
logger.success("\u2713 CLI tools installed");
|
|
5327
|
-
} else {
|
|
5328
|
-
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([
|
|
5329
7717
|
{
|
|
5330
|
-
type: "
|
|
5331
|
-
name: "
|
|
5332
|
-
message: "
|
|
5333
|
-
|
|
5334
|
-
name: tool.name,
|
|
5335
|
-
value: tool,
|
|
5336
|
-
checked: true
|
|
5337
|
-
// Default to install all
|
|
5338
|
-
}))
|
|
7718
|
+
type: "confirm",
|
|
7719
|
+
name: "installClaude",
|
|
7720
|
+
message: "Claude Code CLI is not installed. Install now?",
|
|
7721
|
+
default: true
|
|
5339
7722
|
}
|
|
5340
7723
|
]);
|
|
5341
|
-
if (
|
|
5342
|
-
|
|
5343
|
-
logger.info(`Installing ${installTools.length} CLI tool(s)...`);
|
|
5344
|
-
for (const tool of installTools) {
|
|
5345
|
-
await installCliTool(tool);
|
|
5346
|
-
}
|
|
5347
|
-
console.log();
|
|
5348
|
-
logger.success("\u2713 CLI tools installed");
|
|
5349
|
-
} else {
|
|
5350
|
-
console.log();
|
|
5351
|
-
logger.info("Skipping CLI tool installation");
|
|
7724
|
+
if (installClaude) {
|
|
7725
|
+
await installCliTool(claudeTool);
|
|
5352
7726
|
}
|
|
5353
7727
|
}
|
|
5354
|
-
} else {
|
|
5355
|
-
console.log();
|
|
5356
|
-
logger.success("\u2713 All CLI tools already installed");
|
|
5357
7728
|
}
|
|
5358
7729
|
const beads = new BeadsIntegration();
|
|
5359
7730
|
const beadsStatus = await beads.getStatus();
|
|
@@ -5367,18 +7738,18 @@ function registerInitCommand(program2) {
|
|
|
5367
7738
|
} else {
|
|
5368
7739
|
logger.info("Beads already initialized");
|
|
5369
7740
|
}
|
|
5370
|
-
|
|
5371
|
-
await
|
|
7741
|
+
logger.info("Setting up git hooks...");
|
|
7742
|
+
await beads.setupGitHooks();
|
|
7743
|
+
logger.success("\u2713 Git hooks configured");
|
|
7744
|
+
const adapter = createAdapter(selectedPlatform);
|
|
7745
|
+
logger.info(`Installing AIKit for ${adapter.displayName}...`);
|
|
7746
|
+
await installToPlatform(adapter, config);
|
|
5372
7747
|
console.log(chalk2.bold("\n\u2728 AIKit is ready!\n"));
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
console.log(chalk2.cyan(" /review") + " - Code review checklist");
|
|
5379
|
-
console.log(chalk2.cyan(" /git") + " - Git workflow");
|
|
5380
|
-
console.log(chalk2.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
|
|
5381
|
-
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
|
+
}
|
|
5382
7753
|
}
|
|
5383
7754
|
} catch (error) {
|
|
5384
7755
|
logger.error("Failed to initialize AIKit:", error);
|
|
@@ -5386,18 +7757,121 @@ function registerInitCommand(program2) {
|
|
|
5386
7757
|
}
|
|
5387
7758
|
});
|
|
5388
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
|
+
}
|
|
5389
7805
|
|
|
5390
7806
|
// src/cli/commands/install.ts
|
|
5391
7807
|
init_esm_shims();
|
|
5392
7808
|
init_logger();
|
|
5393
|
-
|
|
7809
|
+
import inquirer2 from "inquirer";
|
|
7810
|
+
init_config();
|
|
5394
7811
|
function registerInstallCommand(program2) {
|
|
5395
|
-
program2.command("install").description("Install AIKit to
|
|
5396
|
-
logger.info("Installing AIKit to OpenCode...");
|
|
7812
|
+
program2.command("install [platform]").description("Install AIKit to specific CLI tool configuration").action(async (platformArg) => {
|
|
5397
7813
|
try {
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
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}!`);
|
|
5401
7875
|
} catch (error) {
|
|
5402
7876
|
logger.error("Failed to install:", error);
|
|
5403
7877
|
process.exit(1);
|
|
@@ -5412,17 +7886,17 @@ import chalk4 from "chalk";
|
|
|
5412
7886
|
|
|
5413
7887
|
// src/core/sync-engine.ts
|
|
5414
7888
|
init_esm_shims();
|
|
5415
|
-
import { readFile as
|
|
5416
|
-
import { join as
|
|
5417
|
-
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";
|
|
5418
7892
|
import chalk3 from "chalk";
|
|
5419
7893
|
|
|
5420
7894
|
// src/core/version-manager.ts
|
|
5421
7895
|
init_esm_shims();
|
|
5422
7896
|
init_paths();
|
|
5423
7897
|
init_logger();
|
|
5424
|
-
import { readFile as
|
|
5425
|
-
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";
|
|
5426
7900
|
import { createHash } from "crypto";
|
|
5427
7901
|
var VersionManager = class {
|
|
5428
7902
|
config;
|
|
@@ -5433,9 +7907,9 @@ var VersionManager = class {
|
|
|
5433
7907
|
* Get current installed version
|
|
5434
7908
|
*/
|
|
5435
7909
|
async getCurrentVersion() {
|
|
5436
|
-
const versionPath =
|
|
7910
|
+
const versionPath = join17(paths.globalConfig(), ".version.json");
|
|
5437
7911
|
try {
|
|
5438
|
-
const content = await
|
|
7912
|
+
const content = await readFile10(versionPath, "utf-8");
|
|
5439
7913
|
return JSON.parse(content);
|
|
5440
7914
|
} catch {
|
|
5441
7915
|
return null;
|
|
@@ -5446,7 +7920,7 @@ var VersionManager = class {
|
|
|
5446
7920
|
*/
|
|
5447
7921
|
getPackageVersion() {
|
|
5448
7922
|
try {
|
|
5449
|
-
const packageJson = __require(
|
|
7923
|
+
const packageJson = __require(join17(process.cwd(), "package.json"));
|
|
5450
7924
|
return packageJson.version || "0.0.0";
|
|
5451
7925
|
} catch {
|
|
5452
7926
|
return "0.0.0";
|
|
@@ -5504,9 +7978,9 @@ var VersionManager = class {
|
|
|
5504
7978
|
const removedSkills = [];
|
|
5505
7979
|
const conflicts = [];
|
|
5506
7980
|
const installedSkills = /* @__PURE__ */ new Map();
|
|
5507
|
-
const installedPath =
|
|
7981
|
+
const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
|
|
5508
7982
|
try {
|
|
5509
|
-
const installedData = await
|
|
7983
|
+
const installedData = await readFile10(installedPath, "utf-8");
|
|
5510
7984
|
const installedList = JSON.parse(installedData);
|
|
5511
7985
|
installedList.forEach((skill) => {
|
|
5512
7986
|
installedSkills.set(skill.name, skill);
|
|
@@ -5554,9 +8028,9 @@ var VersionManager = class {
|
|
|
5554
8028
|
const hashes = [];
|
|
5555
8029
|
try {
|
|
5556
8030
|
const loadFromDir = async (dir) => {
|
|
5557
|
-
const files = await
|
|
8031
|
+
const files = await readdir8(dir);
|
|
5558
8032
|
for (const file of files) {
|
|
5559
|
-
const filePath =
|
|
8033
|
+
const filePath = join17(dir, file);
|
|
5560
8034
|
const stats = await stat(filePath);
|
|
5561
8035
|
if (stats.isDirectory()) {
|
|
5562
8036
|
await loadFromDir(filePath);
|
|
@@ -5582,7 +8056,7 @@ var VersionManager = class {
|
|
|
5582
8056
|
*/
|
|
5583
8057
|
async calculateSkillHash(filePath) {
|
|
5584
8058
|
try {
|
|
5585
|
-
const content = await
|
|
8059
|
+
const content = await readFile10(filePath, "utf-8");
|
|
5586
8060
|
return createHash("sha256").update(content).digest("hex");
|
|
5587
8061
|
} catch {
|
|
5588
8062
|
return "";
|
|
@@ -5603,9 +8077,9 @@ var VersionManager = class {
|
|
|
5603
8077
|
* Save installed skills info
|
|
5604
8078
|
*/
|
|
5605
8079
|
async saveInstalledSkills(skills) {
|
|
5606
|
-
const installedPath =
|
|
8080
|
+
const installedPath = join17(paths.globalConfig(), ".installed-skills.json");
|
|
5607
8081
|
try {
|
|
5608
|
-
await
|
|
8082
|
+
await writeFile12(installedPath, JSON.stringify(skills, null, 2));
|
|
5609
8083
|
} catch (error) {
|
|
5610
8084
|
logger.error("Failed to save installed skills info:", error);
|
|
5611
8085
|
}
|
|
@@ -5626,8 +8100,8 @@ var VersionManager = class {
|
|
|
5626
8100
|
packageVersion: this.getPackageVersion(),
|
|
5627
8101
|
migrationHistory: migration ? [...current.migrationHistory, migration] : current.migrationHistory
|
|
5628
8102
|
};
|
|
5629
|
-
const versionPath =
|
|
5630
|
-
await
|
|
8103
|
+
const versionPath = join17(paths.globalConfig(), ".version.json");
|
|
8104
|
+
await writeFile12(versionPath, JSON.stringify(updated, null, 2));
|
|
5631
8105
|
}
|
|
5632
8106
|
/**
|
|
5633
8107
|
* Check if migration is needed
|
|
@@ -5642,8 +8116,8 @@ var VersionManager = class {
|
|
|
5642
8116
|
// src/core/backup-manager.ts
|
|
5643
8117
|
init_esm_shims();
|
|
5644
8118
|
init_logger();
|
|
5645
|
-
import { readFile as
|
|
5646
|
-
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";
|
|
5647
8121
|
import { createHash as createHash2 } from "crypto";
|
|
5648
8122
|
var BackupManager = class {
|
|
5649
8123
|
configPath;
|
|
@@ -5651,7 +8125,7 @@ var BackupManager = class {
|
|
|
5651
8125
|
maxBackups;
|
|
5652
8126
|
constructor(configPath, maxBackups = 5) {
|
|
5653
8127
|
this.configPath = configPath;
|
|
5654
|
-
this.backupsDir =
|
|
8128
|
+
this.backupsDir = join18(configPath, ".backups");
|
|
5655
8129
|
this.maxBackups = maxBackups;
|
|
5656
8130
|
}
|
|
5657
8131
|
/**
|
|
@@ -5659,10 +8133,10 @@ var BackupManager = class {
|
|
|
5659
8133
|
*/
|
|
5660
8134
|
async createBackup(fromVersion, toVersion) {
|
|
5661
8135
|
try {
|
|
5662
|
-
await
|
|
8136
|
+
await mkdir12(this.backupsDir, { recursive: true });
|
|
5663
8137
|
const backupId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
5664
|
-
const backupPath =
|
|
5665
|
-
await
|
|
8138
|
+
const backupPath = join18(this.backupsDir, `${backupId}-v${toVersion}`);
|
|
8139
|
+
await mkdir12(backupPath, { recursive: true });
|
|
5666
8140
|
logger.info(`Creating backup: ${backupPath}`);
|
|
5667
8141
|
const files = [];
|
|
5668
8142
|
const backupItems = [
|
|
@@ -5683,8 +8157,8 @@ var BackupManager = class {
|
|
|
5683
8157
|
files,
|
|
5684
8158
|
success: true
|
|
5685
8159
|
};
|
|
5686
|
-
const manifestPath =
|
|
5687
|
-
await
|
|
8160
|
+
const manifestPath = join18(backupPath, "backup-manifest.json");
|
|
8161
|
+
await writeFile13(manifestPath, JSON.stringify(manifest, null, 2));
|
|
5688
8162
|
await this.cleanupOldBackups();
|
|
5689
8163
|
logger.success(`\u2713 Backup created: ${backupId}`);
|
|
5690
8164
|
return backupId;
|
|
@@ -5697,20 +8171,20 @@ var BackupManager = class {
|
|
|
5697
8171
|
* Backup a file or directory
|
|
5698
8172
|
*/
|
|
5699
8173
|
async backupItem(sourceDir, item, targetDir) {
|
|
5700
|
-
const sourcePath =
|
|
5701
|
-
const targetPath =
|
|
8174
|
+
const sourcePath = join18(sourceDir, item);
|
|
8175
|
+
const targetPath = join18(targetDir, item);
|
|
5702
8176
|
const files = [];
|
|
5703
8177
|
try {
|
|
5704
8178
|
const stats = await stat2(sourcePath);
|
|
5705
8179
|
if (stats.isDirectory()) {
|
|
5706
|
-
await
|
|
5707
|
-
const entries = await
|
|
8180
|
+
await mkdir12(targetPath, { recursive: true });
|
|
8181
|
+
const entries = await readdir9(sourcePath);
|
|
5708
8182
|
for (const entry of entries) {
|
|
5709
8183
|
const entryFiles = await this.backupItem(sourcePath, entry, targetPath);
|
|
5710
8184
|
files.push(...entryFiles);
|
|
5711
8185
|
}
|
|
5712
8186
|
} else if (stats.isFile()) {
|
|
5713
|
-
await
|
|
8187
|
+
await mkdir12(dirname3(targetPath), { recursive: true });
|
|
5714
8188
|
await this.copyFile(sourcePath, targetPath);
|
|
5715
8189
|
const hash = await this.calculateHash(targetPath);
|
|
5716
8190
|
files.push({
|
|
@@ -5728,15 +8202,15 @@ var BackupManager = class {
|
|
|
5728
8202
|
* Copy file with hash calculation
|
|
5729
8203
|
*/
|
|
5730
8204
|
async copyFile(source, target) {
|
|
5731
|
-
const content = await
|
|
5732
|
-
await
|
|
8205
|
+
const content = await readFile11(source);
|
|
8206
|
+
await writeFile13(target, content);
|
|
5733
8207
|
}
|
|
5734
8208
|
/**
|
|
5735
8209
|
* Calculate file hash
|
|
5736
8210
|
*/
|
|
5737
8211
|
async calculateHash(filePath) {
|
|
5738
8212
|
try {
|
|
5739
|
-
const content = await
|
|
8213
|
+
const content = await readFile11(filePath);
|
|
5740
8214
|
return createHash2("sha256").update(content).digest("hex");
|
|
5741
8215
|
} catch {
|
|
5742
8216
|
return "";
|
|
@@ -5747,13 +8221,13 @@ var BackupManager = class {
|
|
|
5747
8221
|
*/
|
|
5748
8222
|
async listBackups() {
|
|
5749
8223
|
try {
|
|
5750
|
-
const entries = await
|
|
8224
|
+
const entries = await readdir9(this.backupsDir);
|
|
5751
8225
|
const backups = [];
|
|
5752
8226
|
for (const entry of entries) {
|
|
5753
|
-
const backupPath =
|
|
5754
|
-
const manifestPath =
|
|
8227
|
+
const backupPath = join18(this.backupsDir, entry);
|
|
8228
|
+
const manifestPath = join18(backupPath, "backup-manifest.json");
|
|
5755
8229
|
try {
|
|
5756
|
-
const manifestContent = await
|
|
8230
|
+
const manifestContent = await readFile11(manifestPath, "utf-8");
|
|
5757
8231
|
const manifest = JSON.parse(manifestContent);
|
|
5758
8232
|
const size = await this.calculateBackupSize(backupPath);
|
|
5759
8233
|
backups.push({
|
|
@@ -5779,9 +8253,9 @@ var BackupManager = class {
|
|
|
5779
8253
|
let totalSize = 0;
|
|
5780
8254
|
try {
|
|
5781
8255
|
const calculate = async (dir) => {
|
|
5782
|
-
const entries = await
|
|
8256
|
+
const entries = await readdir9(dir);
|
|
5783
8257
|
for (const entry of entries) {
|
|
5784
|
-
const entryPath =
|
|
8258
|
+
const entryPath = join18(dir, entry);
|
|
5785
8259
|
const stats = await stat2(entryPath);
|
|
5786
8260
|
if (stats.isDirectory()) {
|
|
5787
8261
|
await calculate(entryPath);
|
|
@@ -5813,9 +8287,9 @@ var BackupManager = class {
|
|
|
5813
8287
|
return false;
|
|
5814
8288
|
}
|
|
5815
8289
|
for (const file of backup.manifest.files) {
|
|
5816
|
-
const sourcePath =
|
|
5817
|
-
const targetPath =
|
|
5818
|
-
await
|
|
8290
|
+
const sourcePath = join18(backup.path, file.path);
|
|
8291
|
+
const targetPath = join18(this.configPath, file.path);
|
|
8292
|
+
await mkdir12(dirname3(targetPath), { recursive: true });
|
|
5819
8293
|
await this.copyFile(sourcePath, targetPath);
|
|
5820
8294
|
}
|
|
5821
8295
|
logger.success(`\u2713 Backup restored: ${backupId}`);
|
|
@@ -5830,10 +8304,10 @@ var BackupManager = class {
|
|
|
5830
8304
|
*/
|
|
5831
8305
|
async validateBackup(backup) {
|
|
5832
8306
|
try {
|
|
5833
|
-
const manifestPath =
|
|
5834
|
-
await
|
|
8307
|
+
const manifestPath = join18(backup.path, "backup-manifest.json");
|
|
8308
|
+
await readFile11(manifestPath, "utf-8");
|
|
5835
8309
|
for (const file of backup.manifest.files) {
|
|
5836
|
-
const filePath =
|
|
8310
|
+
const filePath = join18(backup.path, file.path);
|
|
5837
8311
|
await stat2(filePath);
|
|
5838
8312
|
const currentHash = await this.calculateHash(filePath);
|
|
5839
8313
|
if (currentHash !== file.hash) {
|
|
@@ -5857,9 +8331,9 @@ var BackupManager = class {
|
|
|
5857
8331
|
if (!backup) {
|
|
5858
8332
|
return false;
|
|
5859
8333
|
}
|
|
5860
|
-
const entries = await
|
|
8334
|
+
const entries = await readdir9(backup.path);
|
|
5861
8335
|
for (const entry of entries) {
|
|
5862
|
-
const entryPath =
|
|
8336
|
+
const entryPath = join18(backup.path, entry);
|
|
5863
8337
|
const stats = await stat2(entryPath);
|
|
5864
8338
|
if (stats.isDirectory()) {
|
|
5865
8339
|
await this.removeDirectory(entryPath);
|
|
@@ -5878,9 +8352,9 @@ var BackupManager = class {
|
|
|
5878
8352
|
* Remove directory recursively
|
|
5879
8353
|
*/
|
|
5880
8354
|
async removeDirectory(dirPath) {
|
|
5881
|
-
const entries = await
|
|
8355
|
+
const entries = await readdir9(dirPath);
|
|
5882
8356
|
for (const entry of entries) {
|
|
5883
|
-
const entryPath =
|
|
8357
|
+
const entryPath = join18(dirPath, entry);
|
|
5884
8358
|
const stats = await stat2(entryPath);
|
|
5885
8359
|
if (stats.isDirectory()) {
|
|
5886
8360
|
await this.removeDirectory(entryPath);
|
|
@@ -5926,14 +8400,14 @@ var BackupManager = class {
|
|
|
5926
8400
|
// src/core/migration-manager.ts
|
|
5927
8401
|
init_esm_shims();
|
|
5928
8402
|
init_logger();
|
|
5929
|
-
import { readFile as
|
|
5930
|
-
import { join as
|
|
8403
|
+
import { readFile as readFile12, writeFile as writeFile14, readdir as readdir10 } from "fs/promises";
|
|
8404
|
+
import { join as join19 } from "path";
|
|
5931
8405
|
var MigrationManager = class {
|
|
5932
8406
|
configPath;
|
|
5933
8407
|
migrationsDir;
|
|
5934
8408
|
constructor(configPath) {
|
|
5935
8409
|
this.configPath = configPath;
|
|
5936
|
-
this.migrationsDir =
|
|
8410
|
+
this.migrationsDir = join19(process.cwd(), "src/core/migrations");
|
|
5937
8411
|
}
|
|
5938
8412
|
/**
|
|
5939
8413
|
* Load all available migrations
|
|
@@ -5941,11 +8415,11 @@ var MigrationManager = class {
|
|
|
5941
8415
|
async loadMigrations() {
|
|
5942
8416
|
const migrations = [];
|
|
5943
8417
|
try {
|
|
5944
|
-
const files = await
|
|
8418
|
+
const files = await readdir10(this.migrationsDir);
|
|
5945
8419
|
for (const file of files) {
|
|
5946
8420
|
if (file.endsWith(".js") && file.startsWith("migrate-")) {
|
|
5947
8421
|
try {
|
|
5948
|
-
const module = await import(
|
|
8422
|
+
const module = await import(join19(this.migrationsDir, file));
|
|
5949
8423
|
const migration = module.default || module.migration;
|
|
5950
8424
|
if (migration) {
|
|
5951
8425
|
migrations.push(migration);
|
|
@@ -5964,9 +8438,9 @@ var MigrationManager = class {
|
|
|
5964
8438
|
* Get applied migrations
|
|
5965
8439
|
*/
|
|
5966
8440
|
async getAppliedMigrations() {
|
|
5967
|
-
const migrationHistoryPath =
|
|
8441
|
+
const migrationHistoryPath = join19(this.configPath, ".migration-history.json");
|
|
5968
8442
|
try {
|
|
5969
|
-
const content = await
|
|
8443
|
+
const content = await readFile12(migrationHistoryPath, "utf-8");
|
|
5970
8444
|
const history = JSON.parse(content);
|
|
5971
8445
|
return history.filter((m) => m.status === "completed").map((m) => m.to);
|
|
5972
8446
|
} catch {
|
|
@@ -6052,16 +8526,16 @@ var MigrationManager = class {
|
|
|
6052
8526
|
* Update migration history
|
|
6053
8527
|
*/
|
|
6054
8528
|
async updateMigrationHistory(entries) {
|
|
6055
|
-
const historyPath =
|
|
8529
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6056
8530
|
try {
|
|
6057
8531
|
let history = [];
|
|
6058
8532
|
try {
|
|
6059
|
-
const content = await
|
|
8533
|
+
const content = await readFile12(historyPath, "utf-8");
|
|
6060
8534
|
history = JSON.parse(content);
|
|
6061
8535
|
} catch {
|
|
6062
8536
|
}
|
|
6063
8537
|
history.push(...entries);
|
|
6064
|
-
await
|
|
8538
|
+
await writeFile14(historyPath, JSON.stringify(history, null, 2));
|
|
6065
8539
|
} catch (error) {
|
|
6066
8540
|
logger.error("Failed to update migration history:", error);
|
|
6067
8541
|
}
|
|
@@ -6070,14 +8544,14 @@ var MigrationManager = class {
|
|
|
6070
8544
|
* Update migration history status
|
|
6071
8545
|
*/
|
|
6072
8546
|
async updateMigrationHistoryStatus(version, status) {
|
|
6073
|
-
const historyPath =
|
|
8547
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6074
8548
|
try {
|
|
6075
|
-
const content = await
|
|
8549
|
+
const content = await readFile12(historyPath, "utf-8");
|
|
6076
8550
|
const history = JSON.parse(content);
|
|
6077
8551
|
const updated = history.map(
|
|
6078
8552
|
(m) => m.to === version ? { ...m, status } : m
|
|
6079
8553
|
);
|
|
6080
|
-
await
|
|
8554
|
+
await writeFile14(historyPath, JSON.stringify(updated, null, 2));
|
|
6081
8555
|
} catch (error) {
|
|
6082
8556
|
logger.error("Failed to update migration history status:", error);
|
|
6083
8557
|
}
|
|
@@ -6086,9 +8560,9 @@ var MigrationManager = class {
|
|
|
6086
8560
|
* Get migration history
|
|
6087
8561
|
*/
|
|
6088
8562
|
async getMigrationHistory() {
|
|
6089
|
-
const historyPath =
|
|
8563
|
+
const historyPath = join19(this.configPath, ".migration-history.json");
|
|
6090
8564
|
try {
|
|
6091
|
-
const content = await
|
|
8565
|
+
const content = await readFile12(historyPath, "utf-8");
|
|
6092
8566
|
return JSON.parse(content);
|
|
6093
8567
|
} catch {
|
|
6094
8568
|
return [];
|
|
@@ -6176,7 +8650,7 @@ var SyncEngine = class {
|
|
|
6176
8650
|
}
|
|
6177
8651
|
await this.displayChanges(changes);
|
|
6178
8652
|
if (!options.force) {
|
|
6179
|
-
const { confirmed } = await
|
|
8653
|
+
const { confirmed } = await inquirer3.prompt([{
|
|
6180
8654
|
type: "confirm",
|
|
6181
8655
|
name: "confirmed",
|
|
6182
8656
|
message: "Continue with update?",
|
|
@@ -6257,7 +8731,7 @@ var SyncEngine = class {
|
|
|
6257
8731
|
console.log(chalk3.yellow("No backups available"));
|
|
6258
8732
|
return false;
|
|
6259
8733
|
}
|
|
6260
|
-
const { selectedBackup } = await
|
|
8734
|
+
const { selectedBackup } = await inquirer3.prompt([{
|
|
6261
8735
|
type: "list",
|
|
6262
8736
|
name: "selectedBackup",
|
|
6263
8737
|
message: "Select backup to restore:",
|
|
@@ -6330,7 +8804,7 @@ var SyncEngine = class {
|
|
|
6330
8804
|
\u26A0\uFE0F Conflict detected: ${conflict.skillName}
|
|
6331
8805
|
`));
|
|
6332
8806
|
console.log(chalk3.yellow("Your version differs from official version."));
|
|
6333
|
-
const { action } = await
|
|
8807
|
+
const { action } = await inquirer3.prompt([{
|
|
6334
8808
|
type: "list",
|
|
6335
8809
|
name: "action",
|
|
6336
8810
|
message: "Choose action:",
|
|
@@ -6397,19 +8871,19 @@ var SyncEngine = class {
|
|
|
6397
8871
|
* Install a skill
|
|
6398
8872
|
*/
|
|
6399
8873
|
async installSkill(sourceDir, skill, targetDir) {
|
|
6400
|
-
const sourcePath =
|
|
6401
|
-
const targetPath =
|
|
6402
|
-
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 });
|
|
6403
8877
|
await copyFile(sourcePath, targetPath);
|
|
6404
8878
|
}
|
|
6405
8879
|
/**
|
|
6406
8880
|
* Archive a removed skill
|
|
6407
8881
|
*/
|
|
6408
8882
|
async archiveSkill(targetDir, skill) {
|
|
6409
|
-
const sourcePath =
|
|
6410
|
-
const targetPath =
|
|
8883
|
+
const sourcePath = join20(targetDir, skill.category, `${skill.name}.md`);
|
|
8884
|
+
const targetPath = join20(targetDir, skill.category, `${skill.name}-deprecated.md`);
|
|
6411
8885
|
try {
|
|
6412
|
-
const content = await
|
|
8886
|
+
const content = await readFile13(sourcePath, "utf-8");
|
|
6413
8887
|
const deprecatedNotice = `---
|
|
6414
8888
|
\u26A0\uFE0F DEPRECATED: This skill has been removed
|
|
6415
8889
|
|
|
@@ -6418,8 +8892,8 @@ Reason: Check release notes for replacement
|
|
|
6418
8892
|
---
|
|
6419
8893
|
|
|
6420
8894
|
${content}`;
|
|
6421
|
-
await
|
|
6422
|
-
await
|
|
8895
|
+
await mkdir13(dirname4(targetPath), { recursive: true });
|
|
8896
|
+
await writeFile15(targetPath, deprecatedNotice);
|
|
6423
8897
|
} catch (error) {
|
|
6424
8898
|
if (error.code === "ENOENT") {
|
|
6425
8899
|
console.log(chalk3.yellow(` - ${skill.name} (not found, skipping)`));
|
|
@@ -6650,8 +9124,8 @@ async function configureToolAction(toolName) {
|
|
|
6650
9124
|
// src/cli/commands/misc.ts
|
|
6651
9125
|
init_esm_shims();
|
|
6652
9126
|
import chalk6 from "chalk";
|
|
6653
|
-
import { readFile as
|
|
6654
|
-
import { join as
|
|
9127
|
+
import { readFile as readFile15, writeFile as writeFile17 } from "fs/promises";
|
|
9128
|
+
import { join as join22 } from "path";
|
|
6655
9129
|
init_config();
|
|
6656
9130
|
init_memory();
|
|
6657
9131
|
init_beads();
|
|
@@ -6714,9 +9188,9 @@ function registerModeCommand(program2) {
|
|
|
6714
9188
|
console.log(chalk6.red(`Invalid mode. Available modes: ${validModes.join(", ")}`));
|
|
6715
9189
|
return;
|
|
6716
9190
|
}
|
|
6717
|
-
const configData = JSON.parse(await
|
|
9191
|
+
const configData = JSON.parse(await readFile15(join22(configPath, "aikit.json"), "utf-8"));
|
|
6718
9192
|
configData.mode = mode;
|
|
6719
|
-
await
|
|
9193
|
+
await writeFile17(join22(configPath, "aikit.json"), JSON.stringify(configData, null, 2));
|
|
6720
9194
|
console.log(chalk6.green(`\u2713 Mode set to: ${mode}`));
|
|
6721
9195
|
console.log(chalk6.gray(`Configuration updated at: ${configPath}/aikit.json`));
|
|
6722
9196
|
} catch (error) {
|
|
@@ -6822,8 +9296,36 @@ function registerStatusCommand(program2) {
|
|
|
6822
9296
|
});
|
|
6823
9297
|
}
|
|
6824
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
|
+
|
|
6825
9327
|
// src/cli/index.ts
|
|
6826
|
-
var program = new
|
|
9328
|
+
var program = new Command3();
|
|
6827
9329
|
program.name("aikit").description("Open-source AI coding agent toolkit for OpenCode").version(getVersion());
|
|
6828
9330
|
registerInitCommand(program);
|
|
6829
9331
|
registerInstallCommand(program);
|
|
@@ -6836,6 +9338,7 @@ registerToolsCommand(program);
|
|
|
6836
9338
|
registerPluginsCommand(program);
|
|
6837
9339
|
registerMemoryCommand(program);
|
|
6838
9340
|
registerBeadsCommand(program);
|
|
9341
|
+
registerSessionCommand(program);
|
|
6839
9342
|
registerStatusCommand(program);
|
|
6840
9343
|
program.parse();
|
|
6841
9344
|
//# sourceMappingURL=cli.js.map
|