@tdsoft-tech/aikit 0.1.30 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +28 -17
- package/dist/cli.js +1012 -394
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +384 -67
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +104 -67
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -1
package/dist/cli.js
CHANGED
|
@@ -159,6 +159,7 @@ var init_paths = __esm({
|
|
|
159
159
|
import { readFileSync } from "fs";
|
|
160
160
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
161
161
|
import { dirname, join as join2 } from "path";
|
|
162
|
+
import { compare, gt, valid } from "semver";
|
|
162
163
|
function getVersion() {
|
|
163
164
|
try {
|
|
164
165
|
const __filename2 = fileURLToPath2(import.meta.url);
|
|
@@ -171,6 +172,9 @@ function getVersion() {
|
|
|
171
172
|
return "0.0.0";
|
|
172
173
|
}
|
|
173
174
|
}
|
|
175
|
+
function isGreaterThan(v1, v2) {
|
|
176
|
+
return gt(v1, v2);
|
|
177
|
+
}
|
|
174
178
|
var init_version = __esm({
|
|
175
179
|
"src/utils/version.ts"() {
|
|
176
180
|
"use strict";
|
|
@@ -403,8 +407,8 @@ var init_memory = __esm({
|
|
|
403
407
|
for (const subDir of subDirs) {
|
|
404
408
|
const dirPath = join6(memoryPath, subDir);
|
|
405
409
|
try {
|
|
406
|
-
const { readdir:
|
|
407
|
-
const files = await
|
|
410
|
+
const { readdir: readdir12 } = await import("fs/promises");
|
|
411
|
+
const files = await readdir12(dirPath);
|
|
408
412
|
for (const file of files) {
|
|
409
413
|
if (!file.endsWith(".md")) continue;
|
|
410
414
|
const content = await readFile4(join6(dirPath, file), "utf-8");
|
|
@@ -1684,11 +1688,14 @@ __export(sessions_exports, {
|
|
|
1684
1688
|
SessionManager: () => SessionManager,
|
|
1685
1689
|
formatSession: () => formatSession
|
|
1686
1690
|
});
|
|
1687
|
-
import { readFile as
|
|
1688
|
-
import { join as
|
|
1691
|
+
import { readFile as readFile8, writeFile as writeFile10, readdir as readdir7, mkdir as mkdir10, access as access4, constants as constants4 } from "fs/promises";
|
|
1692
|
+
import { join as join15 } from "path";
|
|
1689
1693
|
import matter3 from "gray-matter";
|
|
1690
1694
|
import { exec as exec2 } from "child_process";
|
|
1691
1695
|
import { promisify as promisify2 } from "util";
|
|
1696
|
+
function sanitizeTTY(tty) {
|
|
1697
|
+
return tty.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
1698
|
+
}
|
|
1692
1699
|
function formatSession(session) {
|
|
1693
1700
|
const startDate = new Date(session.startTime);
|
|
1694
1701
|
const endDate = session.endTime ? new Date(session.endTime) : null;
|
|
@@ -1711,20 +1718,104 @@ var init_sessions = __esm({
|
|
|
1711
1718
|
SessionManager = class {
|
|
1712
1719
|
sessionsDir;
|
|
1713
1720
|
projectPath;
|
|
1721
|
+
aikitDir;
|
|
1714
1722
|
constructor(projectPath) {
|
|
1715
1723
|
this.projectPath = projectPath || process.cwd();
|
|
1716
|
-
this.
|
|
1724
|
+
this.aikitDir = join15(this.projectPath, ".aikit");
|
|
1725
|
+
this.sessionsDir = join15(this.aikitDir, "sessions");
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Get current terminal's TTY path
|
|
1729
|
+
* Uses the `tty` command to get the terminal device path
|
|
1730
|
+
* Returns null if not a TTY (editor environment)
|
|
1731
|
+
*/
|
|
1732
|
+
async getCurrentTTY() {
|
|
1733
|
+
try {
|
|
1734
|
+
const { stdout } = await execAsync2("tty");
|
|
1735
|
+
const tty = stdout.trim();
|
|
1736
|
+
if (tty === "not a tty" || !tty.startsWith("/")) {
|
|
1737
|
+
return null;
|
|
1738
|
+
}
|
|
1739
|
+
return tty;
|
|
1740
|
+
} catch {
|
|
1741
|
+
return null;
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* Get a unique identifier for the current terminal/editor session
|
|
1746
|
+
* Uses TTY if available, otherwise uses PPID (parent process ID)
|
|
1747
|
+
*/
|
|
1748
|
+
async getTerminalIdentifier() {
|
|
1749
|
+
const tty = await this.getCurrentTTY();
|
|
1750
|
+
if (tty) {
|
|
1751
|
+
return sanitizeTTY(tty);
|
|
1752
|
+
}
|
|
1753
|
+
return `ppid-${process.ppid}`;
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Get the current session tracker file path
|
|
1757
|
+
* Always uses per-terminal file (TTY or PPID-based)
|
|
1758
|
+
*/
|
|
1759
|
+
async getSessionTrackerPath() {
|
|
1760
|
+
const identifier = await this.getTerminalIdentifier();
|
|
1761
|
+
return join15(this.sessionsDir, `.current-${identifier}-session`);
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Switch to a different session in the current terminal
|
|
1765
|
+
*/
|
|
1766
|
+
async switchSession(sessionId) {
|
|
1767
|
+
const session = await this.getSession(sessionId);
|
|
1768
|
+
if (!session) {
|
|
1769
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
1770
|
+
}
|
|
1771
|
+
const sessionFile = await this.getSessionTrackerPath();
|
|
1772
|
+
await writeFile10(sessionFile, sessionId);
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Initialize the current terminal's session file
|
|
1776
|
+
* Creates an empty tracker file if it doesn't exist
|
|
1777
|
+
*/
|
|
1778
|
+
async initTerminalSession() {
|
|
1779
|
+
const sessionFile = await this.getSessionTrackerPath();
|
|
1780
|
+
try {
|
|
1781
|
+
await access4(sessionFile);
|
|
1782
|
+
} catch {
|
|
1783
|
+
await writeFile10(sessionFile, "");
|
|
1784
|
+
}
|
|
1785
|
+
return { tracker: sessionFile };
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Get current terminal info (for display purposes)
|
|
1789
|
+
*/
|
|
1790
|
+
async getTerminalInfo() {
|
|
1791
|
+
const tty = await this.getCurrentTTY();
|
|
1792
|
+
const sessionId = await this.getActiveSessionId();
|
|
1793
|
+
return { tty, sessionId };
|
|
1794
|
+
}
|
|
1795
|
+
/**
|
|
1796
|
+
* Check if .aikit directory exists in current project path
|
|
1797
|
+
*/
|
|
1798
|
+
async ensureAikitExists() {
|
|
1799
|
+
try {
|
|
1800
|
+
await access4(this.aikitDir, constants4.R_OK);
|
|
1801
|
+
} catch {
|
|
1802
|
+
throw new Error(
|
|
1803
|
+
`AIKit not initialized in current directory (${this.projectPath}). Run 'aikit init' first to initialize AIKit in this directory.`
|
|
1804
|
+
);
|
|
1805
|
+
}
|
|
1717
1806
|
}
|
|
1718
1807
|
/**
|
|
1719
1808
|
* Initialize sessions directory
|
|
1720
1809
|
*/
|
|
1721
1810
|
async init() {
|
|
1722
|
-
await
|
|
1811
|
+
await this.ensureAikitExists();
|
|
1812
|
+
await mkdir10(this.sessionsDir, { recursive: true });
|
|
1723
1813
|
}
|
|
1724
1814
|
/**
|
|
1725
1815
|
* Start a new session
|
|
1726
1816
|
*/
|
|
1727
1817
|
async startSession(name, goals) {
|
|
1818
|
+
await this.ensureAikitExists();
|
|
1728
1819
|
await this.init();
|
|
1729
1820
|
const now = /* @__PURE__ */ new Date();
|
|
1730
1821
|
const date = now.toISOString().split("T")[0].replace(/-/g, "");
|
|
@@ -1754,6 +1845,7 @@ var init_sessions = __esm({
|
|
|
1754
1845
|
* Update current session with notes
|
|
1755
1846
|
*/
|
|
1756
1847
|
async updateSession(notes) {
|
|
1848
|
+
await this.ensureAikitExists();
|
|
1757
1849
|
const sessionId = await this.getActiveSessionId();
|
|
1758
1850
|
if (!sessionId) {
|
|
1759
1851
|
throw new Error("No active session. Use startSession() first.");
|
|
@@ -1783,6 +1875,7 @@ var init_sessions = __esm({
|
|
|
1783
1875
|
* End current session and generate summary
|
|
1784
1876
|
*/
|
|
1785
1877
|
async endSession() {
|
|
1878
|
+
await this.ensureAikitExists();
|
|
1786
1879
|
const sessionId = await this.getActiveSessionId();
|
|
1787
1880
|
if (!sessionId) {
|
|
1788
1881
|
throw new Error("No active session. Use startSession() first.");
|
|
@@ -1810,6 +1903,7 @@ var init_sessions = __esm({
|
|
|
1810
1903
|
* Get current active session
|
|
1811
1904
|
*/
|
|
1812
1905
|
async getCurrentSession() {
|
|
1906
|
+
await this.ensureAikitExists();
|
|
1813
1907
|
const sessionId = await this.getActiveSessionId();
|
|
1814
1908
|
if (!sessionId) return null;
|
|
1815
1909
|
return this.getSession(sessionId);
|
|
@@ -1818,6 +1912,7 @@ var init_sessions = __esm({
|
|
|
1818
1912
|
* Get all sessions
|
|
1819
1913
|
*/
|
|
1820
1914
|
async listSessions() {
|
|
1915
|
+
await this.ensureAikitExists();
|
|
1821
1916
|
try {
|
|
1822
1917
|
const files = await readdir7(this.sessionsDir);
|
|
1823
1918
|
const sessions = [];
|
|
@@ -1832,17 +1927,21 @@ var init_sessions = __esm({
|
|
|
1832
1927
|
return sessions.sort(
|
|
1833
1928
|
(a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
|
|
1834
1929
|
);
|
|
1835
|
-
} catch {
|
|
1836
|
-
|
|
1930
|
+
} catch (error) {
|
|
1931
|
+
if (error.code === "ENOENT") {
|
|
1932
|
+
return [];
|
|
1933
|
+
}
|
|
1934
|
+
throw error;
|
|
1837
1935
|
}
|
|
1838
1936
|
}
|
|
1839
1937
|
/**
|
|
1840
1938
|
* Get specific session
|
|
1841
1939
|
*/
|
|
1842
1940
|
async getSession(id) {
|
|
1843
|
-
|
|
1941
|
+
await this.ensureAikitExists();
|
|
1942
|
+
const filePath = join15(this.sessionsDir, `${id}.md`);
|
|
1844
1943
|
try {
|
|
1845
|
-
const content = await
|
|
1944
|
+
const content = await readFile8(filePath, "utf-8");
|
|
1846
1945
|
const { data, content: body } = matter3(content);
|
|
1847
1946
|
const updates = this.parseUpdates(body);
|
|
1848
1947
|
return {
|
|
@@ -1865,35 +1964,88 @@ var init_sessions = __esm({
|
|
|
1865
1964
|
const sessions = await this.listSessions();
|
|
1866
1965
|
const lowerQuery = query.toLowerCase();
|
|
1867
1966
|
return sessions.filter(
|
|
1868
|
-
(session) => session.name.toLowerCase().includes(lowerQuery) || session.id.toLowerCase().includes(lowerQuery) || session.goals
|
|
1967
|
+
(session) => session.name.toLowerCase().includes(lowerQuery) || session.id.toLowerCase().includes(lowerQuery) || Array.isArray(session.goals) && session.goals.some(
|
|
1968
|
+
(g) => typeof g === "string" && g.toLowerCase().includes(lowerQuery)
|
|
1969
|
+
) || session.updates.some((u) => u.notes?.toLowerCase().includes(lowerQuery))
|
|
1869
1970
|
);
|
|
1870
1971
|
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Resume a past session (set as active)
|
|
1974
|
+
* Supports partial ID matching and "latest" keyword
|
|
1975
|
+
*/
|
|
1976
|
+
async resumeSession(idOrLatest) {
|
|
1977
|
+
await this.ensureAikitExists();
|
|
1978
|
+
let session = null;
|
|
1979
|
+
if (idOrLatest === "latest") {
|
|
1980
|
+
const sessions = await this.listSessions();
|
|
1981
|
+
if (sessions.length === 0) {
|
|
1982
|
+
throw new Error("No sessions found to resume");
|
|
1983
|
+
}
|
|
1984
|
+
session = sessions[0];
|
|
1985
|
+
} else {
|
|
1986
|
+
session = await this.getSession(idOrLatest);
|
|
1987
|
+
if (!session) {
|
|
1988
|
+
const sessions = await this.listSessions();
|
|
1989
|
+
const matches = sessions.filter((s) => s.id.startsWith(idOrLatest));
|
|
1990
|
+
if (matches.length === 0) {
|
|
1991
|
+
throw new Error(`Session not found: ${idOrLatest}`);
|
|
1992
|
+
}
|
|
1993
|
+
if (matches.length > 1) {
|
|
1994
|
+
throw new Error(
|
|
1995
|
+
`Multiple sessions match "${idOrLatest}": ${matches.map((s) => s.id).join(", ")}. Please use a more specific ID.`
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
session = matches[0];
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
if (!session) {
|
|
2002
|
+
throw new Error(`Session not found: ${idOrLatest}`);
|
|
2003
|
+
}
|
|
2004
|
+
const currentSessionId = await this.getActiveSessionId();
|
|
2005
|
+
if (currentSessionId === session.id) {
|
|
2006
|
+
return session;
|
|
2007
|
+
}
|
|
2008
|
+
await this.setActiveSession(session.id);
|
|
2009
|
+
if (session.status === "ended") {
|
|
2010
|
+
session.status = "active";
|
|
2011
|
+
session.endTime = void 0;
|
|
2012
|
+
session.updates.push({
|
|
2013
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2014
|
+
notes: "Session resumed",
|
|
2015
|
+
gitBranch: (await this.getGitState()).branch
|
|
2016
|
+
});
|
|
2017
|
+
await this.saveSession(session);
|
|
2018
|
+
}
|
|
2019
|
+
return session;
|
|
2020
|
+
}
|
|
1871
2021
|
/**
|
|
1872
2022
|
* Get active session ID
|
|
2023
|
+
* Reads from the current session tracker file
|
|
1873
2024
|
*/
|
|
1874
2025
|
async getActiveSessionId() {
|
|
1875
|
-
const
|
|
2026
|
+
const sessionFile = await this.getSessionTrackerPath();
|
|
1876
2027
|
try {
|
|
1877
|
-
const content = await
|
|
1878
|
-
return content.trim();
|
|
2028
|
+
const content = await readFile8(sessionFile, "utf-8");
|
|
2029
|
+
return content.trim() || null;
|
|
1879
2030
|
} catch {
|
|
1880
2031
|
return null;
|
|
1881
2032
|
}
|
|
1882
2033
|
}
|
|
1883
2034
|
/**
|
|
1884
|
-
* Set active session
|
|
2035
|
+
* Set active session for current terminal
|
|
2036
|
+
* Writes to the current session tracker file
|
|
1885
2037
|
*/
|
|
1886
2038
|
async setActiveSession(id) {
|
|
1887
|
-
const
|
|
1888
|
-
await
|
|
2039
|
+
const sessionFile = await this.getSessionTrackerPath();
|
|
2040
|
+
await writeFile10(sessionFile, id);
|
|
1889
2041
|
}
|
|
1890
2042
|
/**
|
|
1891
|
-
* Clear active session
|
|
2043
|
+
* Clear active session for current terminal
|
|
1892
2044
|
*/
|
|
1893
2045
|
async clearActiveSession() {
|
|
1894
|
-
const
|
|
2046
|
+
const sessionFile = await this.getSessionTrackerPath();
|
|
1895
2047
|
try {
|
|
1896
|
-
await
|
|
2048
|
+
await writeFile10(sessionFile, "");
|
|
1897
2049
|
} catch {
|
|
1898
2050
|
}
|
|
1899
2051
|
}
|
|
@@ -1901,7 +2053,7 @@ var init_sessions = __esm({
|
|
|
1901
2053
|
* Save session to file
|
|
1902
2054
|
*/
|
|
1903
2055
|
async saveSession(session) {
|
|
1904
|
-
const filePath =
|
|
2056
|
+
const filePath = join15(this.sessionsDir, `${session.id}.md`);
|
|
1905
2057
|
const updatesMarkdown = session.updates.map((update) => {
|
|
1906
2058
|
const date = new Date(update.timestamp);
|
|
1907
2059
|
const dateStr = date.toLocaleString();
|
|
@@ -1940,7 +2092,7 @@ var init_sessions = __esm({
|
|
|
1940
2092
|
${session.endTime ? `**Ended:** ${new Date(session.endTime).toLocaleString()}` : ""}
|
|
1941
2093
|
|
|
1942
2094
|
## Goals
|
|
1943
|
-
${session.goals.map((g
|
|
2095
|
+
${session.goals.map((g) => `- [ ] ${g}`).join("\n")}
|
|
1944
2096
|
|
|
1945
2097
|
## Progress
|
|
1946
2098
|
|
|
@@ -1950,7 +2102,7 @@ ${updatesMarkdown}
|
|
|
1950
2102
|
${this.generateSummary(session)}
|
|
1951
2103
|
`;
|
|
1952
2104
|
const fileContent = matter3.stringify(content, frontmatter);
|
|
1953
|
-
await
|
|
2105
|
+
await writeFile10(filePath, fileContent);
|
|
1954
2106
|
}
|
|
1955
2107
|
/**
|
|
1956
2108
|
* Generate session summary
|
|
@@ -2076,14 +2228,16 @@ ${this.generateSummary(session)}
|
|
|
2076
2228
|
}
|
|
2077
2229
|
/**
|
|
2078
2230
|
* Get current Beads task
|
|
2231
|
+
* NOTE: This only reads Beads metadata for session updates.
|
|
2232
|
+
* Sessions are NEVER stored in .beads - they are always in .aikit/sessions
|
|
2079
2233
|
*/
|
|
2080
2234
|
async getCurrentBeadsTask() {
|
|
2081
|
-
const beadsDir =
|
|
2235
|
+
const beadsDir = join15(this.projectPath, ".beads");
|
|
2082
2236
|
try {
|
|
2083
2237
|
const files = await readdir7(beadsDir);
|
|
2084
2238
|
const beadFiles = files.filter((f) => f.startsWith("bead-") && f.endsWith(".md"));
|
|
2085
2239
|
for (const file of beadFiles) {
|
|
2086
|
-
const content = await
|
|
2240
|
+
const content = await readFile8(join15(beadsDir, file), "utf-8");
|
|
2087
2241
|
const statusMatch = content.match(/^status:\s*(\w+)/m);
|
|
2088
2242
|
const id = file.replace(".md", "");
|
|
2089
2243
|
if (statusMatch && (statusMatch[1] === "in-progress" || statusMatch[1] === "todo")) {
|
|
@@ -2107,8 +2261,8 @@ var tool_config_exports = {};
|
|
|
2107
2261
|
__export(tool_config_exports, {
|
|
2108
2262
|
ToolConfigManager: () => ToolConfigManager
|
|
2109
2263
|
});
|
|
2110
|
-
import { readFile as
|
|
2111
|
-
import { join as
|
|
2264
|
+
import { readFile as readFile15, writeFile as writeFile18, mkdir as mkdir16, access as access7, constants as constants5 } from "fs/promises";
|
|
2265
|
+
import { join as join23 } from "path";
|
|
2112
2266
|
import { z as z3 } from "zod";
|
|
2113
2267
|
var ToolConfigSchema, REGISTERED_TOOLS, ToolConfigManager;
|
|
2114
2268
|
var init_tool_config = __esm({
|
|
@@ -2136,7 +2290,7 @@ var init_tool_config = __esm({
|
|
|
2136
2290
|
toolsConfigPath;
|
|
2137
2291
|
constructor(config) {
|
|
2138
2292
|
this.config = config;
|
|
2139
|
-
this.toolsConfigPath =
|
|
2293
|
+
this.toolsConfigPath = join23(this.config.configPath, "config", "tools.json");
|
|
2140
2294
|
}
|
|
2141
2295
|
/**
|
|
2142
2296
|
* Get all registered tools with their current status
|
|
@@ -2219,8 +2373,8 @@ var init_tool_config = __esm({
|
|
|
2219
2373
|
*/
|
|
2220
2374
|
async loadConfigs() {
|
|
2221
2375
|
try {
|
|
2222
|
-
await access7(this.toolsConfigPath,
|
|
2223
|
-
const content = await
|
|
2376
|
+
await access7(this.toolsConfigPath, constants5.R_OK);
|
|
2377
|
+
const content = await readFile15(this.toolsConfigPath, "utf-8");
|
|
2224
2378
|
return JSON.parse(content);
|
|
2225
2379
|
} catch {
|
|
2226
2380
|
return {};
|
|
@@ -2230,9 +2384,9 @@ var init_tool_config = __esm({
|
|
|
2230
2384
|
* Save configurations
|
|
2231
2385
|
*/
|
|
2232
2386
|
async saveConfigs(configs) {
|
|
2233
|
-
const configDir =
|
|
2234
|
-
await
|
|
2235
|
-
await
|
|
2387
|
+
const configDir = join23(this.config.configPath, "config");
|
|
2388
|
+
await mkdir16(configDir, { recursive: true });
|
|
2389
|
+
await writeFile18(this.toolsConfigPath, JSON.stringify(configs, null, 2));
|
|
2236
2390
|
}
|
|
2237
2391
|
};
|
|
2238
2392
|
}
|
|
@@ -4161,14 +4315,14 @@ Total: 2 checkpoints
|
|
|
4161
4315
|
init_esm_shims();
|
|
4162
4316
|
var SESSION_COMMANDS = [
|
|
4163
4317
|
{
|
|
4164
|
-
name: "session
|
|
4318
|
+
name: "session-start",
|
|
4165
4319
|
description: "Start a new development session",
|
|
4166
4320
|
category: "session",
|
|
4167
|
-
usage: "/session
|
|
4321
|
+
usage: "/session-start [name]",
|
|
4168
4322
|
examples: [
|
|
4169
|
-
"/session
|
|
4170
|
-
"/session
|
|
4171
|
-
'/session
|
|
4323
|
+
"/session-start",
|
|
4324
|
+
"/session-start authentication-refactor",
|
|
4325
|
+
'/session-start "Add user profile feature"'
|
|
4172
4326
|
],
|
|
4173
4327
|
content: `Start a new development session to track your work.
|
|
4174
4328
|
|
|
@@ -4176,47 +4330,70 @@ var SESSION_COMMANDS = [
|
|
|
4176
4330
|
|
|
4177
4331
|
Session name: $ARGUMENTS
|
|
4178
4332
|
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4333
|
+
**IMPORTANT - Scope Rules:**
|
|
4334
|
+
- Sessions are scoped to the CURRENT working directory
|
|
4335
|
+
- AIKit will NOT search parent directories for .aikit
|
|
4336
|
+
- If .aikit doesn't exist in current directory, you MUST run 'aikit init' first
|
|
4337
|
+
- Each directory needs its own .aikit if you want separate session tracking
|
|
4338
|
+
|
|
4339
|
+
1. **Check Current Directory:**
|
|
4340
|
+
- Verify .aikit exists in current directory (process.cwd())
|
|
4341
|
+
- If not, inform user to run 'aikit init' first
|
|
4342
|
+
- DO NOT search parent directories
|
|
4184
4343
|
|
|
4185
|
-
2. **
|
|
4344
|
+
2. **Create Session:**
|
|
4345
|
+
- Generate session ID with timestamp
|
|
4346
|
+
- Create session file in .aikit/sessions/ (current directory only)
|
|
4347
|
+
- Determine session tracker file:
|
|
4348
|
+
* Try 'tty' command to get terminal identifier
|
|
4349
|
+
* If 'tty' works, use .aikit/sessions/.current-<sanitized_tty>-session
|
|
4350
|
+
(replace '/' with '-' in TTY path)
|
|
4351
|
+
* If 'tty' fails with "not a tty", get parent PID using: ps -o ppid= -p $$
|
|
4352
|
+
Use .aikit/sessions/.current-ppid-<PPID>-session
|
|
4353
|
+
(each Claude Code window has unique PPID)
|
|
4354
|
+
- Write session ID to the tracker file
|
|
4355
|
+
- **Capture initial git state (scoped to current directory):**
|
|
4356
|
+
* First check if .git exists in CURRENT directory (process.cwd())
|
|
4357
|
+
* ONLY capture git state if .git exists in current directory
|
|
4358
|
+
* DO NOT search parent directories for git repo
|
|
4359
|
+
* If no .git in current directory, skip git state capture
|
|
4360
|
+
|
|
4361
|
+
3. **Set Goals:**
|
|
4186
4362
|
- Ask user for session goals if not provided
|
|
4187
4363
|
- Document what you want to accomplish
|
|
4188
4364
|
- Link to Beads task if active
|
|
4189
4365
|
|
|
4190
|
-
|
|
4366
|
+
4. **Session Started:**
|
|
4191
4367
|
- Session ID: YYYY-MM-DD-HHMM[-name]
|
|
4192
4368
|
- Status: active
|
|
4193
4369
|
- Ready for updates
|
|
4194
4370
|
|
|
4195
4371
|
## What Gets Tracked
|
|
4196
4372
|
- Session start time
|
|
4197
|
-
- Git branch and commits
|
|
4198
|
-
- Modified files
|
|
4373
|
+
- Git branch and commits (ONLY if .git exists in current directory)
|
|
4374
|
+
- Modified files (ONLY if .git exists in current directory)
|
|
4199
4375
|
- Progress notes
|
|
4200
4376
|
- Linked Beads task
|
|
4201
4377
|
|
|
4202
4378
|
## Session File Location
|
|
4203
|
-
.aikit/sessions/YYYY-MM-DD-HHMM[-name].md
|
|
4379
|
+
Current directory: .aikit/sessions/YYYY-MM-DD-HHMM[-name].md
|
|
4380
|
+
(Always relative to process.cwd(), never parent directories)
|
|
4204
4381
|
|
|
4205
4382
|
## Examples
|
|
4206
4383
|
|
|
4207
4384
|
Start unnamed session:
|
|
4208
4385
|
\`\`\`
|
|
4209
|
-
/session
|
|
4386
|
+
/session-start
|
|
4210
4387
|
\`\`\`
|
|
4211
4388
|
|
|
4212
4389
|
Start with descriptive name:
|
|
4213
4390
|
\`\`\`
|
|
4214
|
-
/session
|
|
4391
|
+
/session-start auth-refactor
|
|
4215
4392
|
\`\`\`
|
|
4216
4393
|
|
|
4217
4394
|
Start with goal:
|
|
4218
4395
|
\`\`\`
|
|
4219
|
-
/session
|
|
4396
|
+
/session-start "Implement OAuth 2.0"
|
|
4220
4397
|
Goals:
|
|
4221
4398
|
- Add Google OAuth
|
|
4222
4399
|
- Add JWT token handling
|
|
@@ -4225,18 +4402,18 @@ Goals:
|
|
|
4225
4402
|
## Notes
|
|
4226
4403
|
- Session files are markdown with frontmatter
|
|
4227
4404
|
- Sessions persist across AI conversations
|
|
4228
|
-
- Use /session
|
|
4229
|
-
- Use /session
|
|
4405
|
+
- Use /session-update to add progress notes
|
|
4406
|
+
- Use /session-end to close and summarize`
|
|
4230
4407
|
},
|
|
4231
4408
|
{
|
|
4232
|
-
name: "session
|
|
4409
|
+
name: "session-update",
|
|
4233
4410
|
description: "Add progress notes to current session",
|
|
4234
4411
|
category: "session",
|
|
4235
|
-
usage: "/session
|
|
4412
|
+
usage: "/session-update [notes]",
|
|
4236
4413
|
examples: [
|
|
4237
|
-
"/session
|
|
4238
|
-
"/session
|
|
4239
|
-
'/session
|
|
4414
|
+
"/session-update",
|
|
4415
|
+
"/session-update Fixed authentication bug",
|
|
4416
|
+
'/session-update "Added JWT middleware"'
|
|
4240
4417
|
],
|
|
4241
4418
|
content: `Update the current session with progress notes.
|
|
4242
4419
|
|
|
@@ -4245,19 +4422,28 @@ Goals:
|
|
|
4245
4422
|
Progress notes: $ARGUMENTS
|
|
4246
4423
|
|
|
4247
4424
|
1. **Check Active Session:**
|
|
4248
|
-
-
|
|
4425
|
+
- Determine session tracker file:
|
|
4426
|
+
* Try 'tty' command to get terminal identifier
|
|
4427
|
+
* If 'tty' works, read .aikit/sessions/.current-<sanitized_tty>-session
|
|
4428
|
+
* If 'tty' fails, get parent PID and read .aikit/sessions/.current-ppid-<PPID>-session
|
|
4249
4429
|
- Load session file
|
|
4250
4430
|
|
|
4251
4431
|
2. **Capture Current State:**
|
|
4252
|
-
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4432
|
+
- **IMPORTANT - Git State Scope:**
|
|
4433
|
+
* First check if .git exists in CURRENT directory (process.cwd())
|
|
4434
|
+
* ONLY capture git state if .git exists in current directory
|
|
4435
|
+
* DO NOT search parent directories for git repo
|
|
4436
|
+
* If no .git in current directory, skip git state capture
|
|
4437
|
+
- If .git exists in current directory:
|
|
4438
|
+
* Get current git branch
|
|
4439
|
+
* Count git commits
|
|
4440
|
+
* List modified files
|
|
4441
|
+
- Check active Beads task (from .beads directory if exists)
|
|
4256
4442
|
|
|
4257
4443
|
3. **Add Update:**
|
|
4258
4444
|
- Add timestamped update entry
|
|
4259
4445
|
- Include your notes (or auto-generate)
|
|
4260
|
-
- Include git state
|
|
4446
|
+
- Include git state ONLY if .git exists in current directory
|
|
4261
4447
|
- Include Beads task if active
|
|
4262
4448
|
|
|
4263
4449
|
4. **Save Session:**
|
|
@@ -4267,27 +4453,25 @@ Progress notes: $ARGUMENTS
|
|
|
4267
4453
|
## What Gets Captured
|
|
4268
4454
|
- Timestamp of update
|
|
4269
4455
|
- Your progress notes
|
|
4270
|
-
-
|
|
4271
|
-
- Number of commits
|
|
4272
|
-
- List of modified files
|
|
4456
|
+
- Git state (branch, commits, files) - ONLY if .git exists in current directory
|
|
4273
4457
|
- Active Beads task (if any)
|
|
4274
4458
|
|
|
4275
4459
|
## Examples
|
|
4276
4460
|
|
|
4277
4461
|
Auto-update (no notes):
|
|
4278
4462
|
\`\`\`
|
|
4279
|
-
/session
|
|
4463
|
+
/session-update
|
|
4280
4464
|
\`\`\`
|
|
4281
4465
|
*Auto-generates summary of recent work*
|
|
4282
4466
|
|
|
4283
4467
|
With specific notes:
|
|
4284
4468
|
\`\`\`
|
|
4285
|
-
/session
|
|
4469
|
+
/session-update Fixed Next.js params issue
|
|
4286
4470
|
\`\`\`
|
|
4287
4471
|
|
|
4288
4472
|
With detailed notes:
|
|
4289
4473
|
\`\`\`
|
|
4290
|
-
/session
|
|
4474
|
+
/session-update "Implemented OAuth flow with Google provider. Added callback handler and token validation."
|
|
4291
4475
|
\`\`\`
|
|
4292
4476
|
|
|
4293
4477
|
## Notes
|
|
@@ -4297,11 +4481,11 @@ With detailed notes:
|
|
|
4297
4481
|
- Beads task automatically linked`
|
|
4298
4482
|
},
|
|
4299
4483
|
{
|
|
4300
|
-
name: "session
|
|
4484
|
+
name: "session-end",
|
|
4301
4485
|
description: "End current session with summary",
|
|
4302
4486
|
category: "session",
|
|
4303
|
-
usage: "/session
|
|
4304
|
-
examples: ["/session
|
|
4487
|
+
usage: "/session-end",
|
|
4488
|
+
examples: ["/session-end"],
|
|
4305
4489
|
content: `End the current session and generate a comprehensive summary.
|
|
4306
4490
|
|
|
4307
4491
|
## Workflow
|
|
@@ -4331,7 +4515,10 @@ With detailed notes:
|
|
|
4331
4515
|
- Mark session as ended
|
|
4332
4516
|
- Set end time
|
|
4333
4517
|
- Save session file
|
|
4334
|
-
-
|
|
4518
|
+
- Determine session tracker file:
|
|
4519
|
+
* Try 'tty' command to get terminal identifier
|
|
4520
|
+
* If 'tty' works, clear .aikit/sessions/.current-<sanitized_tty>-session
|
|
4521
|
+
* If 'tty' fails, get parent PID and clear .aikit/sessions/.current-ppid-<PPID>-session
|
|
4335
4522
|
|
|
4336
4523
|
## Summary Includes
|
|
4337
4524
|
|
|
@@ -4386,17 +4573,20 @@ Lessons:
|
|
|
4386
4573
|
- Can start new session after ending`
|
|
4387
4574
|
},
|
|
4388
4575
|
{
|
|
4389
|
-
name: "session
|
|
4576
|
+
name: "session-current",
|
|
4390
4577
|
description: "Show current active session",
|
|
4391
4578
|
category: "session",
|
|
4392
|
-
usage: "/session
|
|
4393
|
-
examples: ["/session
|
|
4579
|
+
usage: "/session-current",
|
|
4580
|
+
examples: ["/session-current"],
|
|
4394
4581
|
content: `Display information about the current active session.
|
|
4395
4582
|
|
|
4396
4583
|
## Workflow
|
|
4397
4584
|
|
|
4398
4585
|
1. **Check Active Session:**
|
|
4399
|
-
-
|
|
4586
|
+
- Determine session tracker file:
|
|
4587
|
+
* Try 'tty' command to get terminal identifier
|
|
4588
|
+
* If 'tty' works, read .aikit/sessions/.current-<sanitized_tty>-session
|
|
4589
|
+
* If 'tty' fails, get parent PID and read .aikit/sessions/.current-ppid-<PPID>-session
|
|
4400
4590
|
- Load session data
|
|
4401
4591
|
|
|
4402
4592
|
2. **Display Session Info:**
|
|
@@ -4436,8 +4626,8 @@ Beads Task:
|
|
|
4436
4626
|
- bead-001 (in-progress)
|
|
4437
4627
|
|
|
4438
4628
|
Commands:
|
|
4439
|
-
/session
|
|
4440
|
-
/session
|
|
4629
|
+
/session-update [notes] - Add progress
|
|
4630
|
+
/session-end - Close session
|
|
4441
4631
|
\`\`\`
|
|
4442
4632
|
|
|
4443
4633
|
## Notes
|
|
@@ -4446,18 +4636,18 @@ Commands:
|
|
|
4446
4636
|
- Displays recent progress`
|
|
4447
4637
|
},
|
|
4448
4638
|
{
|
|
4449
|
-
name: "session
|
|
4639
|
+
name: "session-list",
|
|
4450
4640
|
description: "List all sessions",
|
|
4451
4641
|
category: "session",
|
|
4452
|
-
usage: "/session
|
|
4453
|
-
examples: ["/session
|
|
4642
|
+
usage: "/session-list",
|
|
4643
|
+
examples: ["/session-list"],
|
|
4454
4644
|
content: `List all development sessions with summaries.
|
|
4455
4645
|
|
|
4456
4646
|
## Workflow
|
|
4457
4647
|
|
|
4458
4648
|
1. **Scan Sessions Directory:**
|
|
4459
4649
|
- Find all .md files in .aikit/sessions/
|
|
4460
|
-
- Exclude .current
|
|
4650
|
+
- Exclude all .current-*-session files (terminal trackers)
|
|
4461
4651
|
|
|
4462
4652
|
2. **Sort by Date:**
|
|
4463
4653
|
- Newest sessions first
|
|
@@ -4500,16 +4690,16 @@ Total: 3 sessions
|
|
|
4500
4690
|
- Shows both active and ended sessions
|
|
4501
4691
|
- Most recent sessions first
|
|
4502
4692
|
- Active session highlighted
|
|
4503
|
-
- Use /session
|
|
4693
|
+
- Use /session-show <id> for details`
|
|
4504
4694
|
},
|
|
4505
4695
|
{
|
|
4506
|
-
name: "session
|
|
4696
|
+
name: "session-show",
|
|
4507
4697
|
description: "Show details of a specific session",
|
|
4508
4698
|
category: "session",
|
|
4509
|
-
usage: "/session
|
|
4699
|
+
usage: "/session-show <session-id>",
|
|
4510
4700
|
examples: [
|
|
4511
|
-
"/session
|
|
4512
|
-
"/session
|
|
4701
|
+
"/session-show 2025-01-02-1430",
|
|
4702
|
+
"/session-show 2025-01-02-1430-auth-refactor"
|
|
4513
4703
|
],
|
|
4514
4704
|
content: `Display full details of a specific session.
|
|
4515
4705
|
|
|
@@ -4580,14 +4770,14 @@ Successfully refactored authentication system...
|
|
|
4580
4770
|
- Full session details displayed`
|
|
4581
4771
|
},
|
|
4582
4772
|
{
|
|
4583
|
-
name: "session
|
|
4773
|
+
name: "session-search",
|
|
4584
4774
|
description: "Search sessions by keyword",
|
|
4585
4775
|
category: "session",
|
|
4586
|
-
usage: "/session
|
|
4776
|
+
usage: "/session-search <query>",
|
|
4587
4777
|
examples: [
|
|
4588
|
-
"/session
|
|
4589
|
-
'/session
|
|
4590
|
-
"/session
|
|
4778
|
+
"/session-search oauth",
|
|
4779
|
+
'/session-search "jwt"',
|
|
4780
|
+
"/session-search authentication"
|
|
4591
4781
|
],
|
|
4592
4782
|
content: `Search for sessions matching a keyword.
|
|
4593
4783
|
|
|
@@ -4608,7 +4798,7 @@ Search query: $ARGUMENTS
|
|
|
4608
4798
|
|
|
4609
4799
|
3. **Show Actions:**
|
|
4610
4800
|
- List matching sessions
|
|
4611
|
-
- Suggest /session
|
|
4801
|
+
- Suggest /session-show for details
|
|
4612
4802
|
|
|
4613
4803
|
## Example Output
|
|
4614
4804
|
\`\`\`
|
|
@@ -4638,14 +4828,14 @@ Total: 2 matching sessions
|
|
|
4638
4828
|
- Use partial IDs too`
|
|
4639
4829
|
},
|
|
4640
4830
|
{
|
|
4641
|
-
name: "session
|
|
4831
|
+
name: "session-resume",
|
|
4642
4832
|
description: "Resume a past session (load context)",
|
|
4643
4833
|
category: "session",
|
|
4644
|
-
usage: "/session
|
|
4834
|
+
usage: "/session-resume <session-id>",
|
|
4645
4835
|
examples: [
|
|
4646
|
-
"/session
|
|
4647
|
-
"/session
|
|
4648
|
-
"/session
|
|
4836
|
+
"/session-resume latest",
|
|
4837
|
+
"/session-resume 2025-01-02-1430",
|
|
4838
|
+
"/session-resume 2025-01-02-1430-auth-refactor"
|
|
4649
4839
|
],
|
|
4650
4840
|
content: `Load context from a past session to resume work.
|
|
4651
4841
|
|
|
@@ -6597,6 +6787,282 @@ init_beads();
|
|
|
6597
6787
|
init_esm_shims();
|
|
6598
6788
|
init_logger();
|
|
6599
6789
|
|
|
6790
|
+
// src/core/update-manager.ts
|
|
6791
|
+
init_esm_shims();
|
|
6792
|
+
init_version();
|
|
6793
|
+
import chalk2 from "chalk";
|
|
6794
|
+
|
|
6795
|
+
// src/utils/npm-client.ts
|
|
6796
|
+
init_esm_shims();
|
|
6797
|
+
import https from "https";
|
|
6798
|
+
async function getLatestVersion(packageName) {
|
|
6799
|
+
return new Promise((resolve) => {
|
|
6800
|
+
const url = `https://registry.npmjs.org/${packageName}`;
|
|
6801
|
+
https.get(url, (res) => {
|
|
6802
|
+
let data = "";
|
|
6803
|
+
res.on("data", (chunk) => {
|
|
6804
|
+
data += chunk;
|
|
6805
|
+
});
|
|
6806
|
+
res.on("end", () => {
|
|
6807
|
+
try {
|
|
6808
|
+
if (res.statusCode === 200) {
|
|
6809
|
+
const packageData = JSON.parse(data);
|
|
6810
|
+
const latestVersion = packageData["dist-tags"]?.latest;
|
|
6811
|
+
resolve(latestVersion || null);
|
|
6812
|
+
} else {
|
|
6813
|
+
resolve(null);
|
|
6814
|
+
}
|
|
6815
|
+
} catch {
|
|
6816
|
+
resolve(null);
|
|
6817
|
+
}
|
|
6818
|
+
});
|
|
6819
|
+
}).on("error", () => {
|
|
6820
|
+
resolve(null);
|
|
6821
|
+
}).setTimeout(5e3, () => {
|
|
6822
|
+
resolve(null);
|
|
6823
|
+
});
|
|
6824
|
+
});
|
|
6825
|
+
}
|
|
6826
|
+
|
|
6827
|
+
// src/utils/update-cache.ts
|
|
6828
|
+
init_esm_shims();
|
|
6829
|
+
init_paths();
|
|
6830
|
+
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
6831
|
+
import { existsSync as existsSync5 } from "fs";
|
|
6832
|
+
import { join as join12 } from "path";
|
|
6833
|
+
var CACHE_FILE = ".update-cache.json";
|
|
6834
|
+
var DEFAULT_CACHE = {
|
|
6835
|
+
lastCheckTime: 0,
|
|
6836
|
+
lastCheckedVersion: "0.0.0",
|
|
6837
|
+
errorCount: 0
|
|
6838
|
+
};
|
|
6839
|
+
function getCachePath() {
|
|
6840
|
+
const configDir = paths.globalConfig();
|
|
6841
|
+
return join12(configDir, CACHE_FILE);
|
|
6842
|
+
}
|
|
6843
|
+
async function readCache() {
|
|
6844
|
+
try {
|
|
6845
|
+
const cachePath = getCachePath();
|
|
6846
|
+
if (!existsSync5(cachePath)) {
|
|
6847
|
+
return DEFAULT_CACHE;
|
|
6848
|
+
}
|
|
6849
|
+
const content = await readFile7(cachePath, "utf-8");
|
|
6850
|
+
const data = JSON.parse(content);
|
|
6851
|
+
return { ...DEFAULT_CACHE, ...data };
|
|
6852
|
+
} catch {
|
|
6853
|
+
return DEFAULT_CACHE;
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
async function writeCache(data) {
|
|
6857
|
+
try {
|
|
6858
|
+
const cachePath = getCachePath();
|
|
6859
|
+
const configDir = paths.globalConfig();
|
|
6860
|
+
if (!existsSync5(configDir)) {
|
|
6861
|
+
await mkdir8(configDir, { recursive: true });
|
|
6862
|
+
}
|
|
6863
|
+
await writeFile8(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
6864
|
+
} catch {
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
async function setLastCheckTime(timestamp) {
|
|
6868
|
+
const cache = await readCache();
|
|
6869
|
+
cache.lastCheckTime = timestamp;
|
|
6870
|
+
await writeCache(cache);
|
|
6871
|
+
}
|
|
6872
|
+
async function setLastCheckedVersion(version) {
|
|
6873
|
+
const cache = await readCache();
|
|
6874
|
+
cache.lastCheckedVersion = version;
|
|
6875
|
+
await writeCache(cache);
|
|
6876
|
+
}
|
|
6877
|
+
async function setCompletedUpdate(version) {
|
|
6878
|
+
const cache = await readCache();
|
|
6879
|
+
cache.completedUpdate = version;
|
|
6880
|
+
cache.completedUpdateTime = Date.now();
|
|
6881
|
+
cache.errorCount = 0;
|
|
6882
|
+
cache.lastError = void 0;
|
|
6883
|
+
await writeCache(cache);
|
|
6884
|
+
}
|
|
6885
|
+
async function clearCompletedUpdate() {
|
|
6886
|
+
const cache = await readCache();
|
|
6887
|
+
cache.completedUpdate = void 0;
|
|
6888
|
+
cache.completedUpdateTime = void 0;
|
|
6889
|
+
await writeCache(cache);
|
|
6890
|
+
}
|
|
6891
|
+
async function incrementError(error) {
|
|
6892
|
+
const cache = await readCache();
|
|
6893
|
+
cache.errorCount += 1;
|
|
6894
|
+
cache.lastError = error;
|
|
6895
|
+
await writeCache(cache);
|
|
6896
|
+
}
|
|
6897
|
+
|
|
6898
|
+
// src/core/background-updater.ts
|
|
6899
|
+
init_esm_shims();
|
|
6900
|
+
init_paths();
|
|
6901
|
+
import { spawn } from "child_process";
|
|
6902
|
+
import { writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
|
|
6903
|
+
import { join as join13 } from "path";
|
|
6904
|
+
async function spawnUpdateProcess(targetVersion) {
|
|
6905
|
+
try {
|
|
6906
|
+
const configDir = paths.globalConfig();
|
|
6907
|
+
const logsDir = join13(configDir, "logs");
|
|
6908
|
+
await mkdir9(logsDir, { recursive: true });
|
|
6909
|
+
const scriptContent = generateUpdateScript(targetVersion, logsDir);
|
|
6910
|
+
const scriptPath = join13(configDir, "update-script.js");
|
|
6911
|
+
await writeFile9(scriptPath, scriptContent, "utf-8");
|
|
6912
|
+
const child = spawn(process.execPath, [scriptPath], {
|
|
6913
|
+
detached: true,
|
|
6914
|
+
stdio: "ignore",
|
|
6915
|
+
windowsHide: true
|
|
6916
|
+
});
|
|
6917
|
+
child.unref();
|
|
6918
|
+
return true;
|
|
6919
|
+
} catch {
|
|
6920
|
+
return false;
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
function generateUpdateScript(targetVersion, logsDir) {
|
|
6924
|
+
return `
|
|
6925
|
+
// AIKit Auto-Update Script
|
|
6926
|
+
// Generated automatically - DO NOT EDIT
|
|
6927
|
+
|
|
6928
|
+
const { spawn } = require('child_process');
|
|
6929
|
+
const { writeFile, appendFile } = require('fs').promises;
|
|
6930
|
+
const { join } = require('path');
|
|
6931
|
+
|
|
6932
|
+
const configDir = '${paths.globalConfig().replace(/\\/g, "\\\\")}';
|
|
6933
|
+
const logsDir = '${logsDir.replace(/\\/g, "\\\\")}';
|
|
6934
|
+
const cachePath = join(configDir, '.update-cache.json');
|
|
6935
|
+
const errorLogPath = join(logsDir, 'update-error.log');
|
|
6936
|
+
const targetVersion = '${targetVersion}';
|
|
6937
|
+
|
|
6938
|
+
async function logError(message) {
|
|
6939
|
+
const timestamp = new Date().toISOString();
|
|
6940
|
+
await appendFile(errorLogPath, \`[\${timestamp}] \${message}\\n\`);
|
|
6941
|
+
}
|
|
6942
|
+
|
|
6943
|
+
async function updateCache(version, error) {
|
|
6944
|
+
try {
|
|
6945
|
+
const fs = require('fs');
|
|
6946
|
+
let cache = { lastCheckTime: 0, lastCheckedVersion: '0.0.0', errorCount: 0 };
|
|
6947
|
+
|
|
6948
|
+
try {
|
|
6949
|
+
cache = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
|
|
6950
|
+
} catch {}
|
|
6951
|
+
|
|
6952
|
+
if (error) {
|
|
6953
|
+
cache.errorCount = (cache.errorCount || 0) + 1;
|
|
6954
|
+
cache.lastError = error;
|
|
6955
|
+
} else {
|
|
6956
|
+
cache.completedUpdate = version;
|
|
6957
|
+
cache.completedUpdateTime = Date.now();
|
|
6958
|
+
cache.errorCount = 0;
|
|
6959
|
+
cache.lastError = undefined;
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6962
|
+
await writeFile(cachePath, JSON.stringify(cache, null, 2));
|
|
6963
|
+
} catch {}
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6966
|
+
async function runUpdate() {
|
|
6967
|
+
return new Promise((resolve) => {
|
|
6968
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
6969
|
+
const child = spawn(npmCmd, ['install', '-g', '@tdsoft-tech/aikit@latest'], {
|
|
6970
|
+
stdio: 'pipe',
|
|
6971
|
+
});
|
|
6972
|
+
|
|
6973
|
+
let output = '';
|
|
6974
|
+
let errorOutput = '';
|
|
6975
|
+
|
|
6976
|
+
child.stdout.on('data', (data) => {
|
|
6977
|
+
output += data.toString();
|
|
6978
|
+
});
|
|
6979
|
+
|
|
6980
|
+
child.stderr.on('data', (data) => {
|
|
6981
|
+
errorOutput += data.toString();
|
|
6982
|
+
});
|
|
6983
|
+
|
|
6984
|
+
child.on('close', async (code) => {
|
|
6985
|
+
if (code === 0) {
|
|
6986
|
+
await updateCache(targetVersion, null);
|
|
6987
|
+
resolve(true);
|
|
6988
|
+
} else {
|
|
6989
|
+
const errorMsg = errorOutput || 'npm install failed';
|
|
6990
|
+
await logError(\`Update failed (code \${code}): \${errorMsg}\`);
|
|
6991
|
+
await updateCache(targetVersion, errorMsg);
|
|
6992
|
+
resolve(false);
|
|
6993
|
+
}
|
|
6994
|
+
});
|
|
6995
|
+
|
|
6996
|
+
child.on('error', async (err) => {
|
|
6997
|
+
await logError(\`Update error: \${err.message}\`);
|
|
6998
|
+
await updateCache(targetVersion, err.message);
|
|
6999
|
+
resolve(false);
|
|
7000
|
+
});
|
|
7001
|
+
});
|
|
7002
|
+
}
|
|
7003
|
+
|
|
7004
|
+
// Run update and exit
|
|
7005
|
+
runUpdate().then(() => process.exit(0));
|
|
7006
|
+
`;
|
|
7007
|
+
}
|
|
7008
|
+
|
|
7009
|
+
// src/core/update-manager.ts
|
|
7010
|
+
var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
7011
|
+
var PACKAGE_NAME = "@tdsoft-tech/aikit";
|
|
7012
|
+
async function shouldCheckForUpdates() {
|
|
7013
|
+
const cache = await readCache();
|
|
7014
|
+
const now = Date.now();
|
|
7015
|
+
return now - cache.lastCheckTime > CHECK_INTERVAL;
|
|
7016
|
+
}
|
|
7017
|
+
async function displayNotification() {
|
|
7018
|
+
const cache = await readCache();
|
|
7019
|
+
if (cache.completedUpdate) {
|
|
7020
|
+
const currentVersion = getVersion();
|
|
7021
|
+
if (isGreaterThan(cache.completedUpdate, currentVersion)) {
|
|
7022
|
+
console.log(chalk2.cyan.bold("\n\u2728 AIKit has been updated!\n"));
|
|
7023
|
+
console.log(chalk2.gray(` Version: ${currentVersion} \u2192 ${cache.completedUpdate}`));
|
|
7024
|
+
console.log(chalk2.gray(` Updated: Just now
|
|
7025
|
+
`));
|
|
7026
|
+
console.log(chalk2.gray("Run 'aikit --version' to verify.\n"));
|
|
7027
|
+
await clearCompletedUpdate();
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
if (cache.errorCount >= 3 && cache.lastError) {
|
|
7031
|
+
console.log(chalk2.yellow.bold("\n\u26A0\uFE0F AIKit update failed\n"));
|
|
7032
|
+
console.log(chalk2.gray(` Last error: ${cache.lastError}`));
|
|
7033
|
+
console.log(chalk2.gray(" Check logs: ~/.config/aikit/logs/update-error.log\n"));
|
|
7034
|
+
}
|
|
7035
|
+
}
|
|
7036
|
+
async function performBackgroundUpdate(latestVersion) {
|
|
7037
|
+
const success = await spawnUpdateProcess(latestVersion);
|
|
7038
|
+
if (!success) {
|
|
7039
|
+
await incrementError("Failed to spawn update process");
|
|
7040
|
+
} else {
|
|
7041
|
+
await setCompletedUpdate(latestVersion);
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
async function checkForUpdates() {
|
|
7045
|
+
try {
|
|
7046
|
+
await displayNotification();
|
|
7047
|
+
if (!await shouldCheckForUpdates()) {
|
|
7048
|
+
return;
|
|
7049
|
+
}
|
|
7050
|
+
const currentVersion = getVersion();
|
|
7051
|
+
const latestVersion = await getLatestVersion(PACKAGE_NAME);
|
|
7052
|
+
await setLastCheckTime(Date.now());
|
|
7053
|
+
await setLastCheckedVersion(currentVersion);
|
|
7054
|
+
if (!latestVersion || !isGreaterThan(latestVersion, currentVersion)) {
|
|
7055
|
+
return;
|
|
7056
|
+
}
|
|
7057
|
+
await performBackgroundUpdate(latestVersion);
|
|
7058
|
+
} catch {
|
|
7059
|
+
}
|
|
7060
|
+
}
|
|
7061
|
+
async function checkForUpdatesAsync() {
|
|
7062
|
+
checkForUpdates().catch(() => {
|
|
7063
|
+
});
|
|
7064
|
+
}
|
|
7065
|
+
|
|
6600
7066
|
// src/index.ts
|
|
6601
7067
|
init_logger();
|
|
6602
7068
|
init_paths();
|
|
@@ -6608,15 +7074,15 @@ init_esm_shims();
|
|
|
6608
7074
|
// src/cli/commands/init.ts
|
|
6609
7075
|
init_esm_shims();
|
|
6610
7076
|
init_config();
|
|
6611
|
-
import
|
|
7077
|
+
import chalk3 from "chalk";
|
|
6612
7078
|
import inquirer from "inquirer";
|
|
6613
7079
|
init_beads();
|
|
6614
7080
|
|
|
6615
7081
|
// src/utils/cli-detector.ts
|
|
6616
7082
|
init_esm_shims();
|
|
6617
7083
|
import { execSync } from "child_process";
|
|
6618
|
-
import { existsSync as
|
|
6619
|
-
import { join as
|
|
7084
|
+
import { existsSync as existsSync6 } from "fs";
|
|
7085
|
+
import { join as join14 } from "path";
|
|
6620
7086
|
import { homedir as homedir2 } from "os";
|
|
6621
7087
|
var CliPlatform = /* @__PURE__ */ ((CliPlatform2) => {
|
|
6622
7088
|
CliPlatform2["OPENCODE"] = "opencode";
|
|
@@ -6630,16 +7096,16 @@ var CliDetector = class {
|
|
|
6630
7096
|
*/
|
|
6631
7097
|
static async checkOpenCode() {
|
|
6632
7098
|
try {
|
|
6633
|
-
const opencodePath = process.platform === "win32" ? process.env.APPDATA ||
|
|
6634
|
-
const opencodeConfig =
|
|
6635
|
-
let installed =
|
|
7099
|
+
const opencodePath = process.platform === "win32" ? process.env.APPDATA || join14(homedir2(), "AppData", "Roaming") : join14(homedir2(), ".config");
|
|
7100
|
+
const opencodeConfig = join14(opencodePath, "opencode", "opencode.json");
|
|
7101
|
+
let installed = existsSync6(opencodeConfig);
|
|
6636
7102
|
let version;
|
|
6637
7103
|
if (installed) {
|
|
6638
7104
|
try {
|
|
6639
7105
|
execSync("opencode --version", { stdio: "ignore" });
|
|
6640
7106
|
version = "installed";
|
|
6641
7107
|
} catch (error) {
|
|
6642
|
-
if (
|
|
7108
|
+
if (existsSync6(opencodeConfig)) {
|
|
6643
7109
|
version = "installed (config exists)";
|
|
6644
7110
|
} else {
|
|
6645
7111
|
installed = false;
|
|
@@ -6736,18 +7202,18 @@ var CliDetector = class {
|
|
|
6736
7202
|
*/
|
|
6737
7203
|
static async detectPlatforms() {
|
|
6738
7204
|
const platforms = [];
|
|
6739
|
-
const opencodePath = process.platform === "win32" ? process.env.APPDATA ||
|
|
7205
|
+
const opencodePath = process.platform === "win32" ? process.env.APPDATA || join14(homedir2(), "AppData", "Roaming") : join14(homedir2(), ".config");
|
|
6740
7206
|
platforms.push({
|
|
6741
7207
|
platform: "opencode" /* OPENCODE */,
|
|
6742
7208
|
displayName: "OpenCode",
|
|
6743
|
-
installed:
|
|
7209
|
+
installed: existsSync6(join14(opencodePath, "opencode", "opencode.json")),
|
|
6744
7210
|
configPath: opencodePath
|
|
6745
7211
|
});
|
|
6746
|
-
const claudePath = process.platform === "win32" ? process.env.APPDATA ||
|
|
7212
|
+
const claudePath = process.platform === "win32" ? process.env.APPDATA || join14(homedir2(), "AppData", "Roaming") : join14(homedir2(), ".claude");
|
|
6747
7213
|
platforms.push({
|
|
6748
7214
|
platform: "claude" /* CLAUDE */,
|
|
6749
7215
|
displayName: "Claude Code CLI",
|
|
6750
|
-
installed:
|
|
7216
|
+
installed: existsSync6(claudePath),
|
|
6751
7217
|
configPath: claudePath
|
|
6752
7218
|
});
|
|
6753
7219
|
return platforms;
|
|
@@ -6780,9 +7246,9 @@ init_paths();
|
|
|
6780
7246
|
|
|
6781
7247
|
// src/cli/helpers.ts
|
|
6782
7248
|
init_esm_shims();
|
|
6783
|
-
import { existsSync as
|
|
6784
|
-
import { mkdir as
|
|
6785
|
-
import { join as
|
|
7249
|
+
import { existsSync as existsSync7 } from "fs";
|
|
7250
|
+
import { mkdir as mkdir11, writeFile as writeFile11, readFile as readFile9, access as access5 } from "fs/promises";
|
|
7251
|
+
import { join as join16, dirname as dirname2 } from "path";
|
|
6786
7252
|
import { homedir as homedir3 } from "os";
|
|
6787
7253
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6788
7254
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -6808,7 +7274,7 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
6808
7274
|
"memory/research"
|
|
6809
7275
|
];
|
|
6810
7276
|
for (const dir of dirs) {
|
|
6811
|
-
await
|
|
7277
|
+
await mkdir11(join16(configDir, dir), { recursive: true });
|
|
6812
7278
|
}
|
|
6813
7279
|
const defaultConfig = {
|
|
6814
7280
|
version: getVersion(),
|
|
@@ -6821,8 +7287,8 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
6821
7287
|
beads: { enabled: true },
|
|
6822
7288
|
antiHallucination: { enabled: true }
|
|
6823
7289
|
};
|
|
6824
|
-
await
|
|
6825
|
-
|
|
7290
|
+
await writeFile11(
|
|
7291
|
+
join16(configDir, "aikit.json"),
|
|
6826
7292
|
JSON.stringify(defaultConfig, null, 2)
|
|
6827
7293
|
);
|
|
6828
7294
|
const agentsMd = `# AIKit Agent Rules
|
|
@@ -6845,20 +7311,20 @@ async function initializeConfig(configDir, _isGlobal) {
|
|
|
6845
7311
|
## Project-Specific Rules
|
|
6846
7312
|
Add your project-specific rules here.
|
|
6847
7313
|
`;
|
|
6848
|
-
await
|
|
7314
|
+
await writeFile11(join16(configDir, "AGENTS.md"), agentsMd);
|
|
6849
7315
|
}
|
|
6850
7316
|
async function configureMcpServer(projectPath) {
|
|
6851
7317
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
6852
7318
|
const currentDir = dirname2(currentFile);
|
|
6853
|
-
const aikitPath =
|
|
6854
|
-
const mcpServerPath =
|
|
7319
|
+
const aikitPath = join16(currentDir, "..", "..");
|
|
7320
|
+
const mcpServerPath = join16(aikitPath, "dist", "mcp-server.js");
|
|
6855
7321
|
const configLocations = [
|
|
6856
7322
|
// Global config (most common)
|
|
6857
|
-
|
|
7323
|
+
join16(homedir3(), ".config", "opencode", "opencode.json"),
|
|
6858
7324
|
// Project-level config
|
|
6859
|
-
|
|
7325
|
+
join16(projectPath, ".opencode", "opencode.json"),
|
|
6860
7326
|
// Alternative global location
|
|
6861
|
-
|
|
7327
|
+
join16(homedir3(), ".opencode", "opencode.json")
|
|
6862
7328
|
];
|
|
6863
7329
|
const mcpServerConfig = {
|
|
6864
7330
|
type: "local",
|
|
@@ -6867,12 +7333,12 @@ async function configureMcpServer(projectPath) {
|
|
|
6867
7333
|
};
|
|
6868
7334
|
for (const configPath of configLocations) {
|
|
6869
7335
|
try {
|
|
6870
|
-
const configDir =
|
|
6871
|
-
await
|
|
7336
|
+
const configDir = join16(configPath, "..");
|
|
7337
|
+
await mkdir11(configDir, { recursive: true });
|
|
6872
7338
|
let config = {};
|
|
6873
|
-
if (
|
|
7339
|
+
if (existsSync7(configPath)) {
|
|
6874
7340
|
try {
|
|
6875
|
-
const existing = await
|
|
7341
|
+
const existing = await readFile9(configPath, "utf-8");
|
|
6876
7342
|
config = JSON.parse(existing);
|
|
6877
7343
|
} catch {
|
|
6878
7344
|
config = {};
|
|
@@ -6882,7 +7348,7 @@ async function configureMcpServer(projectPath) {
|
|
|
6882
7348
|
config.mcp = {};
|
|
6883
7349
|
}
|
|
6884
7350
|
config.mcp.aikit = mcpServerConfig;
|
|
6885
|
-
await
|
|
7351
|
+
await writeFile11(configPath, JSON.stringify(config, null, 2));
|
|
6886
7352
|
logger.success(`
|
|
6887
7353
|
\u2705 MCP server configured: ${configPath}`);
|
|
6888
7354
|
logger.info(` Server: node ${mcpServerPath}`);
|
|
@@ -6891,9 +7357,9 @@ async function configureMcpServer(projectPath) {
|
|
|
6891
7357
|
continue;
|
|
6892
7358
|
}
|
|
6893
7359
|
}
|
|
6894
|
-
const instructionsPath =
|
|
6895
|
-
await
|
|
6896
|
-
await
|
|
7360
|
+
const instructionsPath = join16(projectPath, ".opencode", "MCP_SETUP.md");
|
|
7361
|
+
await mkdir11(join16(projectPath, ".opencode"), { recursive: true });
|
|
7362
|
+
await writeFile11(instructionsPath, `# AIKit MCP Server Configuration
|
|
6897
7363
|
|
|
6898
7364
|
## Automatic Setup Failed
|
|
6899
7365
|
|
|
@@ -7146,26 +7612,26 @@ Report what was extracted:
|
|
|
7146
7612
|
}
|
|
7147
7613
|
async function installToOpenCode(_opencodePath) {
|
|
7148
7614
|
const projectPath = process.cwd();
|
|
7149
|
-
const opencodeCommandDir =
|
|
7150
|
-
const aikitDir =
|
|
7151
|
-
const opencodeAgentDir =
|
|
7152
|
-
await
|
|
7153
|
-
await
|
|
7154
|
-
await
|
|
7615
|
+
const opencodeCommandDir = join16(projectPath, ".opencode", "command");
|
|
7616
|
+
const aikitDir = join16(projectPath, ".aikit");
|
|
7617
|
+
const opencodeAgentDir = join16(paths.opencodeConfig(), "agent");
|
|
7618
|
+
await mkdir11(opencodeCommandDir, { recursive: true });
|
|
7619
|
+
await mkdir11(join16(aikitDir, "skills"), { recursive: true });
|
|
7620
|
+
await mkdir11(opencodeAgentDir, { recursive: true });
|
|
7155
7621
|
for (const [name, content] of Object.entries(AGENT_FILES)) {
|
|
7156
|
-
const filePath =
|
|
7622
|
+
const filePath = join16(opencodeAgentDir, `${name}.md`);
|
|
7157
7623
|
try {
|
|
7158
7624
|
await access5(filePath);
|
|
7159
|
-
const existingContent = await
|
|
7625
|
+
const existingContent = await readFile9(filePath, "utf8");
|
|
7160
7626
|
if (!existingContent.includes("mode: subagent")) {
|
|
7161
7627
|
const matter5 = await import("gray-matter");
|
|
7162
7628
|
const { data: frontmatter, content: body } = matter5.default(existingContent);
|
|
7163
7629
|
frontmatter.mode = "subagent";
|
|
7164
7630
|
const updatedContent = matter5.default.stringify(body, frontmatter);
|
|
7165
|
-
await
|
|
7631
|
+
await writeFile11(filePath, updatedContent, "utf8");
|
|
7166
7632
|
}
|
|
7167
7633
|
} catch {
|
|
7168
|
-
await
|
|
7634
|
+
await writeFile11(filePath, content, "utf8");
|
|
7169
7635
|
}
|
|
7170
7636
|
}
|
|
7171
7637
|
const config = await loadConfig();
|
|
@@ -7174,8 +7640,8 @@ async function installToOpenCode(_opencodePath) {
|
|
|
7174
7640
|
const skills = await skillEngine.listSkills();
|
|
7175
7641
|
const commands = await commandRunner.listCommands();
|
|
7176
7642
|
const opencodeCommands = {};
|
|
7177
|
-
const skillsList = skills.map((s) => `|
|
|
7178
|
-
opencodeCommands["
|
|
7643
|
+
const skillsList = skills.map((s) => `| \`/${s.name.replace(/\s+/g, "-")}\` | ${s.description} |`).join("\n");
|
|
7644
|
+
opencodeCommands["skills"] = `List all available AIKit skills and how to use them.
|
|
7179
7645
|
|
|
7180
7646
|
READ .aikit/AGENTS.md
|
|
7181
7647
|
|
|
@@ -7185,9 +7651,9 @@ READ .aikit/AGENTS.md
|
|
|
7185
7651
|
|---------|-------------|
|
|
7186
7652
|
${skillsList}
|
|
7187
7653
|
|
|
7188
|
-
Type any command to use that skill. For example: \`/
|
|
7654
|
+
Type any command to use that skill. For example: \`/test-driven-development\``;
|
|
7189
7655
|
for (const skill of skills) {
|
|
7190
|
-
const commandName =
|
|
7656
|
+
const commandName = skill.name.replace(/\s+/g, "-").toLowerCase();
|
|
7191
7657
|
const skillPath = skill.filePath;
|
|
7192
7658
|
const relativePath = skillPath.startsWith(projectPath) ? skillPath.replace(projectPath, "").replace(/\\/g, "/").replace(/^\//, "") : `.aikit/skills/${skill.name.replace(/\s+/g, "-").toLowerCase()}.md`;
|
|
7193
7659
|
const useWhen = skill.useWhen || `The user asks you to ${skill.name}`;
|
|
@@ -7209,21 +7675,20 @@ Complete the checklist at the end of the skill.`;
|
|
|
7209
7675
|
}
|
|
7210
7676
|
for (const cmd of commands) {
|
|
7211
7677
|
if (opencodeCommands[cmd.name]) continue;
|
|
7212
|
-
const commandName =
|
|
7678
|
+
const commandName = cmd.name.replace(/\//g, "").replace(/\s+/g, "-");
|
|
7213
7679
|
const examples = cmd.examples.map((e) => {
|
|
7214
|
-
|
|
7215
|
-
return `- \`${prefixed}\``;
|
|
7680
|
+
return `- \`${e}\``;
|
|
7216
7681
|
}).join("\n");
|
|
7217
7682
|
if (cmd.name === "analyze-figma") {
|
|
7218
7683
|
opencodeCommands[commandName] = generateAnalyzeFigmaCommand();
|
|
7219
7684
|
} else {
|
|
7220
|
-
opencodeCommands[commandName] = `# Command:
|
|
7685
|
+
opencodeCommands[commandName] = `# Command: /${cmd.name}
|
|
7221
7686
|
|
|
7222
7687
|
## Description
|
|
7223
7688
|
${cmd.description}
|
|
7224
7689
|
|
|
7225
7690
|
## Usage
|
|
7226
|
-
\`${cmd.usage
|
|
7691
|
+
\`${cmd.usage}\`
|
|
7227
7692
|
|
|
7228
7693
|
## Examples
|
|
7229
7694
|
${examples}
|
|
@@ -7241,8 +7706,8 @@ The arguments are available in this command response - look at the command workf
|
|
|
7241
7706
|
4. They have already provided it - extract and use it!
|
|
7242
7707
|
|
|
7243
7708
|
**Example Scenario**:
|
|
7244
|
-
- User runs:
|
|
7245
|
-
- Command:
|
|
7709
|
+
- User runs: \`/${cmd.name} snake game with html & css\`
|
|
7710
|
+
- Command: \`/${cmd.name}\`
|
|
7246
7711
|
- Arguments to use: \`snake game with html & css\`
|
|
7247
7712
|
- You must use "snake game with html & css" as provided in the workflow!
|
|
7248
7713
|
|
|
@@ -7257,8 +7722,8 @@ ${cmd.content}
|
|
|
7257
7722
|
}
|
|
7258
7723
|
let count = 0;
|
|
7259
7724
|
for (const [name, content] of Object.entries(opencodeCommands)) {
|
|
7260
|
-
const filePath =
|
|
7261
|
-
await
|
|
7725
|
+
const filePath = join16(opencodeCommandDir, `${name}.md`);
|
|
7726
|
+
await writeFile11(filePath, content.trim());
|
|
7262
7727
|
logger.info(` \u2713 Created /${name} command`);
|
|
7263
7728
|
count++;
|
|
7264
7729
|
}
|
|
@@ -7267,8 +7732,8 @@ Created ${count} OpenCode commands in .opencode/command/`);
|
|
|
7267
7732
|
await configureMcpServer(projectPath);
|
|
7268
7733
|
logger.info("\nUsage in OpenCode:");
|
|
7269
7734
|
logger.info(" Press Ctrl+K to open command picker");
|
|
7270
|
-
logger.info(" Or type /
|
|
7271
|
-
logger.info(` Available: ${skills.length} skills
|
|
7735
|
+
logger.info(" Or type /skills to see all available skills");
|
|
7736
|
+
logger.info(` Available: ${skills.length} skills, ${commands.length} commands`);
|
|
7272
7737
|
logger.info(" MCP server configured - tools available via MCP protocol");
|
|
7273
7738
|
}
|
|
7274
7739
|
function groupBy(array, keyFn) {
|
|
@@ -7295,9 +7760,15 @@ async function startSession(name, goals) {
|
|
|
7295
7760
|
console.log("\nCommands:");
|
|
7296
7761
|
console.log(" /session:update [notes] - Add progress notes");
|
|
7297
7762
|
console.log(" /session:end - End session with summary");
|
|
7298
|
-
console.log(" /session:current - Show session status
|
|
7763
|
+
console.log(" /session:current - Show session status");
|
|
7764
|
+
console.log(" /session:use <id> - Switch to a different session\n");
|
|
7299
7765
|
} catch (error) {
|
|
7300
|
-
|
|
7766
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
7767
|
+
logger.error(error.message);
|
|
7768
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
7769
|
+
} else {
|
|
7770
|
+
logger.error("Failed to start session:", error);
|
|
7771
|
+
}
|
|
7301
7772
|
}
|
|
7302
7773
|
}
|
|
7303
7774
|
async function updateSession(notes) {
|
|
@@ -7317,7 +7788,10 @@ async function updateSession(notes) {
|
|
|
7317
7788
|
console.log();
|
|
7318
7789
|
}
|
|
7319
7790
|
} catch (error) {
|
|
7320
|
-
if (error instanceof Error && error.message.includes("
|
|
7791
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
7792
|
+
logger.error(error.message);
|
|
7793
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
7794
|
+
} else if (error instanceof Error && error.message.includes("No active session")) {
|
|
7321
7795
|
logger.error("No active session. Use /session:start first");
|
|
7322
7796
|
} else {
|
|
7323
7797
|
logger.error("Failed to update session:", error);
|
|
@@ -7356,7 +7830,10 @@ Use /session:show ${session.id} for details
|
|
|
7356
7830
|
`);
|
|
7357
7831
|
}
|
|
7358
7832
|
} catch (error) {
|
|
7359
|
-
if (error instanceof Error && error.message.includes("
|
|
7833
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
7834
|
+
logger.error(error.message);
|
|
7835
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
7836
|
+
} else if (error instanceof Error && error.message.includes("No active session")) {
|
|
7360
7837
|
logger.error("No active session. Use /session:start first");
|
|
7361
7838
|
} else {
|
|
7362
7839
|
logger.error("Failed to end session:", error);
|
|
@@ -7374,12 +7851,16 @@ async function showCurrentSession() {
|
|
|
7374
7851
|
return;
|
|
7375
7852
|
}
|
|
7376
7853
|
const duration = Math.floor((Date.now() - new Date(session.startTime).getTime()) / 6e4);
|
|
7854
|
+
const terminalInfo = await manager.getTerminalInfo();
|
|
7377
7855
|
console.log("\n\u{1F4CD} Current Session");
|
|
7378
7856
|
console.log("\u2501".repeat(60));
|
|
7379
7857
|
console.log(`
|
|
7380
7858
|
Session: ${session.name}`);
|
|
7381
7859
|
console.log(`ID: ${session.id}`);
|
|
7382
7860
|
console.log(`Started: ${Math.floor(duration / 60)}h ${duration % 60}m ago`);
|
|
7861
|
+
if (terminalInfo.tty) {
|
|
7862
|
+
console.log(`Terminal: ${terminalInfo.tty}`);
|
|
7863
|
+
}
|
|
7383
7864
|
if (session.goals.length > 0) {
|
|
7384
7865
|
console.log(`
|
|
7385
7866
|
Goals:`);
|
|
@@ -7411,10 +7892,16 @@ Beads Task:`);
|
|
|
7411
7892
|
}
|
|
7412
7893
|
console.log("\nCommands:");
|
|
7413
7894
|
console.log(" /session:update [notes] - Add progress");
|
|
7895
|
+
console.log(" /session:use <id> - Switch to another session");
|
|
7414
7896
|
console.log(" /session:end - Close session");
|
|
7415
7897
|
console.log("\u2501".repeat(60) + "\n");
|
|
7416
7898
|
} catch (error) {
|
|
7417
|
-
|
|
7899
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
7900
|
+
logger.error(error.message);
|
|
7901
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
7902
|
+
} else {
|
|
7903
|
+
logger.error("Failed to show current session:", error);
|
|
7904
|
+
}
|
|
7418
7905
|
}
|
|
7419
7906
|
}
|
|
7420
7907
|
async function listSessions() {
|
|
@@ -7455,7 +7942,12 @@ Total: ${sessions.length} session${sessions.length > 1 ? "s" : ""}
|
|
|
7455
7942
|
console.log(" /session:resume <id> - Resume session");
|
|
7456
7943
|
console.log(" /session:search <query> - Search sessions\n");
|
|
7457
7944
|
} catch (error) {
|
|
7458
|
-
|
|
7945
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
7946
|
+
logger.error(error.message);
|
|
7947
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
7948
|
+
} else {
|
|
7949
|
+
logger.error("Failed to list sessions:", error);
|
|
7950
|
+
}
|
|
7459
7951
|
}
|
|
7460
7952
|
}
|
|
7461
7953
|
async function showSession(sessionId) {
|
|
@@ -7513,7 +8005,12 @@ Goals:`);
|
|
|
7513
8005
|
}
|
|
7514
8006
|
console.log("\n" + "\u2501".repeat(60) + "\n");
|
|
7515
8007
|
} catch (error) {
|
|
7516
|
-
|
|
8008
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
8009
|
+
logger.error(error.message);
|
|
8010
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
8011
|
+
} else {
|
|
8012
|
+
logger.error("Failed to show session:", error);
|
|
8013
|
+
}
|
|
7517
8014
|
}
|
|
7518
8015
|
}
|
|
7519
8016
|
async function searchSessions(query) {
|
|
@@ -7551,9 +8048,84 @@ Total: ${sessions.length} matching session${sessions.length > 1 ? "s" : ""}
|
|
|
7551
8048
|
console.log(" /session:show <id> - View session details");
|
|
7552
8049
|
console.log(" /session:resume <id> - Resume session\n");
|
|
7553
8050
|
} catch (error) {
|
|
7554
|
-
|
|
8051
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
8052
|
+
logger.error(error.message);
|
|
8053
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
8054
|
+
} else {
|
|
8055
|
+
logger.error("Failed to search sessions:", error);
|
|
8056
|
+
}
|
|
7555
8057
|
}
|
|
7556
8058
|
}
|
|
8059
|
+
async function resumeSession(sessionId) {
|
|
8060
|
+
try {
|
|
8061
|
+
const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
8062
|
+
const manager = new SessionManager2();
|
|
8063
|
+
const session = await manager.resumeSession(sessionId);
|
|
8064
|
+
logger.success("\u2713 Session resumed");
|
|
8065
|
+
console.log(` ID: ${session.id}`);
|
|
8066
|
+
console.log(` Name: ${session.name}`);
|
|
8067
|
+
console.log(` Status: ${session.status}`);
|
|
8068
|
+
console.log(` Started: ${new Date(session.startTime).toLocaleString()}`);
|
|
8069
|
+
if (session.goals.length > 0) {
|
|
8070
|
+
console.log(` Goals:`);
|
|
8071
|
+
session.goals.forEach((goal) => console.log(` - ${goal}`));
|
|
8072
|
+
}
|
|
8073
|
+
console.log("\nCommands:");
|
|
8074
|
+
console.log(" /session:update [notes] - Add progress notes");
|
|
8075
|
+
console.log(" /session:end - End session with summary");
|
|
8076
|
+
console.log(" /session:current - Show session status");
|
|
8077
|
+
console.log(" /session:use <id> - Switch to a different session\n");
|
|
8078
|
+
} catch (error) {
|
|
8079
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
8080
|
+
logger.error(error.message);
|
|
8081
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
8082
|
+
} else if (error instanceof Error && error.message.includes("not found")) {
|
|
8083
|
+
logger.error(error.message);
|
|
8084
|
+
console.log("Use /session:list to see all sessions\n");
|
|
8085
|
+
} else {
|
|
8086
|
+
logger.error("Failed to resume session:", error);
|
|
8087
|
+
}
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8090
|
+
async function switchSession(sessionId) {
|
|
8091
|
+
try {
|
|
8092
|
+
const { SessionManager: SessionManager2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
8093
|
+
const manager = new SessionManager2();
|
|
8094
|
+
const session = await manager.getSession(sessionId);
|
|
8095
|
+
if (!session) {
|
|
8096
|
+
logger.error(`Session not found: ${sessionId}`);
|
|
8097
|
+
console.log("Use /session:list to see all sessions\n");
|
|
8098
|
+
return;
|
|
8099
|
+
}
|
|
8100
|
+
await manager.switchSession(sessionId);
|
|
8101
|
+
logger.success("\u2713 Switched to session");
|
|
8102
|
+
console.log(` ID: ${session.id}`);
|
|
8103
|
+
console.log(` Name: ${session.name}`);
|
|
8104
|
+
console.log(` Status: ${session.status}`);
|
|
8105
|
+
console.log(` Started: ${new Date(session.startTime).toLocaleString()}`);
|
|
8106
|
+
if (session.goals.length > 0) {
|
|
8107
|
+
console.log(` Goals:`);
|
|
8108
|
+
session.goals.forEach((goal) => console.log(` - ${goal}`));
|
|
8109
|
+
}
|
|
8110
|
+
console.log("\nCommands:");
|
|
8111
|
+
console.log(" /session:update [notes] - Add progress notes");
|
|
8112
|
+
console.log(" /session:end - End session with summary");
|
|
8113
|
+
console.log(" /session:current - Show session status\n");
|
|
8114
|
+
} catch (error) {
|
|
8115
|
+
if (error instanceof Error && error.message.includes("not initialized")) {
|
|
8116
|
+
logger.error(error.message);
|
|
8117
|
+
console.log('Run "aikit init" first to initialize AIKit in this directory.\n');
|
|
8118
|
+
} else if (error instanceof Error && error.message.includes("not found")) {
|
|
8119
|
+
logger.error(error.message);
|
|
8120
|
+
console.log("Use /session:list to see all sessions\n");
|
|
8121
|
+
} else {
|
|
8122
|
+
logger.error("Failed to switch session:", error);
|
|
8123
|
+
}
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
|
|
8127
|
+
// src/cli/commands/init.ts
|
|
8128
|
+
init_sessions();
|
|
7557
8129
|
|
|
7558
8130
|
// src/platform/adapters.ts
|
|
7559
8131
|
init_esm_shims();
|
|
@@ -7561,33 +8133,31 @@ init_esm_shims();
|
|
|
7561
8133
|
// src/platform/opencode-adapter.ts
|
|
7562
8134
|
init_esm_shims();
|
|
7563
8135
|
init_paths();
|
|
7564
|
-
import { readFile as
|
|
7565
|
-
import { join as
|
|
8136
|
+
import { readFile as readFile10, writeFile as writeFile12, mkdir as mkdir12, access as access6 } from "fs/promises";
|
|
8137
|
+
import { join as join17 } from "path";
|
|
7566
8138
|
var OpenCodeAdapter = class {
|
|
7567
8139
|
platform = "opencode" /* OPENCODE */;
|
|
7568
8140
|
displayName = "OpenCode";
|
|
7569
8141
|
getCommandsDir() {
|
|
7570
|
-
return
|
|
8142
|
+
return join17(process.cwd(), ".opencode", "command");
|
|
7571
8143
|
}
|
|
7572
8144
|
getSkillsDir() {
|
|
7573
|
-
return
|
|
8145
|
+
return join17(process.cwd(), ".opencode", "skill");
|
|
7574
8146
|
}
|
|
7575
8147
|
getAgentsDir() {
|
|
7576
|
-
return
|
|
8148
|
+
return join17(paths.opencodeConfig(), "agent");
|
|
7577
8149
|
}
|
|
7578
8150
|
async transformCommand(command) {
|
|
7579
|
-
const
|
|
7580
|
-
const name = `ak_cm_${sanitizedName}`;
|
|
8151
|
+
const name = command.name.replace(/:/g, "-");
|
|
7581
8152
|
const content = this.generateCommandContent(command);
|
|
7582
8153
|
return { name, content };
|
|
7583
8154
|
}
|
|
7584
8155
|
async transformSkill(skill) {
|
|
7585
|
-
const skillName = `ak_sk_${skill.name}`;
|
|
7586
8156
|
const skillContent = this.generateSkillContent(skill);
|
|
7587
8157
|
const result = {
|
|
7588
|
-
name:
|
|
8158
|
+
name: skill.name,
|
|
7589
8159
|
directory: "",
|
|
7590
|
-
files: { [`${
|
|
8160
|
+
files: { [`${skill.name}.md`]: skillContent }
|
|
7591
8161
|
};
|
|
7592
8162
|
return result;
|
|
7593
8163
|
}
|
|
@@ -7598,47 +8168,46 @@ var OpenCodeAdapter = class {
|
|
|
7598
8168
|
}
|
|
7599
8169
|
async installCommand(name, content) {
|
|
7600
8170
|
const dir = this.getCommandsDir();
|
|
7601
|
-
await
|
|
7602
|
-
await
|
|
8171
|
+
await mkdir12(dir, { recursive: true });
|
|
8172
|
+
await writeFile12(join17(dir, `${name}.md`), content);
|
|
7603
8173
|
}
|
|
7604
8174
|
async installSkill(_name, directory, files) {
|
|
7605
8175
|
const baseDir = this.getSkillsDir();
|
|
7606
|
-
const targetDir = directory ?
|
|
7607
|
-
await
|
|
8176
|
+
const targetDir = directory ? join17(baseDir, directory) : baseDir;
|
|
8177
|
+
await mkdir12(targetDir, { recursive: true });
|
|
7608
8178
|
for (const [filename, content] of Object.entries(files)) {
|
|
7609
|
-
await
|
|
8179
|
+
await writeFile12(join17(targetDir, filename), content);
|
|
7610
8180
|
}
|
|
7611
8181
|
}
|
|
7612
8182
|
async installAgent(name, content) {
|
|
7613
8183
|
const dir = this.getAgentsDir();
|
|
7614
|
-
await
|
|
7615
|
-
const filePath =
|
|
8184
|
+
await mkdir12(dir, { recursive: true });
|
|
8185
|
+
const filePath = join17(dir, `${name}.md`);
|
|
7616
8186
|
try {
|
|
7617
8187
|
await access6(filePath);
|
|
7618
|
-
const existingContent = await
|
|
8188
|
+
const existingContent = await readFile10(filePath, "utf-8");
|
|
7619
8189
|
if (!existingContent.includes("mode: subagent")) {
|
|
7620
8190
|
const matter5 = await import("gray-matter");
|
|
7621
8191
|
const { data: frontmatter, content: body } = matter5.default(existingContent);
|
|
7622
8192
|
frontmatter.mode = "subagent";
|
|
7623
8193
|
const updatedContent = matter5.default.stringify(body, frontmatter);
|
|
7624
|
-
await
|
|
8194
|
+
await writeFile12(filePath, updatedContent, "utf-8");
|
|
7625
8195
|
}
|
|
7626
8196
|
} catch {
|
|
7627
|
-
await
|
|
8197
|
+
await writeFile12(filePath, content, "utf-8");
|
|
7628
8198
|
}
|
|
7629
8199
|
}
|
|
7630
8200
|
generateCommandContent(command) {
|
|
7631
8201
|
const examples = command.examples.map((e) => {
|
|
7632
|
-
|
|
7633
|
-
return `- \`${prefixed}\``;
|
|
8202
|
+
return `- \`${e}\``;
|
|
7634
8203
|
}).join("\n");
|
|
7635
|
-
return `# Command:
|
|
8204
|
+
return `# Command: /${command.name}
|
|
7636
8205
|
|
|
7637
8206
|
## Description
|
|
7638
8207
|
${command.description}
|
|
7639
8208
|
|
|
7640
8209
|
## Usage
|
|
7641
|
-
\`${command.usage
|
|
8210
|
+
\`${command.usage}\`
|
|
7642
8211
|
|
|
7643
8212
|
## Examples
|
|
7644
8213
|
${examples}
|
|
@@ -7656,8 +8225,8 @@ The arguments are available in this command response - look at the command workf
|
|
|
7656
8225
|
4. They have already provided it - extract and use it!
|
|
7657
8226
|
|
|
7658
8227
|
**Example Scenario**:
|
|
7659
|
-
- User runs:
|
|
7660
|
-
- Command:
|
|
8228
|
+
- User runs: \`/${command.name} snake game with html & css\`
|
|
8229
|
+
- Command: \`/${command.name}\`
|
|
7661
8230
|
- Arguments to use: \`snake game with html & css\`
|
|
7662
8231
|
- You must use "snake game with html & css" as provided in the workflow!
|
|
7663
8232
|
|
|
@@ -7700,12 +8269,14 @@ ${agent.systemPrompt}`;
|
|
|
7700
8269
|
// src/platform/claude-adapter.ts
|
|
7701
8270
|
init_esm_shims();
|
|
7702
8271
|
init_paths();
|
|
7703
|
-
import { writeFile as
|
|
7704
|
-
import { join as
|
|
8272
|
+
import { writeFile as writeFile13, mkdir as mkdir13 } from "fs/promises";
|
|
8273
|
+
import { join as join18 } from "path";
|
|
7705
8274
|
import matter4 from "gray-matter";
|
|
7706
8275
|
var ClaudeAdapter = class {
|
|
7707
8276
|
platform = "claude" /* CLAUDE */;
|
|
7708
8277
|
displayName = "Claude Code CLI";
|
|
8278
|
+
// Track installed commands for manifest generation
|
|
8279
|
+
installedCommands = [];
|
|
7709
8280
|
getCommandsDir() {
|
|
7710
8281
|
return paths.claudeCommands(true);
|
|
7711
8282
|
}
|
|
@@ -7736,26 +8307,27 @@ var ClaudeAdapter = class {
|
|
|
7736
8307
|
}
|
|
7737
8308
|
async installCommand(name, content) {
|
|
7738
8309
|
const dir = this.getCommandsDir();
|
|
7739
|
-
await
|
|
7740
|
-
await
|
|
8310
|
+
await mkdir13(dir, { recursive: true });
|
|
8311
|
+
await writeFile13(join18(dir, `${name}.md`), content);
|
|
8312
|
+
this.installedCommands.push(name);
|
|
7741
8313
|
}
|
|
7742
8314
|
async installSkill(_name, directory, files) {
|
|
7743
8315
|
const baseDir = this.getSkillsDir();
|
|
7744
|
-
const targetDir =
|
|
7745
|
-
await
|
|
8316
|
+
const targetDir = join18(baseDir, directory);
|
|
8317
|
+
await mkdir13(targetDir, { recursive: true });
|
|
7746
8318
|
for (const [filename, content] of Object.entries(files)) {
|
|
7747
|
-
await
|
|
8319
|
+
await writeFile13(join18(targetDir, filename), content);
|
|
7748
8320
|
}
|
|
7749
8321
|
}
|
|
7750
8322
|
async installAgent(name, content) {
|
|
7751
8323
|
const dir = this.getAgentsDir();
|
|
7752
|
-
await
|
|
7753
|
-
await
|
|
8324
|
+
await mkdir13(dir, { recursive: true });
|
|
8325
|
+
await writeFile13(join18(dir, `${name}.md`), content);
|
|
7754
8326
|
}
|
|
7755
8327
|
generateCommandContent(command) {
|
|
7756
8328
|
let workflow = command.content;
|
|
7757
8329
|
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, "");
|
|
7758
|
-
workflow = workflow.replace(/^# Command: \/
|
|
8330
|
+
workflow = workflow.replace(/^# Command: \/[a-z_]*[\s-]+\n+/g, "");
|
|
7759
8331
|
workflow = workflow.replace(/\$ARGUMENTS/g, "$ARGUMENTS").replace(/\$1/g, "$1").replace(/\$2/g, "$2");
|
|
7760
8332
|
const frontmatter = {
|
|
7761
8333
|
description: command.description,
|
|
@@ -7794,6 +8366,26 @@ ${skill.content}
|
|
|
7794
8366
|
};
|
|
7795
8367
|
return matter4.stringify(agent.systemPrompt, frontmatter);
|
|
7796
8368
|
}
|
|
8369
|
+
/**
|
|
8370
|
+
* Generate commands.json manifest file
|
|
8371
|
+
* This ensures local commands are discovered by Claude Code
|
|
8372
|
+
* and take precedence over parent directory commands
|
|
8373
|
+
*
|
|
8374
|
+
* Reference: https://github.com/anthropics/claude-code/issues/14243
|
|
8375
|
+
*/
|
|
8376
|
+
async generateCommandsManifest() {
|
|
8377
|
+
const commandsDir = this.getCommandsDir();
|
|
8378
|
+
const manifestPath = join18(commandsDir, "commands.json");
|
|
8379
|
+
const sortedCommands = [...this.installedCommands].sort();
|
|
8380
|
+
const manifest = {
|
|
8381
|
+
commands: sortedCommands,
|
|
8382
|
+
// Add version for future compatibility
|
|
8383
|
+
version: "1.0",
|
|
8384
|
+
generatedBy: "aikit",
|
|
8385
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8386
|
+
};
|
|
8387
|
+
await writeFile13(manifestPath, JSON.stringify(manifest, null, 2));
|
|
8388
|
+
}
|
|
7797
8389
|
};
|
|
7798
8390
|
|
|
7799
8391
|
// src/platform/adapters.ts
|
|
@@ -7816,7 +8408,7 @@ var SUPPORTED_PLATFORMS = [
|
|
|
7816
8408
|
function registerInitCommand(program2) {
|
|
7817
8409
|
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) => {
|
|
7818
8410
|
const configDir = options.global ? paths.globalConfig() : paths.projectConfig();
|
|
7819
|
-
console.log(
|
|
8411
|
+
console.log(chalk3.bold("\n\u{1F680} AIKit Setup\n"));
|
|
7820
8412
|
logger.info(`Initializing AIKit in ${configDir}...`);
|
|
7821
8413
|
try {
|
|
7822
8414
|
await initializeConfig(configDir, options.global);
|
|
@@ -7828,9 +8420,9 @@ function registerInitCommand(program2) {
|
|
|
7828
8420
|
} else {
|
|
7829
8421
|
const platforms = await CliDetector.detectPlatforms();
|
|
7830
8422
|
const installed = CliDetector.filterInstalledPlatforms(platforms);
|
|
7831
|
-
console.log(
|
|
8423
|
+
console.log(chalk3.bold("\n\u{1F50D} Available CLI Tools\n"));
|
|
7832
8424
|
for (const p of platforms) {
|
|
7833
|
-
const status = p.installed ?
|
|
8425
|
+
const status = p.installed ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
|
|
7834
8426
|
console.log(` ${status} ${p.displayName}`);
|
|
7835
8427
|
}
|
|
7836
8428
|
const { platform } = await inquirer.prompt([
|
|
@@ -7886,10 +8478,15 @@ function registerInitCommand(program2) {
|
|
|
7886
8478
|
logger.info("Setting up git hooks...");
|
|
7887
8479
|
await beads.setupGitHooks();
|
|
7888
8480
|
logger.success("\u2713 Git hooks configured");
|
|
8481
|
+
const sessionManager = new SessionManager();
|
|
8482
|
+
await sessionManager.init();
|
|
8483
|
+
logger.success("\u2713 Sessions folder initialized");
|
|
8484
|
+
const { tracker } = await sessionManager.initTerminalSession();
|
|
8485
|
+
logger.success(`\u2713 Session tracker initialized (${tracker.split("/").pop()})`);
|
|
7889
8486
|
const adapter = createAdapter(selectedPlatform);
|
|
7890
8487
|
logger.info(`Installing AIKit for ${adapter.displayName}...`);
|
|
7891
8488
|
await installToPlatform(adapter, config);
|
|
7892
|
-
console.log(
|
|
8489
|
+
console.log(chalk3.bold("\n\u2728 AIKit is ready!\n"));
|
|
7893
8490
|
if (selectedPlatform === "opencode" /* OPENCODE */) {
|
|
7894
8491
|
showOpenCodeUsage();
|
|
7895
8492
|
} else if (selectedPlatform === "claude" /* CLAUDE */) {
|
|
@@ -7930,22 +8527,22 @@ async function installToPlatform(adapter, config) {
|
|
|
7930
8527
|
}
|
|
7931
8528
|
function showOpenCodeUsage() {
|
|
7932
8529
|
console.log("Usage in OpenCode:");
|
|
7933
|
-
console.log(
|
|
7934
|
-
console.log(
|
|
7935
|
-
console.log(
|
|
7936
|
-
console.log(
|
|
7937
|
-
console.log(
|
|
7938
|
-
console.log(
|
|
7939
|
-
console.log(
|
|
7940
|
-
console.log("\nPress " +
|
|
8530
|
+
console.log(chalk3.cyan(" /skills") + " - List all available skills");
|
|
8531
|
+
console.log(chalk3.cyan(" /plan") + " - Create implementation plan");
|
|
8532
|
+
console.log(chalk3.cyan(" /tdd") + " - Test-driven development");
|
|
8533
|
+
console.log(chalk3.cyan(" /debug") + " - Systematic debugging");
|
|
8534
|
+
console.log(chalk3.cyan(" /review") + " - Code review checklist");
|
|
8535
|
+
console.log(chalk3.cyan(" /git") + " - Git workflow");
|
|
8536
|
+
console.log(chalk3.cyan(" /frontend-aesthetics") + " - UI/UX guidelines");
|
|
8537
|
+
console.log("\nPress " + chalk3.bold("Ctrl+K") + " in OpenCode to see all commands.\n");
|
|
7941
8538
|
}
|
|
7942
8539
|
function showClaudeUsage() {
|
|
7943
8540
|
console.log("Usage in Claude Code CLI:");
|
|
7944
|
-
console.log(
|
|
7945
|
-
console.log(
|
|
7946
|
-
console.log(
|
|
7947
|
-
console.log(
|
|
7948
|
-
console.log("\nType " +
|
|
8541
|
+
console.log(chalk3.cyan(" /help") + " - List all available commands");
|
|
8542
|
+
console.log(chalk3.cyan(" /plan") + " - Create implementation plan");
|
|
8543
|
+
console.log(chalk3.cyan(" /implement") + " - Implement a task");
|
|
8544
|
+
console.log(chalk3.cyan(" /test") + " - Run tests");
|
|
8545
|
+
console.log("\nType " + chalk3.bold('"/help"') + " in Claude to see all commands.\n");
|
|
7949
8546
|
}
|
|
7950
8547
|
|
|
7951
8548
|
// src/cli/commands/install.ts
|
|
@@ -7953,6 +8550,7 @@ init_esm_shims();
|
|
|
7953
8550
|
init_logger();
|
|
7954
8551
|
import inquirer2 from "inquirer";
|
|
7955
8552
|
init_config();
|
|
8553
|
+
init_sessions();
|
|
7956
8554
|
function registerInstallCommand(program2) {
|
|
7957
8555
|
program2.command("install [platform]").description("Install AIKit to specific CLI tool configuration").action(async (platformArg) => {
|
|
7958
8556
|
try {
|
|
@@ -7983,6 +8581,11 @@ function registerInstallCommand(program2) {
|
|
|
7983
8581
|
selectedPlatform = platform;
|
|
7984
8582
|
}
|
|
7985
8583
|
logger.info(`Installing AIKit for ${selectedPlatform}...`);
|
|
8584
|
+
const sessionManager = new SessionManager();
|
|
8585
|
+
await sessionManager.init();
|
|
8586
|
+
logger.success("\u2713 Sessions folder initialized");
|
|
8587
|
+
const { tracker } = await sessionManager.initTerminalSession();
|
|
8588
|
+
logger.success(`\u2713 Session tracker initialized (${tracker.split("/").pop()})`);
|
|
7986
8589
|
const config = await loadConfig();
|
|
7987
8590
|
const adapter = createAdapter(selectedPlatform);
|
|
7988
8591
|
const skillEngine = config.skills.enabled ? new SkillEngine(config) : null;
|
|
@@ -8015,6 +8618,10 @@ function registerInstallCommand(program2) {
|
|
|
8015
8618
|
logger.info(` \u2713 Created ${name} agent`);
|
|
8016
8619
|
}
|
|
8017
8620
|
}
|
|
8621
|
+
if (selectedPlatform === "claude" && adapter.generateCommandsManifest) {
|
|
8622
|
+
await adapter.generateCommandsManifest();
|
|
8623
|
+
logger.success("\u2713 Generated commands manifest");
|
|
8624
|
+
}
|
|
8018
8625
|
logger.success(`
|
|
8019
8626
|
\u2713 AIKit installed to ${adapter.displayName}!`);
|
|
8020
8627
|
} catch (error) {
|
|
@@ -8027,21 +8634,21 @@ function registerInstallCommand(program2) {
|
|
|
8027
8634
|
// src/cli/commands/sync.ts
|
|
8028
8635
|
init_esm_shims();
|
|
8029
8636
|
init_config();
|
|
8030
|
-
import
|
|
8637
|
+
import chalk5 from "chalk";
|
|
8031
8638
|
|
|
8032
8639
|
// src/core/sync-engine.ts
|
|
8033
8640
|
init_esm_shims();
|
|
8034
|
-
import { readFile as
|
|
8035
|
-
import { join as
|
|
8641
|
+
import { readFile as readFile14, writeFile as writeFile17, copyFile, mkdir as mkdir15 } from "fs/promises";
|
|
8642
|
+
import { join as join22, dirname as dirname4 } from "path";
|
|
8036
8643
|
import inquirer3 from "inquirer";
|
|
8037
|
-
import
|
|
8644
|
+
import chalk4 from "chalk";
|
|
8038
8645
|
|
|
8039
8646
|
// src/core/version-manager.ts
|
|
8040
8647
|
init_esm_shims();
|
|
8041
8648
|
init_paths();
|
|
8042
8649
|
init_logger();
|
|
8043
|
-
import { readFile as
|
|
8044
|
-
import { join as
|
|
8650
|
+
import { readFile as readFile11, readdir as readdir9, writeFile as writeFile14, stat } from "fs/promises";
|
|
8651
|
+
import { join as join19 } from "path";
|
|
8045
8652
|
import { createHash } from "crypto";
|
|
8046
8653
|
var VersionManager = class {
|
|
8047
8654
|
config;
|
|
@@ -8052,9 +8659,9 @@ var VersionManager = class {
|
|
|
8052
8659
|
* Get current installed version
|
|
8053
8660
|
*/
|
|
8054
8661
|
async getCurrentVersion() {
|
|
8055
|
-
const versionPath =
|
|
8662
|
+
const versionPath = join19(paths.globalConfig(), ".version.json");
|
|
8056
8663
|
try {
|
|
8057
|
-
const content = await
|
|
8664
|
+
const content = await readFile11(versionPath, "utf-8");
|
|
8058
8665
|
return JSON.parse(content);
|
|
8059
8666
|
} catch {
|
|
8060
8667
|
return null;
|
|
@@ -8065,7 +8672,7 @@ var VersionManager = class {
|
|
|
8065
8672
|
*/
|
|
8066
8673
|
getPackageVersion() {
|
|
8067
8674
|
try {
|
|
8068
|
-
const packageJson = __require(
|
|
8675
|
+
const packageJson = __require(join19(process.cwd(), "package.json"));
|
|
8069
8676
|
return packageJson.version || "0.0.0";
|
|
8070
8677
|
} catch {
|
|
8071
8678
|
return "0.0.0";
|
|
@@ -8123,9 +8730,9 @@ var VersionManager = class {
|
|
|
8123
8730
|
const removedSkills = [];
|
|
8124
8731
|
const conflicts = [];
|
|
8125
8732
|
const installedSkills = /* @__PURE__ */ new Map();
|
|
8126
|
-
const installedPath =
|
|
8733
|
+
const installedPath = join19(paths.globalConfig(), ".installed-skills.json");
|
|
8127
8734
|
try {
|
|
8128
|
-
const installedData = await
|
|
8735
|
+
const installedData = await readFile11(installedPath, "utf-8");
|
|
8129
8736
|
const installedList = JSON.parse(installedData);
|
|
8130
8737
|
installedList.forEach((skill) => {
|
|
8131
8738
|
installedSkills.set(skill.name, skill);
|
|
@@ -8173,9 +8780,9 @@ var VersionManager = class {
|
|
|
8173
8780
|
const hashes = [];
|
|
8174
8781
|
try {
|
|
8175
8782
|
const loadFromDir = async (dir) => {
|
|
8176
|
-
const files = await
|
|
8783
|
+
const files = await readdir9(dir);
|
|
8177
8784
|
for (const file of files) {
|
|
8178
|
-
const filePath =
|
|
8785
|
+
const filePath = join19(dir, file);
|
|
8179
8786
|
const stats = await stat(filePath);
|
|
8180
8787
|
if (stats.isDirectory()) {
|
|
8181
8788
|
await loadFromDir(filePath);
|
|
@@ -8201,7 +8808,7 @@ var VersionManager = class {
|
|
|
8201
8808
|
*/
|
|
8202
8809
|
async calculateSkillHash(filePath) {
|
|
8203
8810
|
try {
|
|
8204
|
-
const content = await
|
|
8811
|
+
const content = await readFile11(filePath, "utf-8");
|
|
8205
8812
|
return createHash("sha256").update(content).digest("hex");
|
|
8206
8813
|
} catch {
|
|
8207
8814
|
return "";
|
|
@@ -8222,9 +8829,9 @@ var VersionManager = class {
|
|
|
8222
8829
|
* Save installed skills info
|
|
8223
8830
|
*/
|
|
8224
8831
|
async saveInstalledSkills(skills) {
|
|
8225
|
-
const installedPath =
|
|
8832
|
+
const installedPath = join19(paths.globalConfig(), ".installed-skills.json");
|
|
8226
8833
|
try {
|
|
8227
|
-
await
|
|
8834
|
+
await writeFile14(installedPath, JSON.stringify(skills, null, 2));
|
|
8228
8835
|
} catch (error) {
|
|
8229
8836
|
logger.error("Failed to save installed skills info:", error);
|
|
8230
8837
|
}
|
|
@@ -8245,8 +8852,8 @@ var VersionManager = class {
|
|
|
8245
8852
|
packageVersion: this.getPackageVersion(),
|
|
8246
8853
|
migrationHistory: migration ? [...current.migrationHistory, migration] : current.migrationHistory
|
|
8247
8854
|
};
|
|
8248
|
-
const versionPath =
|
|
8249
|
-
await
|
|
8855
|
+
const versionPath = join19(paths.globalConfig(), ".version.json");
|
|
8856
|
+
await writeFile14(versionPath, JSON.stringify(updated, null, 2));
|
|
8250
8857
|
}
|
|
8251
8858
|
/**
|
|
8252
8859
|
* Check if migration is needed
|
|
@@ -8261,8 +8868,8 @@ var VersionManager = class {
|
|
|
8261
8868
|
// src/core/backup-manager.ts
|
|
8262
8869
|
init_esm_shims();
|
|
8263
8870
|
init_logger();
|
|
8264
|
-
import { readFile as
|
|
8265
|
-
import { join as
|
|
8871
|
+
import { readFile as readFile12, writeFile as writeFile15, readdir as readdir10, stat as stat2, unlink as unlink2, mkdir as mkdir14 } from "fs/promises";
|
|
8872
|
+
import { join as join20, dirname as dirname3 } from "path";
|
|
8266
8873
|
import { createHash as createHash2 } from "crypto";
|
|
8267
8874
|
var BackupManager = class {
|
|
8268
8875
|
configPath;
|
|
@@ -8270,7 +8877,7 @@ var BackupManager = class {
|
|
|
8270
8877
|
maxBackups;
|
|
8271
8878
|
constructor(configPath, maxBackups = 5) {
|
|
8272
8879
|
this.configPath = configPath;
|
|
8273
|
-
this.backupsDir =
|
|
8880
|
+
this.backupsDir = join20(configPath, ".backups");
|
|
8274
8881
|
this.maxBackups = maxBackups;
|
|
8275
8882
|
}
|
|
8276
8883
|
/**
|
|
@@ -8278,10 +8885,10 @@ var BackupManager = class {
|
|
|
8278
8885
|
*/
|
|
8279
8886
|
async createBackup(fromVersion, toVersion) {
|
|
8280
8887
|
try {
|
|
8281
|
-
await
|
|
8888
|
+
await mkdir14(this.backupsDir, { recursive: true });
|
|
8282
8889
|
const backupId = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
8283
|
-
const backupPath =
|
|
8284
|
-
await
|
|
8890
|
+
const backupPath = join20(this.backupsDir, `${backupId}-v${toVersion}`);
|
|
8891
|
+
await mkdir14(backupPath, { recursive: true });
|
|
8285
8892
|
logger.info(`Creating backup: ${backupPath}`);
|
|
8286
8893
|
const files = [];
|
|
8287
8894
|
const backupItems = [
|
|
@@ -8302,8 +8909,8 @@ var BackupManager = class {
|
|
|
8302
8909
|
files,
|
|
8303
8910
|
success: true
|
|
8304
8911
|
};
|
|
8305
|
-
const manifestPath =
|
|
8306
|
-
await
|
|
8912
|
+
const manifestPath = join20(backupPath, "backup-manifest.json");
|
|
8913
|
+
await writeFile15(manifestPath, JSON.stringify(manifest, null, 2));
|
|
8307
8914
|
await this.cleanupOldBackups();
|
|
8308
8915
|
logger.success(`\u2713 Backup created: ${backupId}`);
|
|
8309
8916
|
return backupId;
|
|
@@ -8316,20 +8923,20 @@ var BackupManager = class {
|
|
|
8316
8923
|
* Backup a file or directory
|
|
8317
8924
|
*/
|
|
8318
8925
|
async backupItem(sourceDir, item, targetDir) {
|
|
8319
|
-
const sourcePath =
|
|
8320
|
-
const targetPath =
|
|
8926
|
+
const sourcePath = join20(sourceDir, item);
|
|
8927
|
+
const targetPath = join20(targetDir, item);
|
|
8321
8928
|
const files = [];
|
|
8322
8929
|
try {
|
|
8323
8930
|
const stats = await stat2(sourcePath);
|
|
8324
8931
|
if (stats.isDirectory()) {
|
|
8325
|
-
await
|
|
8326
|
-
const entries = await
|
|
8932
|
+
await mkdir14(targetPath, { recursive: true });
|
|
8933
|
+
const entries = await readdir10(sourcePath);
|
|
8327
8934
|
for (const entry of entries) {
|
|
8328
8935
|
const entryFiles = await this.backupItem(sourcePath, entry, targetPath);
|
|
8329
8936
|
files.push(...entryFiles);
|
|
8330
8937
|
}
|
|
8331
8938
|
} else if (stats.isFile()) {
|
|
8332
|
-
await
|
|
8939
|
+
await mkdir14(dirname3(targetPath), { recursive: true });
|
|
8333
8940
|
await this.copyFile(sourcePath, targetPath);
|
|
8334
8941
|
const hash = await this.calculateHash(targetPath);
|
|
8335
8942
|
files.push({
|
|
@@ -8347,15 +8954,15 @@ var BackupManager = class {
|
|
|
8347
8954
|
* Copy file with hash calculation
|
|
8348
8955
|
*/
|
|
8349
8956
|
async copyFile(source, target) {
|
|
8350
|
-
const content = await
|
|
8351
|
-
await
|
|
8957
|
+
const content = await readFile12(source);
|
|
8958
|
+
await writeFile15(target, content);
|
|
8352
8959
|
}
|
|
8353
8960
|
/**
|
|
8354
8961
|
* Calculate file hash
|
|
8355
8962
|
*/
|
|
8356
8963
|
async calculateHash(filePath) {
|
|
8357
8964
|
try {
|
|
8358
|
-
const content = await
|
|
8965
|
+
const content = await readFile12(filePath);
|
|
8359
8966
|
return createHash2("sha256").update(content).digest("hex");
|
|
8360
8967
|
} catch {
|
|
8361
8968
|
return "";
|
|
@@ -8366,13 +8973,13 @@ var BackupManager = class {
|
|
|
8366
8973
|
*/
|
|
8367
8974
|
async listBackups() {
|
|
8368
8975
|
try {
|
|
8369
|
-
const entries = await
|
|
8976
|
+
const entries = await readdir10(this.backupsDir);
|
|
8370
8977
|
const backups = [];
|
|
8371
8978
|
for (const entry of entries) {
|
|
8372
|
-
const backupPath =
|
|
8373
|
-
const manifestPath =
|
|
8979
|
+
const backupPath = join20(this.backupsDir, entry);
|
|
8980
|
+
const manifestPath = join20(backupPath, "backup-manifest.json");
|
|
8374
8981
|
try {
|
|
8375
|
-
const manifestContent = await
|
|
8982
|
+
const manifestContent = await readFile12(manifestPath, "utf-8");
|
|
8376
8983
|
const manifest = JSON.parse(manifestContent);
|
|
8377
8984
|
const size = await this.calculateBackupSize(backupPath);
|
|
8378
8985
|
backups.push({
|
|
@@ -8398,9 +9005,9 @@ var BackupManager = class {
|
|
|
8398
9005
|
let totalSize = 0;
|
|
8399
9006
|
try {
|
|
8400
9007
|
const calculate = async (dir) => {
|
|
8401
|
-
const entries = await
|
|
9008
|
+
const entries = await readdir10(dir);
|
|
8402
9009
|
for (const entry of entries) {
|
|
8403
|
-
const entryPath =
|
|
9010
|
+
const entryPath = join20(dir, entry);
|
|
8404
9011
|
const stats = await stat2(entryPath);
|
|
8405
9012
|
if (stats.isDirectory()) {
|
|
8406
9013
|
await calculate(entryPath);
|
|
@@ -8432,9 +9039,9 @@ var BackupManager = class {
|
|
|
8432
9039
|
return false;
|
|
8433
9040
|
}
|
|
8434
9041
|
for (const file of backup.manifest.files) {
|
|
8435
|
-
const sourcePath =
|
|
8436
|
-
const targetPath =
|
|
8437
|
-
await
|
|
9042
|
+
const sourcePath = join20(backup.path, file.path);
|
|
9043
|
+
const targetPath = join20(this.configPath, file.path);
|
|
9044
|
+
await mkdir14(dirname3(targetPath), { recursive: true });
|
|
8438
9045
|
await this.copyFile(sourcePath, targetPath);
|
|
8439
9046
|
}
|
|
8440
9047
|
logger.success(`\u2713 Backup restored: ${backupId}`);
|
|
@@ -8449,10 +9056,10 @@ var BackupManager = class {
|
|
|
8449
9056
|
*/
|
|
8450
9057
|
async validateBackup(backup) {
|
|
8451
9058
|
try {
|
|
8452
|
-
const manifestPath =
|
|
8453
|
-
await
|
|
9059
|
+
const manifestPath = join20(backup.path, "backup-manifest.json");
|
|
9060
|
+
await readFile12(manifestPath, "utf-8");
|
|
8454
9061
|
for (const file of backup.manifest.files) {
|
|
8455
|
-
const filePath =
|
|
9062
|
+
const filePath = join20(backup.path, file.path);
|
|
8456
9063
|
await stat2(filePath);
|
|
8457
9064
|
const currentHash = await this.calculateHash(filePath);
|
|
8458
9065
|
if (currentHash !== file.hash) {
|
|
@@ -8476,14 +9083,14 @@ var BackupManager = class {
|
|
|
8476
9083
|
if (!backup) {
|
|
8477
9084
|
return false;
|
|
8478
9085
|
}
|
|
8479
|
-
const entries = await
|
|
9086
|
+
const entries = await readdir10(backup.path);
|
|
8480
9087
|
for (const entry of entries) {
|
|
8481
|
-
const entryPath =
|
|
9088
|
+
const entryPath = join20(backup.path, entry);
|
|
8482
9089
|
const stats = await stat2(entryPath);
|
|
8483
9090
|
if (stats.isDirectory()) {
|
|
8484
9091
|
await this.removeDirectory(entryPath);
|
|
8485
9092
|
} else {
|
|
8486
|
-
await
|
|
9093
|
+
await unlink2(entryPath);
|
|
8487
9094
|
}
|
|
8488
9095
|
}
|
|
8489
9096
|
logger.success(`\u2713 Backup deleted: ${backupId}`);
|
|
@@ -8497,17 +9104,17 @@ var BackupManager = class {
|
|
|
8497
9104
|
* Remove directory recursively
|
|
8498
9105
|
*/
|
|
8499
9106
|
async removeDirectory(dirPath) {
|
|
8500
|
-
const entries = await
|
|
9107
|
+
const entries = await readdir10(dirPath);
|
|
8501
9108
|
for (const entry of entries) {
|
|
8502
|
-
const entryPath =
|
|
9109
|
+
const entryPath = join20(dirPath, entry);
|
|
8503
9110
|
const stats = await stat2(entryPath);
|
|
8504
9111
|
if (stats.isDirectory()) {
|
|
8505
9112
|
await this.removeDirectory(entryPath);
|
|
8506
9113
|
} else {
|
|
8507
|
-
await
|
|
9114
|
+
await unlink2(entryPath);
|
|
8508
9115
|
}
|
|
8509
9116
|
}
|
|
8510
|
-
await
|
|
9117
|
+
await unlink2(dirPath);
|
|
8511
9118
|
}
|
|
8512
9119
|
/**
|
|
8513
9120
|
* Cleanup old backups (keep only maxBackups)
|
|
@@ -8545,14 +9152,14 @@ var BackupManager = class {
|
|
|
8545
9152
|
// src/core/migration-manager.ts
|
|
8546
9153
|
init_esm_shims();
|
|
8547
9154
|
init_logger();
|
|
8548
|
-
import { readFile as
|
|
8549
|
-
import { join as
|
|
9155
|
+
import { readFile as readFile13, writeFile as writeFile16, readdir as readdir11 } from "fs/promises";
|
|
9156
|
+
import { join as join21 } from "path";
|
|
8550
9157
|
var MigrationManager = class {
|
|
8551
9158
|
configPath;
|
|
8552
9159
|
migrationsDir;
|
|
8553
9160
|
constructor(configPath) {
|
|
8554
9161
|
this.configPath = configPath;
|
|
8555
|
-
this.migrationsDir =
|
|
9162
|
+
this.migrationsDir = join21(process.cwd(), "src/core/migrations");
|
|
8556
9163
|
}
|
|
8557
9164
|
/**
|
|
8558
9165
|
* Load all available migrations
|
|
@@ -8560,11 +9167,11 @@ var MigrationManager = class {
|
|
|
8560
9167
|
async loadMigrations() {
|
|
8561
9168
|
const migrations = [];
|
|
8562
9169
|
try {
|
|
8563
|
-
const files = await
|
|
9170
|
+
const files = await readdir11(this.migrationsDir);
|
|
8564
9171
|
for (const file of files) {
|
|
8565
9172
|
if (file.endsWith(".js") && file.startsWith("migrate-")) {
|
|
8566
9173
|
try {
|
|
8567
|
-
const module = await import(
|
|
9174
|
+
const module = await import(join21(this.migrationsDir, file));
|
|
8568
9175
|
const migration = module.default || module.migration;
|
|
8569
9176
|
if (migration) {
|
|
8570
9177
|
migrations.push(migration);
|
|
@@ -8583,9 +9190,9 @@ var MigrationManager = class {
|
|
|
8583
9190
|
* Get applied migrations
|
|
8584
9191
|
*/
|
|
8585
9192
|
async getAppliedMigrations() {
|
|
8586
|
-
const migrationHistoryPath =
|
|
9193
|
+
const migrationHistoryPath = join21(this.configPath, ".migration-history.json");
|
|
8587
9194
|
try {
|
|
8588
|
-
const content = await
|
|
9195
|
+
const content = await readFile13(migrationHistoryPath, "utf-8");
|
|
8589
9196
|
const history = JSON.parse(content);
|
|
8590
9197
|
return history.filter((m) => m.status === "completed").map((m) => m.to);
|
|
8591
9198
|
} catch {
|
|
@@ -8671,16 +9278,16 @@ var MigrationManager = class {
|
|
|
8671
9278
|
* Update migration history
|
|
8672
9279
|
*/
|
|
8673
9280
|
async updateMigrationHistory(entries) {
|
|
8674
|
-
const historyPath =
|
|
9281
|
+
const historyPath = join21(this.configPath, ".migration-history.json");
|
|
8675
9282
|
try {
|
|
8676
9283
|
let history = [];
|
|
8677
9284
|
try {
|
|
8678
|
-
const content = await
|
|
9285
|
+
const content = await readFile13(historyPath, "utf-8");
|
|
8679
9286
|
history = JSON.parse(content);
|
|
8680
9287
|
} catch {
|
|
8681
9288
|
}
|
|
8682
9289
|
history.push(...entries);
|
|
8683
|
-
await
|
|
9290
|
+
await writeFile16(historyPath, JSON.stringify(history, null, 2));
|
|
8684
9291
|
} catch (error) {
|
|
8685
9292
|
logger.error("Failed to update migration history:", error);
|
|
8686
9293
|
}
|
|
@@ -8689,14 +9296,14 @@ var MigrationManager = class {
|
|
|
8689
9296
|
* Update migration history status
|
|
8690
9297
|
*/
|
|
8691
9298
|
async updateMigrationHistoryStatus(version, status) {
|
|
8692
|
-
const historyPath =
|
|
9299
|
+
const historyPath = join21(this.configPath, ".migration-history.json");
|
|
8693
9300
|
try {
|
|
8694
|
-
const content = await
|
|
9301
|
+
const content = await readFile13(historyPath, "utf-8");
|
|
8695
9302
|
const history = JSON.parse(content);
|
|
8696
9303
|
const updated = history.map(
|
|
8697
9304
|
(m) => m.to === version ? { ...m, status } : m
|
|
8698
9305
|
);
|
|
8699
|
-
await
|
|
9306
|
+
await writeFile16(historyPath, JSON.stringify(updated, null, 2));
|
|
8700
9307
|
} catch (error) {
|
|
8701
9308
|
logger.error("Failed to update migration history status:", error);
|
|
8702
9309
|
}
|
|
@@ -8705,9 +9312,9 @@ var MigrationManager = class {
|
|
|
8705
9312
|
* Get migration history
|
|
8706
9313
|
*/
|
|
8707
9314
|
async getMigrationHistory() {
|
|
8708
|
-
const historyPath =
|
|
9315
|
+
const historyPath = join21(this.configPath, ".migration-history.json");
|
|
8709
9316
|
try {
|
|
8710
|
-
const content = await
|
|
9317
|
+
const content = await readFile13(historyPath, "utf-8");
|
|
8711
9318
|
return JSON.parse(content);
|
|
8712
9319
|
} catch {
|
|
8713
9320
|
return [];
|
|
@@ -8747,7 +9354,7 @@ var SyncEngine = class {
|
|
|
8747
9354
|
if (changes.hasUpdate) {
|
|
8748
9355
|
this.displayUpdateInfo(changes);
|
|
8749
9356
|
} else {
|
|
8750
|
-
console.log(
|
|
9357
|
+
console.log(chalk4.green("\u2713 Your AIKit is up to date"));
|
|
8751
9358
|
console.log(` Installed: ${changes.fromVersion}`);
|
|
8752
9359
|
console.log(` Latest: ${changes.toVersion}`);
|
|
8753
9360
|
}
|
|
@@ -8762,15 +9369,15 @@ var SyncEngine = class {
|
|
|
8762
9369
|
*/
|
|
8763
9370
|
async previewUpdate() {
|
|
8764
9371
|
try {
|
|
8765
|
-
console.log(
|
|
9372
|
+
console.log(chalk4.bold("\n\u{1F50D} Previewing update...\n"));
|
|
8766
9373
|
const changes = await this.versionManager.checkForUpdates();
|
|
8767
9374
|
if (!changes.hasUpdate) {
|
|
8768
|
-
console.log(
|
|
9375
|
+
console.log(chalk4.green("\u2713 No updates available"));
|
|
8769
9376
|
return false;
|
|
8770
9377
|
}
|
|
8771
9378
|
await this.displayChanges(changes);
|
|
8772
|
-
console.log(
|
|
8773
|
-
console.log(
|
|
9379
|
+
console.log(chalk4.yellow("\n\u26A0\uFE0F This is a preview - no changes will be made."));
|
|
9380
|
+
console.log(chalk4.gray("Use `aikit sync apply` to apply these changes."));
|
|
8774
9381
|
return true;
|
|
8775
9382
|
} catch (error) {
|
|
8776
9383
|
logger.error("Failed to preview update:", error);
|
|
@@ -8784,7 +9391,7 @@ var SyncEngine = class {
|
|
|
8784
9391
|
try {
|
|
8785
9392
|
const changes = await this.versionManager.checkForUpdates();
|
|
8786
9393
|
if (!changes.hasUpdate) {
|
|
8787
|
-
console.log(
|
|
9394
|
+
console.log(chalk4.green("\u2713 Already up to date"));
|
|
8788
9395
|
return {
|
|
8789
9396
|
success: true,
|
|
8790
9397
|
newSkills: [],
|
|
@@ -8802,7 +9409,7 @@ var SyncEngine = class {
|
|
|
8802
9409
|
default: false
|
|
8803
9410
|
}]);
|
|
8804
9411
|
if (!confirmed) {
|
|
8805
|
-
console.log(
|
|
9412
|
+
console.log(chalk4.yellow("Update cancelled"));
|
|
8806
9413
|
return {
|
|
8807
9414
|
success: false,
|
|
8808
9415
|
newSkills: [],
|
|
@@ -8814,7 +9421,7 @@ var SyncEngine = class {
|
|
|
8814
9421
|
}
|
|
8815
9422
|
let backupId = void 0;
|
|
8816
9423
|
if (!options.dryRun && options.backup !== false) {
|
|
8817
|
-
console.log(
|
|
9424
|
+
console.log(chalk4.bold("\n\u{1F4E6} Creating backup..."));
|
|
8818
9425
|
const backupResult = await this.backupManager.createBackup(
|
|
8819
9426
|
changes.fromVersion,
|
|
8820
9427
|
changes.toVersion
|
|
@@ -8827,19 +9434,19 @@ var SyncEngine = class {
|
|
|
8827
9434
|
for (const conflict of changes.conflicts) {
|
|
8828
9435
|
await this.resolveConflict(conflict);
|
|
8829
9436
|
}
|
|
8830
|
-
console.log(
|
|
9437
|
+
console.log(chalk4.bold("\n\u{1F504} Running migrations..."));
|
|
8831
9438
|
const migrationResult = await this.migrationManager.runPendingMigrations();
|
|
8832
9439
|
if (!migrationResult.success) {
|
|
8833
9440
|
throw new Error(`Migration failed: ${migrationResult.failed.join(", ")}`);
|
|
8834
9441
|
}
|
|
8835
|
-
console.log(
|
|
9442
|
+
console.log(chalk4.bold("\n\u{1F4DD} Updating skills..."));
|
|
8836
9443
|
const updateResult = await this.updateSkills(changes, options);
|
|
8837
9444
|
await this.versionManager.updateVersion(changes.toVersion);
|
|
8838
9445
|
if (backupId) {
|
|
8839
9446
|
const allSkills = await this.versionManager.loadSkillHashes(paths.skills(paths.globalConfig()));
|
|
8840
9447
|
await this.versionManager.saveInstalledSkills(allSkills);
|
|
8841
9448
|
}
|
|
8842
|
-
console.log(
|
|
9449
|
+
console.log(chalk4.green("\n\u2705 Update complete!"));
|
|
8843
9450
|
this.displaySummary({
|
|
8844
9451
|
success: true,
|
|
8845
9452
|
backupId,
|
|
@@ -8854,7 +9461,7 @@ var SyncEngine = class {
|
|
|
8854
9461
|
};
|
|
8855
9462
|
} catch (error) {
|
|
8856
9463
|
logger.error("Update failed:", error);
|
|
8857
|
-
console.log(
|
|
9464
|
+
console.log(chalk4.red("\n\u274C Update failed"));
|
|
8858
9465
|
return {
|
|
8859
9466
|
success: false,
|
|
8860
9467
|
newSkills: [],
|
|
@@ -8869,11 +9476,11 @@ var SyncEngine = class {
|
|
|
8869
9476
|
*/
|
|
8870
9477
|
async rollback(backupId) {
|
|
8871
9478
|
try {
|
|
8872
|
-
console.log(
|
|
9479
|
+
console.log(chalk4.bold("\n\u{1F504} Rollback...\n"));
|
|
8873
9480
|
if (!backupId) {
|
|
8874
9481
|
const backups = await this.backupManager.listBackups();
|
|
8875
9482
|
if (backups.length === 0) {
|
|
8876
|
-
console.log(
|
|
9483
|
+
console.log(chalk4.yellow("No backups available"));
|
|
8877
9484
|
return false;
|
|
8878
9485
|
}
|
|
8879
9486
|
const { selectedBackup } = await inquirer3.prompt([{
|
|
@@ -8888,12 +9495,12 @@ var SyncEngine = class {
|
|
|
8888
9495
|
backupId = selectedBackup;
|
|
8889
9496
|
}
|
|
8890
9497
|
if (!backupId) {
|
|
8891
|
-
console.log(
|
|
9498
|
+
console.log(chalk4.yellow("No backup ID provided"));
|
|
8892
9499
|
return false;
|
|
8893
9500
|
}
|
|
8894
9501
|
const success = await this.backupManager.restoreBackup(backupId);
|
|
8895
9502
|
if (success) {
|
|
8896
|
-
console.log(
|
|
9503
|
+
console.log(chalk4.green("\u2713 Rollback complete"));
|
|
8897
9504
|
return true;
|
|
8898
9505
|
}
|
|
8899
9506
|
return false;
|
|
@@ -8906,36 +9513,36 @@ var SyncEngine = class {
|
|
|
8906
9513
|
* Display update information
|
|
8907
9514
|
*/
|
|
8908
9515
|
displayUpdateInfo(changes) {
|
|
8909
|
-
console.log(
|
|
8910
|
-
console.log(` ${
|
|
8911
|
-
console.log(` ${
|
|
9516
|
+
console.log(chalk4.bold("\n\u{1F4E2} New version available!\n"));
|
|
9517
|
+
console.log(` ${chalk4.cyan("Current:")} ${changes.fromVersion}`);
|
|
9518
|
+
console.log(` ${chalk4.cyan("Latest:")} ${changes.toVersion}
|
|
8912
9519
|
`);
|
|
8913
9520
|
}
|
|
8914
9521
|
/**
|
|
8915
9522
|
* Display changes summary
|
|
8916
9523
|
*/
|
|
8917
9524
|
async displayChanges(changes) {
|
|
8918
|
-
console.log(
|
|
9525
|
+
console.log(chalk4.bold("\u{1F4CA} Changes detected:\n"));
|
|
8919
9526
|
if (changes.newSkills.length > 0) {
|
|
8920
|
-
console.log(
|
|
9527
|
+
console.log(chalk4.green(" New Skills:"));
|
|
8921
9528
|
changes.newSkills.forEach((skill) => {
|
|
8922
9529
|
console.log(` + ${skill.name} (${skill.category})`);
|
|
8923
9530
|
});
|
|
8924
9531
|
}
|
|
8925
9532
|
if (changes.modifiedSkills.length > 0) {
|
|
8926
|
-
console.log(
|
|
9533
|
+
console.log(chalk4.yellow(" Updated Skills:"));
|
|
8927
9534
|
changes.modifiedSkills.forEach((skill) => {
|
|
8928
9535
|
console.log(` ~ ${skill.name}`);
|
|
8929
9536
|
});
|
|
8930
9537
|
}
|
|
8931
9538
|
if (changes.removedSkills.length > 0) {
|
|
8932
|
-
console.log(
|
|
9539
|
+
console.log(chalk4.red(" Removed Skills:"));
|
|
8933
9540
|
changes.removedSkills.forEach((skill) => {
|
|
8934
9541
|
console.log(` - ${skill.name}`);
|
|
8935
9542
|
});
|
|
8936
9543
|
}
|
|
8937
9544
|
if (changes.conflicts.length > 0) {
|
|
8938
|
-
console.log(
|
|
9545
|
+
console.log(chalk4.bold.red(" \u26A0\uFE0F Conflicts:"));
|
|
8939
9546
|
changes.conflicts.forEach((conflict) => {
|
|
8940
9547
|
console.log(` ! ${conflict.skillName} (user modified)`);
|
|
8941
9548
|
});
|
|
@@ -8945,10 +9552,10 @@ var SyncEngine = class {
|
|
|
8945
9552
|
* Resolve a conflict
|
|
8946
9553
|
*/
|
|
8947
9554
|
async resolveConflict(conflict) {
|
|
8948
|
-
console.log(
|
|
9555
|
+
console.log(chalk4.bold.red(`
|
|
8949
9556
|
\u26A0\uFE0F Conflict detected: ${conflict.skillName}
|
|
8950
9557
|
`));
|
|
8951
|
-
console.log(
|
|
9558
|
+
console.log(chalk4.yellow("Your version differs from official version."));
|
|
8952
9559
|
const { action } = await inquirer3.prompt([{
|
|
8953
9560
|
type: "list",
|
|
8954
9561
|
name: "action",
|
|
@@ -8974,7 +9581,7 @@ var SyncEngine = class {
|
|
|
8974
9581
|
if (action === "overwrite") {
|
|
8975
9582
|
return;
|
|
8976
9583
|
}
|
|
8977
|
-
console.log(
|
|
9584
|
+
console.log(chalk4.yellow(" Your version will be preserved as -custom.md"));
|
|
8978
9585
|
}
|
|
8979
9586
|
/**
|
|
8980
9587
|
* Update skills based on changes
|
|
@@ -8990,21 +9597,21 @@ var SyncEngine = class {
|
|
|
8990
9597
|
await this.installSkill(globalSkillsPath, skill, projectSkillsPath);
|
|
8991
9598
|
}
|
|
8992
9599
|
newSkills.push(skill.name);
|
|
8993
|
-
console.log(
|
|
9600
|
+
console.log(chalk4.green(` + ${skill.name}`));
|
|
8994
9601
|
}
|
|
8995
9602
|
for (const skill of changes.modifiedSkills) {
|
|
8996
9603
|
if (!options.dryRun) {
|
|
8997
9604
|
await this.installSkill(globalSkillsPath, skill, projectSkillsPath);
|
|
8998
9605
|
}
|
|
8999
9606
|
updatedSkills.push(skill.name);
|
|
9000
|
-
console.log(
|
|
9607
|
+
console.log(chalk4.yellow(` ~ ${skill.name}`));
|
|
9001
9608
|
}
|
|
9002
9609
|
for (const skill of changes.removedSkills) {
|
|
9003
9610
|
if (!options.dryRun) {
|
|
9004
9611
|
await this.archiveSkill(projectSkillsPath, skill);
|
|
9005
9612
|
}
|
|
9006
9613
|
removedSkills.push(skill.name);
|
|
9007
|
-
console.log(
|
|
9614
|
+
console.log(chalk4.red(` - ${skill.name} (archived)`));
|
|
9008
9615
|
}
|
|
9009
9616
|
return {
|
|
9010
9617
|
newSkills,
|
|
@@ -9016,19 +9623,19 @@ var SyncEngine = class {
|
|
|
9016
9623
|
* Install a skill
|
|
9017
9624
|
*/
|
|
9018
9625
|
async installSkill(sourceDir, skill, targetDir) {
|
|
9019
|
-
const sourcePath =
|
|
9020
|
-
const targetPath =
|
|
9021
|
-
await
|
|
9626
|
+
const sourcePath = join22(sourceDir, skill.category, `${skill.name}.md`);
|
|
9627
|
+
const targetPath = join22(targetDir, skill.category, `${skill.name}.md`);
|
|
9628
|
+
await mkdir15(dirname4(targetPath), { recursive: true });
|
|
9022
9629
|
await copyFile(sourcePath, targetPath);
|
|
9023
9630
|
}
|
|
9024
9631
|
/**
|
|
9025
9632
|
* Archive a removed skill
|
|
9026
9633
|
*/
|
|
9027
9634
|
async archiveSkill(targetDir, skill) {
|
|
9028
|
-
const sourcePath =
|
|
9029
|
-
const targetPath =
|
|
9635
|
+
const sourcePath = join22(targetDir, skill.category, `${skill.name}.md`);
|
|
9636
|
+
const targetPath = join22(targetDir, skill.category, `${skill.name}-deprecated.md`);
|
|
9030
9637
|
try {
|
|
9031
|
-
const content = await
|
|
9638
|
+
const content = await readFile14(sourcePath, "utf-8");
|
|
9032
9639
|
const deprecatedNotice = `---
|
|
9033
9640
|
\u26A0\uFE0F DEPRECATED: This skill has been removed
|
|
9034
9641
|
|
|
@@ -9037,11 +9644,11 @@ Reason: Check release notes for replacement
|
|
|
9037
9644
|
---
|
|
9038
9645
|
|
|
9039
9646
|
${content}`;
|
|
9040
|
-
await
|
|
9041
|
-
await
|
|
9647
|
+
await mkdir15(dirname4(targetPath), { recursive: true });
|
|
9648
|
+
await writeFile17(targetPath, deprecatedNotice);
|
|
9042
9649
|
} catch (error) {
|
|
9043
9650
|
if (error.code === "ENOENT") {
|
|
9044
|
-
console.log(
|
|
9651
|
+
console.log(chalk4.yellow(` - ${skill.name} (not found, skipping)`));
|
|
9045
9652
|
} else {
|
|
9046
9653
|
throw error;
|
|
9047
9654
|
}
|
|
@@ -9051,24 +9658,24 @@ ${content}`;
|
|
|
9051
9658
|
* Display sync summary
|
|
9052
9659
|
*/
|
|
9053
9660
|
displaySummary(result) {
|
|
9054
|
-
console.log(
|
|
9055
|
-
console.log(` Updated from: ${
|
|
9056
|
-
console.log(` Updated to: ${
|
|
9661
|
+
console.log(chalk4.bold("\n\u{1F4CB} Summary:\n"));
|
|
9662
|
+
console.log(` Updated from: ${chalk4.cyan(result.backupId || "N/A")}`);
|
|
9663
|
+
console.log(` Updated to: ${chalk4.cyan("current")}`);
|
|
9057
9664
|
console.log();
|
|
9058
9665
|
if (result.newSkills.length > 0) {
|
|
9059
|
-
console.log(
|
|
9666
|
+
console.log(chalk4.green(` ${result.newSkills.length} new skills installed`));
|
|
9060
9667
|
}
|
|
9061
9668
|
if (result.updatedSkills.length > 0) {
|
|
9062
|
-
console.log(
|
|
9669
|
+
console.log(chalk4.yellow(` ${result.updatedSkills.length} skills updated`));
|
|
9063
9670
|
}
|
|
9064
9671
|
if (result.removedSkills.length > 0) {
|
|
9065
|
-
console.log(
|
|
9672
|
+
console.log(chalk4.red(` ${result.removedSkills.length} skills archived`));
|
|
9066
9673
|
}
|
|
9067
9674
|
if (result.migrationsRun.length > 0) {
|
|
9068
|
-
console.log(
|
|
9675
|
+
console.log(chalk4.blue(` ${result.migrationsRun.length} migrations run`));
|
|
9069
9676
|
}
|
|
9070
9677
|
if (result.backupId) {
|
|
9071
|
-
console.log(
|
|
9678
|
+
console.log(chalk4.gray(`
|
|
9072
9679
|
Rollback available: aikit sync rollback ${result.backupId}`));
|
|
9073
9680
|
}
|
|
9074
9681
|
}
|
|
@@ -9098,7 +9705,7 @@ function registerSyncCommand(program2) {
|
|
|
9098
9705
|
break;
|
|
9099
9706
|
default:
|
|
9100
9707
|
logger.error(`Unknown subcommand: ${subcommand}`);
|
|
9101
|
-
console.log(
|
|
9708
|
+
console.log(chalk5.gray("Available subcommands: check, preview, apply, rollback"));
|
|
9102
9709
|
process.exit(1);
|
|
9103
9710
|
}
|
|
9104
9711
|
}
|
|
@@ -9108,7 +9715,7 @@ function registerSyncCommand(program2) {
|
|
|
9108
9715
|
// src/cli/commands/skills.ts
|
|
9109
9716
|
init_esm_shims();
|
|
9110
9717
|
init_config();
|
|
9111
|
-
import
|
|
9718
|
+
import chalk6 from "chalk";
|
|
9112
9719
|
init_logger();
|
|
9113
9720
|
function registerSkillsCommand(program2) {
|
|
9114
9721
|
const skillsCmd = program2.command("skills").description("Manage skills");
|
|
@@ -9119,31 +9726,31 @@ function registerSkillsCommand(program2) {
|
|
|
9119
9726
|
const { ToolConfigManager: ToolConfigManager2 } = await Promise.resolve().then(() => (init_tool_config(), tool_config_exports));
|
|
9120
9727
|
const toolConfigManager = new ToolConfigManager2(config);
|
|
9121
9728
|
const tools = await toolConfigManager.listTools();
|
|
9122
|
-
console.log(
|
|
9729
|
+
console.log(chalk6.bold("\n\u{1F4DA} Available Skills:\n"));
|
|
9123
9730
|
for (const skill of skills) {
|
|
9124
|
-
console.log(` ${
|
|
9731
|
+
console.log(` ${chalk6.cyan(skill.name)} - ${skill.description}`);
|
|
9125
9732
|
}
|
|
9126
|
-
console.log(
|
|
9733
|
+
console.log(chalk6.bold("\n\u{1F527} Available Tools:\n"));
|
|
9127
9734
|
for (const tool of tools) {
|
|
9128
9735
|
let statusIcon = " ";
|
|
9129
9736
|
let statusText = "";
|
|
9130
9737
|
if (tool.status === "ready") {
|
|
9131
|
-
statusIcon =
|
|
9132
|
-
statusText =
|
|
9738
|
+
statusIcon = chalk6.green("\u2713");
|
|
9739
|
+
statusText = chalk6.gray("(ready)");
|
|
9133
9740
|
} else if (tool.status === "needs_config") {
|
|
9134
|
-
statusIcon =
|
|
9135
|
-
statusText =
|
|
9741
|
+
statusIcon = chalk6.yellow("\u26A0");
|
|
9742
|
+
statusText = chalk6.yellow("(needs config)");
|
|
9136
9743
|
} else if (tool.status === "error") {
|
|
9137
|
-
statusIcon =
|
|
9138
|
-
statusText =
|
|
9744
|
+
statusIcon = chalk6.red("\u2717");
|
|
9745
|
+
statusText = chalk6.red("(error)");
|
|
9139
9746
|
}
|
|
9140
|
-
console.log(` ${statusIcon} ${
|
|
9747
|
+
console.log(` ${statusIcon} ${chalk6.cyan(tool.name)} - ${tool.description} ${statusText}`);
|
|
9141
9748
|
if (tool.errorMessage) {
|
|
9142
|
-
console.log(` ${
|
|
9749
|
+
console.log(` ${chalk6.red("Error:")} ${tool.errorMessage}`);
|
|
9143
9750
|
}
|
|
9144
9751
|
}
|
|
9145
9752
|
console.log();
|
|
9146
|
-
console.log(
|
|
9753
|
+
console.log(chalk6.gray('Tip: Use "aikit skills <tool-name> config" to configure a tool\n'));
|
|
9147
9754
|
});
|
|
9148
9755
|
skillsCmd.command("show <name>").description("Show skill details").action(async (name) => {
|
|
9149
9756
|
const config = await loadConfig();
|
|
@@ -9153,11 +9760,11 @@ function registerSkillsCommand(program2) {
|
|
|
9153
9760
|
logger.error(`Skill not found: ${name}`);
|
|
9154
9761
|
process.exit(1);
|
|
9155
9762
|
}
|
|
9156
|
-
console.log(
|
|
9763
|
+
console.log(chalk6.bold(`
|
|
9157
9764
|
\u{1F4D6} Skill: ${skill.name}
|
|
9158
9765
|
`));
|
|
9159
|
-
console.log(
|
|
9160
|
-
console.log(
|
|
9766
|
+
console.log(chalk6.gray(skill.description));
|
|
9767
|
+
console.log(chalk6.bold("\nWorkflow:"));
|
|
9161
9768
|
console.log(skill.content);
|
|
9162
9769
|
});
|
|
9163
9770
|
skillsCmd.command("create <name>").description("Create a new skill").action(async (name) => {
|
|
@@ -9173,11 +9780,11 @@ function registerSkillsCommand(program2) {
|
|
|
9173
9780
|
if (result.count === 0) {
|
|
9174
9781
|
logger.info("Skills already in sync or no global skills to sync");
|
|
9175
9782
|
} else {
|
|
9176
|
-
console.log(
|
|
9783
|
+
console.log(chalk6.bold(`
|
|
9177
9784
|
\u2713 Synced ${result.count} skills to project:
|
|
9178
9785
|
`));
|
|
9179
9786
|
for (const skill of result.synced) {
|
|
9180
|
-
console.log(` ${
|
|
9787
|
+
console.log(` ${chalk6.cyan("\u2022")} ${skill}`);
|
|
9181
9788
|
}
|
|
9182
9789
|
console.log();
|
|
9183
9790
|
}
|
|
@@ -9193,7 +9800,7 @@ function registerSkillsCommand(program2) {
|
|
|
9193
9800
|
await configureToolAction(toolName);
|
|
9194
9801
|
} else {
|
|
9195
9802
|
logger.error(`Unknown command: ${toolName || "unknown"} ${action || ""}`);
|
|
9196
|
-
console.log(
|
|
9803
|
+
console.log(chalk6.gray("\nAvailable commands:"));
|
|
9197
9804
|
console.log(" aikit skills list - List all skills and tools");
|
|
9198
9805
|
console.log(" aikit skills show <name> - Show skill details");
|
|
9199
9806
|
console.log(" aikit skills config <tool-name> - Configure a tool");
|
|
@@ -9211,20 +9818,20 @@ async function configureToolAction(toolName) {
|
|
|
9211
9818
|
const tool = await toolConfigManager.getToolConfig(toolName);
|
|
9212
9819
|
if (!tool) {
|
|
9213
9820
|
logger.error(`Tool not found: ${toolName}`);
|
|
9214
|
-
console.log(
|
|
9821
|
+
console.log(chalk6.gray("\nAvailable tools:"));
|
|
9215
9822
|
const tools = await toolConfigManager.listTools();
|
|
9216
9823
|
for (const t of tools) {
|
|
9217
|
-
console.log(` - ${
|
|
9824
|
+
console.log(` - ${chalk6.cyan(t.name)}`);
|
|
9218
9825
|
}
|
|
9219
9826
|
console.log();
|
|
9220
|
-
console.log(
|
|
9827
|
+
console.log(chalk6.gray("Tip: If you meant to show a skill, use: aikit skills show <name>"));
|
|
9221
9828
|
console.log();
|
|
9222
9829
|
process.exit(1);
|
|
9223
9830
|
}
|
|
9224
|
-
console.log(
|
|
9831
|
+
console.log(chalk6.bold(`
|
|
9225
9832
|
\u{1F527} Configuring: ${tool.name}
|
|
9226
9833
|
`));
|
|
9227
|
-
console.log(
|
|
9834
|
+
console.log(chalk6.gray(tool.description));
|
|
9228
9835
|
console.log();
|
|
9229
9836
|
if (tool.configMethod === "oauth") {
|
|
9230
9837
|
if (toolName === "figma-analysis") {
|
|
@@ -9232,12 +9839,12 @@ async function configureToolAction(toolName) {
|
|
|
9232
9839
|
const oauth = new FigmaOAuth2(toolConfigManager);
|
|
9233
9840
|
try {
|
|
9234
9841
|
const token = await oauth.authenticate();
|
|
9235
|
-
console.log(
|
|
9842
|
+
console.log(chalk6.gray("\nValidating token..."));
|
|
9236
9843
|
const isValid = await oauth.validateToken(token);
|
|
9237
9844
|
if (isValid) {
|
|
9238
9845
|
logger.success(`
|
|
9239
9846
|
\u2705 ${tool.name} configured successfully!`);
|
|
9240
|
-
console.log(
|
|
9847
|
+
console.log(chalk6.gray("\nYou can now use the /analyze-figma command in OpenCode.\n"));
|
|
9241
9848
|
} else {
|
|
9242
9849
|
await toolConfigManager.updateToolConfig(toolName, {
|
|
9243
9850
|
status: "error",
|
|
@@ -9268,9 +9875,9 @@ async function configureToolAction(toolName) {
|
|
|
9268
9875
|
|
|
9269
9876
|
// src/cli/commands/misc.ts
|
|
9270
9877
|
init_esm_shims();
|
|
9271
|
-
import
|
|
9272
|
-
import { readFile as
|
|
9273
|
-
import { join as
|
|
9878
|
+
import chalk7 from "chalk";
|
|
9879
|
+
import { readFile as readFile16, writeFile as writeFile19 } from "fs/promises";
|
|
9880
|
+
import { join as join24 } from "path";
|
|
9274
9881
|
init_config();
|
|
9275
9882
|
init_memory();
|
|
9276
9883
|
init_beads();
|
|
@@ -9281,10 +9888,10 @@ function registerAgentsCommand(program2) {
|
|
|
9281
9888
|
const config = await loadConfig();
|
|
9282
9889
|
const manager = new AgentManager(config);
|
|
9283
9890
|
const agents = manager.listAgents();
|
|
9284
|
-
console.log(
|
|
9891
|
+
console.log(chalk7.bold("\n\u{1F916} Available Agents:\n"));
|
|
9285
9892
|
for (const agent of agents) {
|
|
9286
|
-
console.log(` ${
|
|
9287
|
-
console.log(
|
|
9893
|
+
console.log(` ${chalk7.cyan(`@${agent.name}`)} - ${agent.description}`);
|
|
9894
|
+
console.log(chalk7.gray(` Use when: ${agent.useWhen}`));
|
|
9288
9895
|
}
|
|
9289
9896
|
console.log();
|
|
9290
9897
|
});
|
|
@@ -9296,13 +9903,13 @@ function registerCommandsCommand(program2) {
|
|
|
9296
9903
|
const config = await loadConfig();
|
|
9297
9904
|
const runner = new CommandRunner(config);
|
|
9298
9905
|
const commands = await runner.listCommands();
|
|
9299
|
-
console.log(
|
|
9906
|
+
console.log(chalk7.bold("\n\u26A1 Available Commands:\n"));
|
|
9300
9907
|
const groups = groupBy(commands, (c) => c.category);
|
|
9301
9908
|
for (const [category, cmds] of Object.entries(groups)) {
|
|
9302
|
-
console.log(
|
|
9909
|
+
console.log(chalk7.bold.yellow(`
|
|
9303
9910
|
${category}:`));
|
|
9304
9911
|
for (const cmd of cmds) {
|
|
9305
|
-
console.log(` ${
|
|
9912
|
+
console.log(` ${chalk7.cyan(`/${cmd.name}`)} - ${cmd.description}`);
|
|
9306
9913
|
}
|
|
9307
9914
|
}
|
|
9308
9915
|
console.log();
|
|
@@ -9314,15 +9921,15 @@ function registerModeCommand(program2) {
|
|
|
9314
9921
|
modeCmd.command("get").description("Get current AIKit mode").action(async () => {
|
|
9315
9922
|
const config = await loadConfig();
|
|
9316
9923
|
const { mode } = config;
|
|
9317
|
-
console.log(
|
|
9318
|
-
console.log(` ${
|
|
9924
|
+
console.log(chalk7.bold("\n\u{1F4CB} Current Mode:\n"));
|
|
9925
|
+
console.log(` ${chalk7.cyan(mode || "build")}`);
|
|
9319
9926
|
console.log();
|
|
9320
|
-
console.log(
|
|
9321
|
-
console.log(` ${
|
|
9322
|
-
console.log(` ${
|
|
9323
|
-
console.log(` ${
|
|
9927
|
+
console.log(chalk7.bold("Available Modes:\n"));
|
|
9928
|
+
console.log(` ${chalk7.cyan("plan")} - Create detailed implementation plans`);
|
|
9929
|
+
console.log(` ${chalk7.cyan("build")} - Direct execution mode`);
|
|
9930
|
+
console.log(` ${chalk7.cyan("one-shot")} - End-to-end autonomous execution`);
|
|
9324
9931
|
console.log();
|
|
9325
|
-
console.log(
|
|
9932
|
+
console.log(chalk7.gray('Use "aikit mode set <mode>" to change mode.'));
|
|
9326
9933
|
});
|
|
9327
9934
|
modeCmd.command("set <mode>").description("Set AIKit mode (plan, build, one-shot)").action(async (mode) => {
|
|
9328
9935
|
const config = await loadConfig();
|
|
@@ -9330,16 +9937,16 @@ function registerModeCommand(program2) {
|
|
|
9330
9937
|
try {
|
|
9331
9938
|
const validModes = ["plan", "build", "one-shot"];
|
|
9332
9939
|
if (!validModes.includes(mode)) {
|
|
9333
|
-
console.log(
|
|
9940
|
+
console.log(chalk7.red(`Invalid mode. Available modes: ${validModes.join(", ")}`));
|
|
9334
9941
|
return;
|
|
9335
9942
|
}
|
|
9336
|
-
const configData = JSON.parse(await
|
|
9943
|
+
const configData = JSON.parse(await readFile16(join24(configPath, "aikit.json"), "utf-8"));
|
|
9337
9944
|
configData.mode = mode;
|
|
9338
|
-
await
|
|
9339
|
-
console.log(
|
|
9340
|
-
console.log(
|
|
9945
|
+
await writeFile19(join24(configPath, "aikit.json"), JSON.stringify(configData, null, 2));
|
|
9946
|
+
console.log(chalk7.green(`\u2713 Mode set to: ${mode}`));
|
|
9947
|
+
console.log(chalk7.gray(`Configuration updated at: ${configPath}/aikit.json`));
|
|
9341
9948
|
} catch (error) {
|
|
9342
|
-
console.log(
|
|
9949
|
+
console.log(chalk7.red(`Failed to set mode: ${error instanceof Error ? error.message : String(error)}`));
|
|
9343
9950
|
}
|
|
9344
9951
|
});
|
|
9345
9952
|
return modeCmd;
|
|
@@ -9350,9 +9957,9 @@ function registerToolsCommand(program2) {
|
|
|
9350
9957
|
const config = await loadConfig();
|
|
9351
9958
|
const registry = new ToolRegistry(config);
|
|
9352
9959
|
const tools = await registry.listTools();
|
|
9353
|
-
console.log(
|
|
9960
|
+
console.log(chalk7.bold("\n\u{1F527} Available Tools:\n"));
|
|
9354
9961
|
for (const tool of tools) {
|
|
9355
|
-
console.log(` ${
|
|
9962
|
+
console.log(` ${chalk7.cyan(tool.name)} - ${tool.description}`);
|
|
9356
9963
|
}
|
|
9357
9964
|
console.log();
|
|
9358
9965
|
});
|
|
@@ -9364,10 +9971,10 @@ function registerPluginsCommand(program2) {
|
|
|
9364
9971
|
const config = await loadConfig();
|
|
9365
9972
|
const system = new PluginSystem(config);
|
|
9366
9973
|
const plugins = await system.listPlugins();
|
|
9367
|
-
console.log(
|
|
9974
|
+
console.log(chalk7.bold("\n\u{1F50C} Available Plugins:\n"));
|
|
9368
9975
|
for (const plugin of plugins) {
|
|
9369
|
-
const status = plugin.enabled ?
|
|
9370
|
-
console.log(` ${status} ${
|
|
9976
|
+
const status = plugin.enabled ? chalk7.green("\u2713") : chalk7.gray("\u25CB");
|
|
9977
|
+
console.log(` ${status} ${chalk7.cyan(plugin.name)} - ${plugin.description}`);
|
|
9371
9978
|
}
|
|
9372
9979
|
console.log();
|
|
9373
9980
|
});
|
|
@@ -9379,10 +9986,10 @@ function registerMemoryCommand(program2) {
|
|
|
9379
9986
|
const config = await loadConfig();
|
|
9380
9987
|
const memory = new MemoryManager(config);
|
|
9381
9988
|
const entries = await memory.list();
|
|
9382
|
-
console.log(
|
|
9989
|
+
console.log(chalk7.bold("\n\u{1F9E0} Memory Entries:\n"));
|
|
9383
9990
|
for (const entry of entries) {
|
|
9384
|
-
console.log(` ${
|
|
9385
|
-
console.log(
|
|
9991
|
+
console.log(` ${chalk7.cyan(entry.key)} - ${entry.summary}`);
|
|
9992
|
+
console.log(chalk7.gray(` Updated: ${entry.updatedAt}`));
|
|
9386
9993
|
}
|
|
9387
9994
|
console.log();
|
|
9388
9995
|
});
|
|
@@ -9403,7 +10010,7 @@ function registerBeadsCommand(program2) {
|
|
|
9403
10010
|
beadsCmd.command("status").description("Show current Beads status").action(async () => {
|
|
9404
10011
|
const beads = new BeadsIntegration();
|
|
9405
10012
|
const status = await beads.getStatus();
|
|
9406
|
-
console.log(
|
|
10013
|
+
console.log(chalk7.bold("\n\u{1F4FF} Beads Status:\n"));
|
|
9407
10014
|
console.log(` Active tasks: ${status.activeTasks}`);
|
|
9408
10015
|
console.log(` Completed: ${status.completedTasks}`);
|
|
9409
10016
|
console.log(` Current: ${status.currentTask || "None"}`);
|
|
@@ -9413,12 +10020,12 @@ function registerBeadsCommand(program2) {
|
|
|
9413
10020
|
}
|
|
9414
10021
|
function registerStatusCommand(program2) {
|
|
9415
10022
|
program2.command("status").description("Show AIKit status").action(async () => {
|
|
9416
|
-
console.log(
|
|
10023
|
+
console.log(chalk7.bold(`
|
|
9417
10024
|
\u{1F680} AIKit v${getVersion()}
|
|
9418
10025
|
`));
|
|
9419
10026
|
try {
|
|
9420
10027
|
const config = await loadConfig();
|
|
9421
|
-
console.log(
|
|
10028
|
+
console.log(chalk7.green("\u2713 Configuration loaded"));
|
|
9422
10029
|
const skillEngine = new SkillEngine(config);
|
|
9423
10030
|
const skills = await skillEngine.listSkills();
|
|
9424
10031
|
console.log(` Skills: ${skills.length}`);
|
|
@@ -9433,9 +10040,9 @@ function registerStatusCommand(program2) {
|
|
|
9433
10040
|
console.log(` Tools: ${tools.length}`);
|
|
9434
10041
|
const beads = new BeadsIntegration();
|
|
9435
10042
|
const beadsStatus = await beads.isInstalled();
|
|
9436
|
-
console.log(` Beads: ${beadsStatus ?
|
|
10043
|
+
console.log(` Beads: ${beadsStatus ? chalk7.green("Installed") : chalk7.yellow("Not installed")}`);
|
|
9437
10044
|
} catch (error) {
|
|
9438
|
-
console.log(
|
|
10045
|
+
console.log(chalk7.yellow('\u26A0 AIKit not initialized. Run "aikit init" to get started.'));
|
|
9439
10046
|
}
|
|
9440
10047
|
console.log();
|
|
9441
10048
|
});
|
|
@@ -9466,6 +10073,12 @@ function registerSessionCommand(program2) {
|
|
|
9466
10073
|
sessionCmd.command("search <query>").description("Search sessions by keyword").action(async (query) => {
|
|
9467
10074
|
await searchSessions(query);
|
|
9468
10075
|
});
|
|
10076
|
+
sessionCmd.command("resume <sessionId>").description("Resume a past session (set as active)").action(async (sessionId) => {
|
|
10077
|
+
await resumeSession(sessionId);
|
|
10078
|
+
});
|
|
10079
|
+
sessionCmd.command("use <sessionId>").description("Switch to a different session in current terminal").action(async (sessionId) => {
|
|
10080
|
+
await switchSession(sessionId);
|
|
10081
|
+
});
|
|
9469
10082
|
return sessionCmd;
|
|
9470
10083
|
}
|
|
9471
10084
|
|
|
@@ -9486,4 +10099,9 @@ registerBeadsCommand(program);
|
|
|
9486
10099
|
registerSessionCommand(program);
|
|
9487
10100
|
registerStatusCommand(program);
|
|
9488
10101
|
program.parse();
|
|
10102
|
+
checkForUpdatesAsync().catch((err) => {
|
|
10103
|
+
if (process.env.AIKIT_DEBUG) {
|
|
10104
|
+
console.error("Update check failed:", err);
|
|
10105
|
+
}
|
|
10106
|
+
});
|
|
9489
10107
|
//# sourceMappingURL=cli.js.map
|