@skillkit/tui 1.3.1 → 1.5.0
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/README.md +129 -29
- package/dist/index.d.ts +74 -10
- package/dist/index.js +1594 -326
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { render } from "ink";
|
|
3
3
|
|
|
4
4
|
// src/App.tsx
|
|
5
|
-
import { useState as
|
|
6
|
-
import { Box as
|
|
5
|
+
import { useState as useState19 } from "react";
|
|
6
|
+
import { Box as Box17, Text as Text17, useInput as useInput15, useApp, useStdout } from "ink";
|
|
7
7
|
|
|
8
8
|
// src/components/Sidebar.tsx
|
|
9
9
|
import { Box, Text } from "ink";
|
|
@@ -27,7 +27,13 @@ var symbols = {
|
|
|
27
27
|
checkboxOff: chalk.dim("\u2716"),
|
|
28
28
|
check: chalk.white("\u2713"),
|
|
29
29
|
star: "\u2605",
|
|
30
|
-
spinner: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"]
|
|
30
|
+
spinner: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
|
|
31
|
+
arrowUp: "\u2191",
|
|
32
|
+
arrowDown: "\u2193",
|
|
33
|
+
success: "\u2713",
|
|
34
|
+
error: "\u2717",
|
|
35
|
+
warning: "\u26A0",
|
|
36
|
+
info: "\u2139"
|
|
31
37
|
};
|
|
32
38
|
var logo = `
|
|
33
39
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
@@ -41,14 +47,26 @@ var logo = `
|
|
|
41
47
|
// src/components/Sidebar.tsx
|
|
42
48
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
43
49
|
var NAV = [
|
|
44
|
-
|
|
45
|
-
{ id: "
|
|
46
|
-
{ id: "
|
|
47
|
-
{ id: "
|
|
48
|
-
|
|
49
|
-
{ id: "
|
|
50
|
-
{ id: "
|
|
51
|
-
{ id: "
|
|
50
|
+
// Discovery
|
|
51
|
+
{ id: "home", label: "Home", key: "h" },
|
|
52
|
+
{ id: "marketplace", label: "Marketplace", key: "m" },
|
|
53
|
+
{ id: "browse", label: "Browse", key: "b" },
|
|
54
|
+
// Execution
|
|
55
|
+
{ id: "workflow", label: "Workflows", key: "w" },
|
|
56
|
+
{ id: "execute", label: "Execute", key: "x" },
|
|
57
|
+
{ id: "history", label: "History", key: "y" },
|
|
58
|
+
// Collaboration
|
|
59
|
+
{ id: "team", label: "Team", key: "a" },
|
|
60
|
+
{ id: "plugins", label: "Plugins", key: "p" },
|
|
61
|
+
// Tools
|
|
62
|
+
{ id: "recommend", label: "Recommend", key: "r" },
|
|
63
|
+
{ id: "translate", label: "Translate", key: "t" },
|
|
64
|
+
{ id: "context", label: "Context", key: "c" },
|
|
65
|
+
{ id: "memory", label: "Memory", key: "e" },
|
|
66
|
+
// Management
|
|
67
|
+
{ id: "installed", label: "Installed", key: "i" },
|
|
68
|
+
{ id: "sync", label: "Sync", key: "s" },
|
|
69
|
+
{ id: "settings", label: "Config", key: "," }
|
|
52
70
|
];
|
|
53
71
|
function Sidebar({ screen }) {
|
|
54
72
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 14, borderStyle: "single", paddingX: 1, children: [
|
|
@@ -58,12 +76,22 @@ function Sidebar({ screen }) {
|
|
|
58
76
|
item.label
|
|
59
77
|
] }, item.id)),
|
|
60
78
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
61
|
-
NAV.slice(3,
|
|
79
|
+
NAV.slice(3, 6).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
|
|
62
80
|
screen === item.id ? symbols.bullet : " ",
|
|
63
81
|
item.label
|
|
64
82
|
] }, item.id)),
|
|
65
83
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
66
|
-
NAV.slice(
|
|
84
|
+
NAV.slice(6, 8).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
|
|
85
|
+
screen === item.id ? symbols.bullet : " ",
|
|
86
|
+
item.label
|
|
87
|
+
] }, item.id)),
|
|
88
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
89
|
+
NAV.slice(8, 12).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
|
|
90
|
+
screen === item.id ? symbols.bullet : " ",
|
|
91
|
+
item.label
|
|
92
|
+
] }, item.id)),
|
|
93
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
94
|
+
NAV.slice(12).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
|
|
67
95
|
screen === item.id ? symbols.bullet : " ",
|
|
68
96
|
item.label
|
|
69
97
|
] }, item.id)),
|
|
@@ -154,14 +182,16 @@ function Home({ cols = 80, rows = 24 }) {
|
|
|
154
182
|
|
|
155
183
|
// src/screens/Browse.tsx
|
|
156
184
|
import { useState as useState3 } from "react";
|
|
157
|
-
import { existsSync, mkdirSync, cpSync, rmSync } from "fs";
|
|
158
|
-
import { join as
|
|
185
|
+
import { existsSync as existsSync2, mkdirSync, cpSync, rmSync } from "fs";
|
|
186
|
+
import { join as join3 } from "path";
|
|
159
187
|
import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
160
188
|
|
|
161
189
|
// src/hooks/useMarketplace.ts
|
|
162
190
|
import { useState as useState2, useCallback, useEffect as useEffect2 } from "react";
|
|
163
|
-
import { detectProvider } from "@skillkit/core";
|
|
164
|
-
|
|
191
|
+
import { detectProvider, loadConfig, extractFrontmatter } from "@skillkit/core";
|
|
192
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
193
|
+
import { join as join2 } from "path";
|
|
194
|
+
var DEFAULT_REPOS = [
|
|
165
195
|
{ source: "anthropics/skills", name: "Anthropic Official" },
|
|
166
196
|
{ source: "vercel-labs/agent-skills", name: "Vercel Labs" },
|
|
167
197
|
{ source: "expo/skills", name: "Expo / React Native" },
|
|
@@ -193,6 +223,41 @@ var POPULAR_REPOS = [
|
|
|
193
223
|
{ source: "openrouterteam/agent-skills", name: "OpenRouter SDK" },
|
|
194
224
|
{ source: "intellectronica/agent-skills", name: "Context7" }
|
|
195
225
|
];
|
|
226
|
+
function getMarketplaceRepos() {
|
|
227
|
+
try {
|
|
228
|
+
const config = loadConfig();
|
|
229
|
+
if (config.marketplaceSources?.length) {
|
|
230
|
+
const configRepos = config.marketplaceSources.map((source) => ({
|
|
231
|
+
source,
|
|
232
|
+
name: source.split("/").pop() || source
|
|
233
|
+
}));
|
|
234
|
+
const existingSources = new Set(configRepos.map((r) => r.source));
|
|
235
|
+
for (const repo of DEFAULT_REPOS) {
|
|
236
|
+
if (!existingSources.has(repo.source)) {
|
|
237
|
+
configRepos.push(repo);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return configRepos;
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
}
|
|
244
|
+
return DEFAULT_REPOS;
|
|
245
|
+
}
|
|
246
|
+
function readSkillDescription(skillPath) {
|
|
247
|
+
const skillMdPath = join2(skillPath, "SKILL.md");
|
|
248
|
+
if (!existsSync(skillMdPath)) {
|
|
249
|
+
return void 0;
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const content = readFileSync2(skillMdPath, "utf-8");
|
|
253
|
+
const frontmatter = extractFrontmatter(content);
|
|
254
|
+
if (frontmatter && typeof frontmatter.description === "string") {
|
|
255
|
+
return frontmatter.description;
|
|
256
|
+
}
|
|
257
|
+
} catch {
|
|
258
|
+
}
|
|
259
|
+
return void 0;
|
|
260
|
+
}
|
|
196
261
|
function useMarketplace() {
|
|
197
262
|
const [allSkills, setAllSkills] = useState2([]);
|
|
198
263
|
const [filteredSkills, setFilteredSkills] = useState2([]);
|
|
@@ -200,6 +265,8 @@ function useMarketplace() {
|
|
|
200
265
|
const [error, setError] = useState2(null);
|
|
201
266
|
const [currentRepo, setCurrentRepo] = useState2(null);
|
|
202
267
|
const [fetchedRepos, setFetchedRepos] = useState2(/* @__PURE__ */ new Set());
|
|
268
|
+
const [failedRepos, setFailedRepos] = useState2([]);
|
|
269
|
+
const [repos] = useState2(() => getMarketplaceRepos());
|
|
203
270
|
const fetchRepo = useCallback(async (source) => {
|
|
204
271
|
if (fetchedRepos.has(source)) return;
|
|
205
272
|
setLoading(true);
|
|
@@ -214,12 +281,13 @@ function useMarketplace() {
|
|
|
214
281
|
if (!result.success || !result.discoveredSkills) {
|
|
215
282
|
throw new Error(result.error || "Failed to fetch skills");
|
|
216
283
|
}
|
|
217
|
-
const repoName =
|
|
284
|
+
const repoName = repos.find((r) => r.source === source)?.name || source;
|
|
218
285
|
const newSkills = result.discoveredSkills.map((skill) => ({
|
|
219
286
|
name: skill.name,
|
|
220
287
|
source,
|
|
221
288
|
repoName,
|
|
222
|
-
description
|
|
289
|
+
// Try to read description from skill frontmatter
|
|
290
|
+
description: readSkillDescription(skill.path)
|
|
223
291
|
}));
|
|
224
292
|
setAllSkills((prev) => {
|
|
225
293
|
const updated = [...prev, ...newSkills];
|
|
@@ -231,27 +299,37 @@ function useMarketplace() {
|
|
|
231
299
|
rmSync3(result.tempRoot, { recursive: true, force: true });
|
|
232
300
|
}
|
|
233
301
|
} catch (err) {
|
|
234
|
-
|
|
302
|
+
const errorMsg = err instanceof Error ? err.message : "Failed to fetch repository";
|
|
303
|
+
setError(errorMsg);
|
|
304
|
+
setFailedRepos((prev) => prev.includes(source) ? prev : [...prev, source]);
|
|
235
305
|
} finally {
|
|
236
306
|
setLoading(false);
|
|
237
307
|
setCurrentRepo(null);
|
|
238
308
|
}
|
|
239
|
-
}, [fetchedRepos]);
|
|
309
|
+
}, [fetchedRepos, repos]);
|
|
240
310
|
const fetchAllRepos = useCallback(async () => {
|
|
241
311
|
setLoading(true);
|
|
242
312
|
setError(null);
|
|
243
|
-
|
|
313
|
+
const failures = [];
|
|
314
|
+
for (const repo of repos) {
|
|
244
315
|
if (!fetchedRepos.has(repo.source)) {
|
|
245
316
|
setCurrentRepo(repo.source);
|
|
246
317
|
try {
|
|
247
318
|
await fetchRepo(repo.source);
|
|
248
|
-
} catch {
|
|
319
|
+
} catch (err) {
|
|
320
|
+
failures.push(repo.source);
|
|
249
321
|
}
|
|
250
322
|
}
|
|
251
323
|
}
|
|
324
|
+
if (failures.length > 0) {
|
|
325
|
+
setFailedRepos((prev) => {
|
|
326
|
+
const combined = [...prev, ...failures];
|
|
327
|
+
return [...new Set(combined)];
|
|
328
|
+
});
|
|
329
|
+
}
|
|
252
330
|
setLoading(false);
|
|
253
331
|
setCurrentRepo(null);
|
|
254
|
-
}, [fetchRepo, fetchedRepos]);
|
|
332
|
+
}, [fetchRepo, fetchedRepos, repos]);
|
|
255
333
|
const search = useCallback((query) => {
|
|
256
334
|
if (!query.trim()) {
|
|
257
335
|
setFilteredSkills(allSkills);
|
|
@@ -268,6 +346,8 @@ function useMarketplace() {
|
|
|
268
346
|
setFetchedRepos(/* @__PURE__ */ new Set());
|
|
269
347
|
setAllSkills([]);
|
|
270
348
|
setFilteredSkills([]);
|
|
349
|
+
setFailedRepos([]);
|
|
350
|
+
setError(null);
|
|
271
351
|
}, []);
|
|
272
352
|
useEffect2(() => {
|
|
273
353
|
setFilteredSkills(allSkills);
|
|
@@ -282,8 +362,9 @@ function useMarketplace() {
|
|
|
282
362
|
loading,
|
|
283
363
|
error,
|
|
284
364
|
totalCount: allSkills.length,
|
|
285
|
-
repos
|
|
365
|
+
repos,
|
|
286
366
|
currentRepo,
|
|
367
|
+
failedRepos,
|
|
287
368
|
refresh,
|
|
288
369
|
search,
|
|
289
370
|
fetchRepo,
|
|
@@ -297,14 +378,14 @@ import { detectAgent, getAdapter as getAdapter2, getAllAdapters } from "@skillki
|
|
|
297
378
|
|
|
298
379
|
// src/helpers.ts
|
|
299
380
|
import {
|
|
300
|
-
loadConfig,
|
|
381
|
+
loadConfig as loadConfig2,
|
|
301
382
|
getSearchDirs as coreGetSearchDirs,
|
|
302
383
|
getInstallDir as coreGetInstallDir,
|
|
303
384
|
saveSkillMetadata as coreSaveSkillMetadata
|
|
304
385
|
} from "@skillkit/core";
|
|
305
386
|
import { getAdapter } from "@skillkit/agents";
|
|
306
387
|
function getSearchDirs(agentType) {
|
|
307
|
-
const type = agentType ||
|
|
388
|
+
const type = agentType || loadConfig2().agent;
|
|
308
389
|
const adapter = getAdapter(type);
|
|
309
390
|
const adapterInfo = {
|
|
310
391
|
type: adapter.type,
|
|
@@ -315,7 +396,7 @@ function getSearchDirs(agentType) {
|
|
|
315
396
|
return coreGetSearchDirs(adapterInfo);
|
|
316
397
|
}
|
|
317
398
|
function getInstallDir(global = false, agentType) {
|
|
318
|
-
const type = agentType ||
|
|
399
|
+
const type = agentType || loadConfig2().agent;
|
|
319
400
|
const adapter = getAdapter(type);
|
|
320
401
|
const adapterInfo = {
|
|
321
402
|
type: adapter.type,
|
|
@@ -380,11 +461,11 @@ function Browse({ rows = 24 }) {
|
|
|
380
461
|
const targetAgentType = agentType || await detectAgent();
|
|
381
462
|
const adapter = getAdapter2(targetAgentType);
|
|
382
463
|
const installDir = getInstallDir(false, targetAgentType);
|
|
383
|
-
if (!
|
|
464
|
+
if (!existsSync2(installDir)) {
|
|
384
465
|
mkdirSync(installDir, { recursive: true });
|
|
385
466
|
}
|
|
386
|
-
const targetPath =
|
|
387
|
-
if (
|
|
467
|
+
const targetPath = join3(installDir, skillName);
|
|
468
|
+
if (existsSync2(targetPath)) {
|
|
388
469
|
rmSync(targetPath, { recursive: true, force: true });
|
|
389
470
|
}
|
|
390
471
|
cpSync(skill.path, targetPath, { recursive: true, dereference: true });
|
|
@@ -690,206 +771,176 @@ function Sync({ rows = 24 }) {
|
|
|
690
771
|
}
|
|
691
772
|
|
|
692
773
|
// src/screens/Settings.tsx
|
|
693
|
-
import { useState as useState7 } from "react";
|
|
774
|
+
import { useState as useState7, useEffect as useEffect5 } from "react";
|
|
694
775
|
import { Box as Box6, Text as Text6, useInput as useInput4 } from "ink";
|
|
776
|
+
import TextInput from "ink-text-input";
|
|
777
|
+
import { loadConfig as loadConfig3, saveConfig, AgentType as AgentTypeSchema } from "@skillkit/core";
|
|
695
778
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
779
|
+
var ALL_AGENTS = AgentTypeSchema.options;
|
|
696
780
|
var SETTINGS = [
|
|
697
|
-
{ id: "agent", label: "Default Agent",
|
|
698
|
-
{ id: "
|
|
699
|
-
{ id: "
|
|
781
|
+
{ id: "agent", label: "Default Agent", type: "select", options: ["auto-detect", ...ALL_AGENTS] },
|
|
782
|
+
{ id: "autoSync", label: "Auto Sync", type: "toggle" },
|
|
783
|
+
{ id: "cacheDir", label: "Cache Dir", type: "text" }
|
|
700
784
|
];
|
|
701
|
-
function Settings(
|
|
785
|
+
function Settings(_props) {
|
|
786
|
+
const [config, setConfig] = useState7(null);
|
|
702
787
|
const [sel, setSel] = useState7(0);
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
788
|
+
const [editing, setEditing] = useState7(false);
|
|
789
|
+
const [editValue, setEditValue] = useState7("");
|
|
790
|
+
const [saved, setSaved] = useState7(false);
|
|
791
|
+
const [error, setError] = useState7(null);
|
|
792
|
+
useEffect5(() => {
|
|
793
|
+
try {
|
|
794
|
+
const loaded = loadConfig3();
|
|
795
|
+
setConfig(loaded);
|
|
796
|
+
} catch (err) {
|
|
797
|
+
setError(`Failed to load config: ${err}`);
|
|
798
|
+
}
|
|
799
|
+
}, []);
|
|
800
|
+
const getCurrentValue = (setting) => {
|
|
801
|
+
if (!config) return "";
|
|
802
|
+
switch (setting.id) {
|
|
803
|
+
case "agent":
|
|
804
|
+
return config.agent === "universal" ? "auto-detect" : config.agent || "auto-detect";
|
|
805
|
+
case "autoSync":
|
|
806
|
+
return config.autoSync ? "enabled" : "disabled";
|
|
807
|
+
case "cacheDir":
|
|
808
|
+
return config.cacheDir || "~/.skillkit/cache";
|
|
809
|
+
default:
|
|
810
|
+
return "";
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
const handleSave = (setting, value) => {
|
|
814
|
+
if (!config) return;
|
|
815
|
+
const newConfig = { ...config };
|
|
816
|
+
switch (setting.id) {
|
|
817
|
+
case "agent":
|
|
818
|
+
if (value === "auto-detect") {
|
|
819
|
+
newConfig.agent = "universal";
|
|
820
|
+
} else {
|
|
821
|
+
newConfig.agent = value;
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case "autoSync":
|
|
825
|
+
newConfig.autoSync = value === "enabled";
|
|
826
|
+
break;
|
|
827
|
+
case "cacheDir":
|
|
828
|
+
newConfig.cacheDir = value || void 0;
|
|
829
|
+
break;
|
|
830
|
+
}
|
|
831
|
+
try {
|
|
832
|
+
saveConfig(newConfig, false);
|
|
833
|
+
setConfig(newConfig);
|
|
834
|
+
setSaved(true);
|
|
835
|
+
setTimeout(() => setSaved(false), 2e3);
|
|
836
|
+
} catch (err) {
|
|
837
|
+
setError(`Failed to save: ${err}`);
|
|
838
|
+
setTimeout(() => setError(null), 3e3);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
useInput4((input, key) => {
|
|
842
|
+
if (editing) {
|
|
843
|
+
if (key.return) {
|
|
844
|
+
handleSave(SETTINGS[sel], editValue);
|
|
845
|
+
setEditing(false);
|
|
846
|
+
} else if (key.escape) {
|
|
847
|
+
setEditing(false);
|
|
848
|
+
}
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (key.upArrow) {
|
|
852
|
+
setSel((i) => Math.max(0, i - 1));
|
|
853
|
+
} else if (key.downArrow) {
|
|
854
|
+
setSel((i) => Math.min(SETTINGS.length - 1, i + 1));
|
|
855
|
+
} else if (key.return || input === " ") {
|
|
856
|
+
const setting = SETTINGS[sel];
|
|
857
|
+
if (setting.type === "toggle") {
|
|
858
|
+
const current = getCurrentValue(setting);
|
|
859
|
+
const newValue = current === "enabled" ? "disabled" : "enabled";
|
|
860
|
+
handleSave(setting, newValue);
|
|
861
|
+
} else if (setting.type === "select" && setting.options) {
|
|
862
|
+
const current = getCurrentValue(setting);
|
|
863
|
+
const idx = setting.options.indexOf(current);
|
|
864
|
+
const nextIdx = (idx + 1) % setting.options.length;
|
|
865
|
+
handleSave(setting, setting.options[nextIdx]);
|
|
866
|
+
} else if (setting.type === "text") {
|
|
867
|
+
setEditValue(getCurrentValue(setting));
|
|
868
|
+
setEditing(true);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
706
871
|
});
|
|
872
|
+
if (!config) {
|
|
873
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
874
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, color: colors.primary, children: "SETTINGS" }),
|
|
875
|
+
error ? /* @__PURE__ */ jsxs6(Text6, { color: colors.danger, children: [
|
|
876
|
+
symbols.error,
|
|
877
|
+
" ",
|
|
878
|
+
error
|
|
879
|
+
] }) : /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Loading..." })
|
|
880
|
+
] });
|
|
881
|
+
}
|
|
707
882
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
708
883
|
/* @__PURE__ */ jsx6(Text6, { bold: true, color: colors.primary, children: "SETTINGS" }),
|
|
709
|
-
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Configure SkillKit" }),
|
|
884
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Configure SkillKit (changes save automatically)" }),
|
|
710
885
|
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", children: SETTINGS.map((s, i) => {
|
|
711
886
|
const isSel = i === sel;
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
887
|
+
const value = getCurrentValue(s);
|
|
888
|
+
const isEditing = editing && isSel;
|
|
889
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
890
|
+
/* @__PURE__ */ jsxs6(Text6, { inverse: isSel && !isEditing, children: [
|
|
891
|
+
isSel ? symbols.pointer : " ",
|
|
892
|
+
s.label.padEnd(16)
|
|
893
|
+
] }),
|
|
894
|
+
isEditing ? /* @__PURE__ */ jsx6(Box6, { marginLeft: 1, children: /* @__PURE__ */ jsx6(
|
|
895
|
+
TextInput,
|
|
896
|
+
{
|
|
897
|
+
value: editValue,
|
|
898
|
+
onChange: setEditValue,
|
|
899
|
+
onSubmit: () => {
|
|
900
|
+
handleSave(s, editValue);
|
|
901
|
+
setEditing(false);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
) }) : /* @__PURE__ */ jsxs6(Text6, { color: colors.secondaryDim, children: [
|
|
905
|
+
" ",
|
|
906
|
+
value
|
|
907
|
+
] }),
|
|
908
|
+
s.type === "toggle" && isSel && !isEditing && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " (space to toggle)" }),
|
|
909
|
+
s.type === "select" && isSel && !isEditing && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " (enter to cycle)" })
|
|
717
910
|
] }, s.id);
|
|
718
911
|
}) }),
|
|
719
|
-
/* @__PURE__ */
|
|
912
|
+
/* @__PURE__ */ jsxs6(Box6, { marginTop: 1, children: [
|
|
913
|
+
saved && /* @__PURE__ */ jsxs6(Text6, { color: colors.success, children: [
|
|
914
|
+
symbols.check,
|
|
915
|
+
" Settings saved"
|
|
916
|
+
] }),
|
|
917
|
+
error && /* @__PURE__ */ jsxs6(Text6, { color: colors.danger, children: [
|
|
918
|
+
symbols.error,
|
|
919
|
+
" ",
|
|
920
|
+
error
|
|
921
|
+
] }),
|
|
922
|
+
!saved && !error && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: editing ? "Enter=save Esc=cancel" : "Enter/Space=edit q=quit" })
|
|
923
|
+
] })
|
|
720
924
|
] });
|
|
721
925
|
}
|
|
722
926
|
|
|
723
927
|
// src/screens/Recommend.tsx
|
|
724
928
|
import { useState as useState9 } from "react";
|
|
725
|
-
import { existsSync as existsSync3, mkdirSync as
|
|
929
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
|
|
726
930
|
import { join as join4 } from "path";
|
|
727
931
|
import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
|
|
728
932
|
|
|
729
933
|
// src/hooks/useRecommend.ts
|
|
730
|
-
import { useState as useState8, useCallback as useCallback2, useEffect as
|
|
934
|
+
import { useState as useState8, useCallback as useCallback2, useEffect as useEffect6 } from "react";
|
|
731
935
|
import {
|
|
732
936
|
RecommendationEngine,
|
|
733
|
-
ContextManager
|
|
937
|
+
ContextManager,
|
|
938
|
+
loadIndex as loadIndexFromCache,
|
|
939
|
+
saveIndex,
|
|
940
|
+
buildSkillIndex,
|
|
941
|
+
isIndexStale,
|
|
942
|
+
KNOWN_SKILL_REPOS
|
|
734
943
|
} from "@skillkit/core";
|
|
735
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
736
|
-
import { join as join3 } from "path";
|
|
737
|
-
var INDEX_PATH = join3(process.env.HOME || "~", ".skillkit", "index.json");
|
|
738
|
-
var INDEX_CACHE_HOURS = 24;
|
|
739
|
-
function getSampleSkills() {
|
|
740
|
-
return [
|
|
741
|
-
{
|
|
742
|
-
name: "vercel-react-best-practices",
|
|
743
|
-
description: "Modern React patterns including Server Components, hooks best practices, and performance optimization",
|
|
744
|
-
source: "vercel-labs/agent-skills",
|
|
745
|
-
tags: ["react", "frontend", "typescript", "nextjs", "performance"],
|
|
746
|
-
compatibility: {
|
|
747
|
-
frameworks: ["react", "nextjs"],
|
|
748
|
-
languages: ["typescript", "javascript"],
|
|
749
|
-
libraries: []
|
|
750
|
-
},
|
|
751
|
-
popularity: 1500,
|
|
752
|
-
quality: 95,
|
|
753
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
754
|
-
verified: true
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
name: "tailwind-v4-patterns",
|
|
758
|
-
description: "Tailwind CSS v4 utility patterns, responsive design, and component styling best practices",
|
|
759
|
-
source: "vercel-labs/agent-skills",
|
|
760
|
-
tags: ["tailwind", "css", "styling", "frontend", "responsive"],
|
|
761
|
-
compatibility: {
|
|
762
|
-
frameworks: [],
|
|
763
|
-
languages: ["typescript", "javascript"],
|
|
764
|
-
libraries: ["tailwindcss"]
|
|
765
|
-
},
|
|
766
|
-
popularity: 1200,
|
|
767
|
-
quality: 92,
|
|
768
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
769
|
-
verified: true
|
|
770
|
-
},
|
|
771
|
-
{
|
|
772
|
-
name: "nextjs-app-router",
|
|
773
|
-
description: "Next.js App Router patterns including layouts, server actions, and data fetching",
|
|
774
|
-
source: "vercel-labs/agent-skills",
|
|
775
|
-
tags: ["nextjs", "react", "routing", "server-actions", "frontend"],
|
|
776
|
-
compatibility: {
|
|
777
|
-
frameworks: ["nextjs"],
|
|
778
|
-
languages: ["typescript", "javascript"],
|
|
779
|
-
libraries: []
|
|
780
|
-
},
|
|
781
|
-
popularity: 1100,
|
|
782
|
-
quality: 94,
|
|
783
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
784
|
-
verified: true
|
|
785
|
-
},
|
|
786
|
-
{
|
|
787
|
-
name: "typescript-strict-patterns",
|
|
788
|
-
description: "TypeScript strict mode patterns, type safety, and advanced type utilities",
|
|
789
|
-
source: "anthropics/skills",
|
|
790
|
-
tags: ["typescript", "types", "safety", "patterns"],
|
|
791
|
-
compatibility: {
|
|
792
|
-
frameworks: [],
|
|
793
|
-
languages: ["typescript"],
|
|
794
|
-
libraries: []
|
|
795
|
-
},
|
|
796
|
-
popularity: 900,
|
|
797
|
-
quality: 90,
|
|
798
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
799
|
-
verified: true
|
|
800
|
-
},
|
|
801
|
-
{
|
|
802
|
-
name: "supabase-best-practices",
|
|
803
|
-
description: "Supabase integration patterns including auth, database queries, and real-time subscriptions",
|
|
804
|
-
source: "anthropics/skills",
|
|
805
|
-
tags: ["supabase", "database", "auth", "backend", "postgresql"],
|
|
806
|
-
compatibility: {
|
|
807
|
-
frameworks: [],
|
|
808
|
-
languages: ["typescript", "javascript"],
|
|
809
|
-
libraries: ["@supabase/supabase-js"]
|
|
810
|
-
},
|
|
811
|
-
popularity: 800,
|
|
812
|
-
quality: 88,
|
|
813
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
814
|
-
verified: true
|
|
815
|
-
},
|
|
816
|
-
{
|
|
817
|
-
name: "vitest-testing-patterns",
|
|
818
|
-
description: "Testing patterns with Vitest including mocking, assertions, and test organization",
|
|
819
|
-
source: "anthropics/skills",
|
|
820
|
-
tags: ["vitest", "testing", "typescript", "mocking", "tdd"],
|
|
821
|
-
compatibility: {
|
|
822
|
-
frameworks: [],
|
|
823
|
-
languages: ["typescript", "javascript"],
|
|
824
|
-
libraries: ["vitest"]
|
|
825
|
-
},
|
|
826
|
-
popularity: 700,
|
|
827
|
-
quality: 86,
|
|
828
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
829
|
-
verified: false
|
|
830
|
-
},
|
|
831
|
-
{
|
|
832
|
-
name: "prisma-database-patterns",
|
|
833
|
-
description: "Prisma ORM patterns for schema design, migrations, and efficient queries",
|
|
834
|
-
source: "vercel-labs/agent-skills",
|
|
835
|
-
tags: ["prisma", "database", "orm", "postgresql", "backend"],
|
|
836
|
-
compatibility: {
|
|
837
|
-
frameworks: [],
|
|
838
|
-
languages: ["typescript"],
|
|
839
|
-
libraries: ["@prisma/client"]
|
|
840
|
-
},
|
|
841
|
-
popularity: 850,
|
|
842
|
-
quality: 89,
|
|
843
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
844
|
-
verified: true
|
|
845
|
-
},
|
|
846
|
-
{
|
|
847
|
-
name: "security-best-practices",
|
|
848
|
-
description: "Security patterns for web applications including XSS prevention, CSRF, and secure headers",
|
|
849
|
-
source: "trailofbits/skills",
|
|
850
|
-
tags: ["security", "xss", "csrf", "headers", "owasp"],
|
|
851
|
-
compatibility: {
|
|
852
|
-
frameworks: [],
|
|
853
|
-
languages: ["typescript", "javascript", "python"],
|
|
854
|
-
libraries: []
|
|
855
|
-
},
|
|
856
|
-
popularity: 600,
|
|
857
|
-
quality: 95,
|
|
858
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
859
|
-
verified: true
|
|
860
|
-
},
|
|
861
|
-
{
|
|
862
|
-
name: "python-fastapi-patterns",
|
|
863
|
-
description: "FastAPI best practices for building high-performance Python APIs",
|
|
864
|
-
source: "python-skills/fastapi",
|
|
865
|
-
tags: ["python", "fastapi", "backend", "api", "async"],
|
|
866
|
-
compatibility: {
|
|
867
|
-
frameworks: ["fastapi"],
|
|
868
|
-
languages: ["python"],
|
|
869
|
-
libraries: []
|
|
870
|
-
},
|
|
871
|
-
popularity: 550,
|
|
872
|
-
quality: 85,
|
|
873
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
874
|
-
verified: false
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
name: "zustand-state-management",
|
|
878
|
-
description: "Zustand state management patterns for React applications",
|
|
879
|
-
source: "react-skills/state",
|
|
880
|
-
tags: ["zustand", "react", "state-management", "frontend"],
|
|
881
|
-
compatibility: {
|
|
882
|
-
frameworks: ["react"],
|
|
883
|
-
languages: ["typescript", "javascript"],
|
|
884
|
-
libraries: ["zustand"]
|
|
885
|
-
},
|
|
886
|
-
popularity: 650,
|
|
887
|
-
quality: 84,
|
|
888
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
889
|
-
verified: false
|
|
890
|
-
}
|
|
891
|
-
];
|
|
892
|
-
}
|
|
893
944
|
function useRecommend(projectPath = process.cwd()) {
|
|
894
945
|
const [recommendations, setRecommendations] = useState8([]);
|
|
895
946
|
const [searchResults, setSearchResults] = useState8([]);
|
|
@@ -900,25 +951,17 @@ function useRecommend(projectPath = process.cwd()) {
|
|
|
900
951
|
const [indexStatus, setIndexStatus] = useState8("missing");
|
|
901
952
|
const [engine] = useState8(() => new RecommendationEngine());
|
|
902
953
|
const loadIndex = useCallback2(() => {
|
|
903
|
-
|
|
954
|
+
const index = loadIndexFromCache();
|
|
955
|
+
if (!index) {
|
|
904
956
|
setIndexStatus("missing");
|
|
905
957
|
return null;
|
|
906
958
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
const hoursSinceUpdate = (Date.now() - lastUpdated.getTime()) / (1e3 * 60 * 60);
|
|
912
|
-
if (hoursSinceUpdate > INDEX_CACHE_HOURS) {
|
|
913
|
-
setIndexStatus("stale");
|
|
914
|
-
} else {
|
|
915
|
-
setIndexStatus("fresh");
|
|
916
|
-
}
|
|
917
|
-
return index;
|
|
918
|
-
} catch {
|
|
919
|
-
setIndexStatus("missing");
|
|
920
|
-
return null;
|
|
959
|
+
if (isIndexStale(index)) {
|
|
960
|
+
setIndexStatus("stale");
|
|
961
|
+
} else {
|
|
962
|
+
setIndexStatus("fresh");
|
|
921
963
|
}
|
|
964
|
+
return index;
|
|
922
965
|
}, []);
|
|
923
966
|
const getProjectProfile = useCallback2(() => {
|
|
924
967
|
try {
|
|
@@ -978,37 +1021,17 @@ function useRecommend(projectPath = process.cwd()) {
|
|
|
978
1021
|
const updateIndex = useCallback2(() => {
|
|
979
1022
|
setLoading(true);
|
|
980
1023
|
setError(null);
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
985
|
-
skills: getSampleSkills(),
|
|
986
|
-
sources: [
|
|
987
|
-
{
|
|
988
|
-
name: "vercel-labs",
|
|
989
|
-
url: "https://github.com/vercel-labs/agent-skills",
|
|
990
|
-
lastFetched: (/* @__PURE__ */ new Date()).toISOString(),
|
|
991
|
-
skillCount: 5
|
|
992
|
-
},
|
|
993
|
-
{
|
|
994
|
-
name: "anthropics",
|
|
995
|
-
url: "https://github.com/anthropics/skills",
|
|
996
|
-
lastFetched: (/* @__PURE__ */ new Date()).toISOString(),
|
|
997
|
-
skillCount: 3
|
|
998
|
-
}
|
|
999
|
-
]
|
|
1000
|
-
};
|
|
1001
|
-
const indexDir = join3(process.env.HOME || "~", ".skillkit");
|
|
1002
|
-
if (!existsSync2(indexDir)) {
|
|
1003
|
-
mkdirSync2(indexDir, { recursive: true });
|
|
1024
|
+
buildSkillIndex(KNOWN_SKILL_REPOS).then(({ index, errors }) => {
|
|
1025
|
+
if (errors.length > 0) {
|
|
1026
|
+
console.warn("Index update warnings:", errors);
|
|
1004
1027
|
}
|
|
1005
|
-
|
|
1028
|
+
saveIndex(index);
|
|
1006
1029
|
setIndexStatus("fresh");
|
|
1007
1030
|
loadRecommendations();
|
|
1008
|
-
}
|
|
1031
|
+
}).catch((err) => {
|
|
1009
1032
|
setError(err instanceof Error ? err.message : "Failed to update index");
|
|
1010
1033
|
setLoading(false);
|
|
1011
|
-
}
|
|
1034
|
+
});
|
|
1012
1035
|
}, [loadRecommendations]);
|
|
1013
1036
|
const search = useCallback2((query) => {
|
|
1014
1037
|
if (!query.trim()) {
|
|
@@ -1036,7 +1059,7 @@ function useRecommend(projectPath = process.cwd()) {
|
|
|
1036
1059
|
const refresh = useCallback2(() => {
|
|
1037
1060
|
loadRecommendations();
|
|
1038
1061
|
}, [loadRecommendations]);
|
|
1039
|
-
|
|
1062
|
+
useEffect6(() => {
|
|
1040
1063
|
loadRecommendations();
|
|
1041
1064
|
}, [loadRecommendations]);
|
|
1042
1065
|
return {
|
|
@@ -1127,7 +1150,7 @@ function Recommend({ rows = 24 }) {
|
|
|
1127
1150
|
const adapter = getAdapter3(targetAgentType);
|
|
1128
1151
|
const installDir = getInstallDir(false, targetAgentType);
|
|
1129
1152
|
if (!existsSync3(installDir)) {
|
|
1130
|
-
|
|
1153
|
+
mkdirSync2(installDir, { recursive: true });
|
|
1131
1154
|
}
|
|
1132
1155
|
const targetPath = join4(installDir, skillName);
|
|
1133
1156
|
if (existsSync3(targetPath)) {
|
|
@@ -1333,8 +1356,8 @@ function Recommend({ rows = 24 }) {
|
|
|
1333
1356
|
}
|
|
1334
1357
|
|
|
1335
1358
|
// src/screens/Translate.tsx
|
|
1336
|
-
import { useState as useState10, useEffect as
|
|
1337
|
-
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync3, writeFileSync
|
|
1359
|
+
import { useState as useState10, useEffect as useEffect7 } from "react";
|
|
1360
|
+
import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync3, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
1338
1361
|
import { join as join5 } from "path";
|
|
1339
1362
|
import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
|
|
1340
1363
|
import {
|
|
@@ -1353,7 +1376,7 @@ function Translate({ rows = 24 }) {
|
|
|
1353
1376
|
const [preview, setPreview] = useState10("");
|
|
1354
1377
|
const [result, setResult] = useState10(null);
|
|
1355
1378
|
const [loading, setLoading] = useState10(false);
|
|
1356
|
-
|
|
1379
|
+
useEffect7(() => {
|
|
1357
1380
|
const loadSkills = () => {
|
|
1358
1381
|
const installDir = getInstallDir(false);
|
|
1359
1382
|
const foundSkills = [];
|
|
@@ -1376,7 +1399,7 @@ function Translate({ rows = 24 }) {
|
|
|
1376
1399
|
};
|
|
1377
1400
|
loadSkills();
|
|
1378
1401
|
}, []);
|
|
1379
|
-
|
|
1402
|
+
useEffect7(() => {
|
|
1380
1403
|
const adapters = getAllAdapters4();
|
|
1381
1404
|
const supportedAgents = getSupportedTranslationAgents();
|
|
1382
1405
|
const agentList = adapters.filter((a) => supportedAgents.includes(a.type)).map((a) => ({
|
|
@@ -1415,11 +1438,11 @@ function Translate({ rows = 24 }) {
|
|
|
1415
1438
|
const adapter = getAdapter4(selectedAgent.type);
|
|
1416
1439
|
const targetDir = adapter?.skillsDir ? join5(process.cwd(), adapter.skillsDir) : join5(process.cwd(), `.${selectedAgent.type}/skills/`);
|
|
1417
1440
|
if (!existsSync4(targetDir)) {
|
|
1418
|
-
|
|
1441
|
+
mkdirSync3(targetDir, { recursive: true });
|
|
1419
1442
|
}
|
|
1420
1443
|
const filename = translationResult.filename || `${selectedSkill.name}.md`;
|
|
1421
1444
|
const targetPath = join5(targetDir, filename);
|
|
1422
|
-
|
|
1445
|
+
writeFileSync(targetPath, translationResult.content, "utf-8");
|
|
1423
1446
|
setResult({
|
|
1424
1447
|
success: true,
|
|
1425
1448
|
message: `Translated ${selectedSkill.name} to ${selectedAgent.name} format`,
|
|
@@ -1564,7 +1587,7 @@ function Translate({ rows = 24 }) {
|
|
|
1564
1587
|
}
|
|
1565
1588
|
|
|
1566
1589
|
// src/screens/Context.tsx
|
|
1567
|
-
import { useState as useState11, useEffect as
|
|
1590
|
+
import { useState as useState11, useEffect as useEffect8 } from "react";
|
|
1568
1591
|
import { Box as Box9, Text as Text9, useInput as useInput7 } from "ink";
|
|
1569
1592
|
import {
|
|
1570
1593
|
loadContext,
|
|
@@ -1584,7 +1607,7 @@ function Context({ rows = 24 }) {
|
|
|
1584
1607
|
const [message, setMessage] = useState11(null);
|
|
1585
1608
|
const [error, setError] = useState11(null);
|
|
1586
1609
|
const projectPath = process.cwd();
|
|
1587
|
-
|
|
1610
|
+
useEffect8(() => {
|
|
1588
1611
|
const load = async () => {
|
|
1589
1612
|
setLoading(true);
|
|
1590
1613
|
try {
|
|
@@ -1812,16 +1835,1132 @@ function Context({ rows = 24 }) {
|
|
|
1812
1835
|
] });
|
|
1813
1836
|
}
|
|
1814
1837
|
|
|
1815
|
-
// src/
|
|
1838
|
+
// src/screens/Workflow.tsx
|
|
1839
|
+
import { useState as useState12, useEffect as useEffect9 } from "react";
|
|
1840
|
+
import { Box as Box10, Text as Text10, useInput as useInput8 } from "ink";
|
|
1841
|
+
import { listWorkflows } from "@skillkit/core";
|
|
1816
1842
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1843
|
+
function Workflow({ rows = 24 }) {
|
|
1844
|
+
const [workflows, setWorkflows] = useState12([]);
|
|
1845
|
+
const [loading, setLoading] = useState12(true);
|
|
1846
|
+
const [sel, setSel] = useState12(0);
|
|
1847
|
+
const [running, setRunning] = useState12(null);
|
|
1848
|
+
const [error, setError] = useState12(null);
|
|
1849
|
+
const maxVisible = Math.max(5, rows - 8);
|
|
1850
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), workflows.length - maxVisible));
|
|
1851
|
+
const visible = workflows.slice(start, start + maxVisible);
|
|
1852
|
+
useEffect9(() => {
|
|
1853
|
+
loadWorkflows();
|
|
1854
|
+
}, []);
|
|
1855
|
+
const loadWorkflows = () => {
|
|
1856
|
+
setLoading(true);
|
|
1857
|
+
setError(null);
|
|
1858
|
+
try {
|
|
1859
|
+
const wfs = listWorkflows(process.cwd());
|
|
1860
|
+
setWorkflows(wfs);
|
|
1861
|
+
} catch (e) {
|
|
1862
|
+
setError(e instanceof Error ? e.message : "Failed to load workflows");
|
|
1863
|
+
}
|
|
1864
|
+
setLoading(false);
|
|
1865
|
+
};
|
|
1866
|
+
useInput8((input, key) => {
|
|
1867
|
+
if (loading || running) return;
|
|
1868
|
+
if (key.upArrow) setSel((i) => Math.max(0, i - 1));
|
|
1869
|
+
else if (key.downArrow) setSel((i) => Math.min(workflows.length - 1, i + 1));
|
|
1870
|
+
else if (input === "r") loadWorkflows();
|
|
1871
|
+
else if (key.return && workflows[sel]) {
|
|
1872
|
+
setRunning(workflows[sel].name);
|
|
1873
|
+
setTimeout(() => setRunning(null), 2e3);
|
|
1874
|
+
}
|
|
1875
|
+
});
|
|
1876
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
1877
|
+
/* @__PURE__ */ jsx10(Text10, { bold: true, color: colors.primary, children: "WORKFLOWS" }),
|
|
1878
|
+
/* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
1879
|
+
workflows.length,
|
|
1880
|
+
" workflow(s) found"
|
|
1881
|
+
] }),
|
|
1882
|
+
loading && /* @__PURE__ */ jsx10(Text10, { children: "Loading workflows..." }),
|
|
1883
|
+
error && /* @__PURE__ */ jsx10(Text10, { color: "red", children: error }),
|
|
1884
|
+
running && /* @__PURE__ */ jsxs10(Text10, { color: "yellow", children: [
|
|
1885
|
+
"Running: ",
|
|
1886
|
+
running,
|
|
1887
|
+
"..."
|
|
1888
|
+
] }),
|
|
1889
|
+
!loading && !running && workflows.length === 0 && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
1890
|
+
/* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "No workflows found." }),
|
|
1891
|
+
/* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Create one with: skillkit workflow create" })
|
|
1892
|
+
] }),
|
|
1893
|
+
!loading && !running && workflows.length > 0 && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
1894
|
+
start > 0 && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
1895
|
+
" \u2191 ",
|
|
1896
|
+
start,
|
|
1897
|
+
" more"
|
|
1898
|
+
] }),
|
|
1899
|
+
visible.map((wf, i) => {
|
|
1900
|
+
const idx = start + i;
|
|
1901
|
+
const isSel = idx === sel;
|
|
1902
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
1903
|
+
/* @__PURE__ */ jsxs10(Text10, { inverse: isSel, children: [
|
|
1904
|
+
isSel ? symbols.pointer : " ",
|
|
1905
|
+
" ",
|
|
1906
|
+
wf.name
|
|
1907
|
+
] }),
|
|
1908
|
+
isSel && wf.description && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
1909
|
+
" ",
|
|
1910
|
+
wf.description
|
|
1911
|
+
] }),
|
|
1912
|
+
isSel && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
1913
|
+
" ",
|
|
1914
|
+
wf.waves.length,
|
|
1915
|
+
" wave(s), ",
|
|
1916
|
+
wf.waves.reduce((acc, w) => acc + w.skills.length, 0),
|
|
1917
|
+
" skill(s)"
|
|
1918
|
+
] })
|
|
1919
|
+
] }, wf.name);
|
|
1920
|
+
}),
|
|
1921
|
+
start + maxVisible < workflows.length && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
|
|
1922
|
+
" \u2193 ",
|
|
1923
|
+
workflows.length - start - maxVisible,
|
|
1924
|
+
" more"
|
|
1925
|
+
] })
|
|
1926
|
+
] }),
|
|
1927
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Enter=run r=refresh q=quit" }) })
|
|
1928
|
+
] });
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// src/screens/Execute.tsx
|
|
1932
|
+
import { useState as useState13, useEffect as useEffect10 } from "react";
|
|
1933
|
+
import { Box as Box11, Text as Text11, useInput as useInput9 } from "ink";
|
|
1934
|
+
import { createSessionManager } from "@skillkit/core";
|
|
1935
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1936
|
+
function Execute({ rows = 24 }) {
|
|
1937
|
+
const [session, setSession] = useState13(null);
|
|
1938
|
+
const [loading, setLoading] = useState13(true);
|
|
1939
|
+
const maxVisible = Math.max(5, rows - 10);
|
|
1940
|
+
useEffect10(() => {
|
|
1941
|
+
loadSession();
|
|
1942
|
+
const interval = setInterval(loadSession, 1e3);
|
|
1943
|
+
return () => clearInterval(interval);
|
|
1944
|
+
}, []);
|
|
1945
|
+
const loadSession = () => {
|
|
1946
|
+
try {
|
|
1947
|
+
const manager = createSessionManager(process.cwd());
|
|
1948
|
+
const state = manager.get();
|
|
1949
|
+
setSession(state);
|
|
1950
|
+
} catch {
|
|
1951
|
+
setSession(null);
|
|
1952
|
+
}
|
|
1953
|
+
setLoading(false);
|
|
1954
|
+
};
|
|
1955
|
+
useInput9((input, _key) => {
|
|
1956
|
+
if (input === "r") loadSession();
|
|
1957
|
+
else if (input === "p" && session?.currentExecution?.status === "running") {
|
|
1958
|
+
const manager = createSessionManager(process.cwd());
|
|
1959
|
+
manager.pause();
|
|
1960
|
+
loadSession();
|
|
1961
|
+
} else if (input === "c" && session?.currentExecution?.status === "paused") {
|
|
1962
|
+
const manager = createSessionManager(process.cwd());
|
|
1963
|
+
manager.resume();
|
|
1964
|
+
loadSession();
|
|
1965
|
+
}
|
|
1966
|
+
});
|
|
1967
|
+
const renderExecution = (exec) => {
|
|
1968
|
+
const completedTasks = exec.tasks.filter((t) => t.status === "completed").length;
|
|
1969
|
+
const failedTasks = exec.tasks.filter((t) => t.status === "failed").length;
|
|
1970
|
+
const progress = exec.totalSteps > 0 ? Math.round(completedTasks / exec.totalSteps * 100) : 0;
|
|
1971
|
+
const statusColor = exec.status === "running" ? "yellow" : exec.status === "completed" ? "green" : exec.status === "paused" ? "blue" : exec.status === "failed" ? "red" : "white";
|
|
1972
|
+
const visibleTasks = exec.tasks.slice(0, maxVisible);
|
|
1973
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
|
|
1974
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, children: exec.skillName }),
|
|
1975
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
1976
|
+
"Source: ",
|
|
1977
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: exec.skillSource })
|
|
1978
|
+
] }),
|
|
1979
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
1980
|
+
"Status: ",
|
|
1981
|
+
/* @__PURE__ */ jsx11(Text11, { color: statusColor, children: exec.status.toUpperCase() })
|
|
1982
|
+
] }),
|
|
1983
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
1984
|
+
"Progress: ",
|
|
1985
|
+
completedTasks,
|
|
1986
|
+
"/",
|
|
1987
|
+
exec.totalSteps,
|
|
1988
|
+
" (",
|
|
1989
|
+
progress,
|
|
1990
|
+
"%)"
|
|
1991
|
+
] }),
|
|
1992
|
+
/* @__PURE__ */ jsxs11(Box11, { marginY: 1, children: [
|
|
1993
|
+
/* @__PURE__ */ jsx11(Text11, { children: "[" }),
|
|
1994
|
+
/* @__PURE__ */ jsx11(Text11, { color: "green", children: "\u2588".repeat(Math.floor(progress / 5)) }),
|
|
1995
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2591".repeat(20 - Math.floor(progress / 5)) }),
|
|
1996
|
+
/* @__PURE__ */ jsx11(Text11, { children: "]" })
|
|
1997
|
+
] }),
|
|
1998
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, children: "Tasks:" }),
|
|
1999
|
+
visibleTasks.map((task, i) => {
|
|
2000
|
+
const icon = task.status === "completed" ? symbols.success : task.status === "failed" ? symbols.error : task.status === "in_progress" ? symbols.warning : task.status === "paused" ? symbols.info : symbols.bullet;
|
|
2001
|
+
const color = task.status === "completed" ? "green" : task.status === "failed" ? "red" : task.status === "in_progress" ? "yellow" : task.status === "paused" ? "blue" : "white";
|
|
2002
|
+
return /* @__PURE__ */ jsxs11(Text11, { color, children: [
|
|
2003
|
+
icon,
|
|
2004
|
+
" ",
|
|
2005
|
+
task.name,
|
|
2006
|
+
" ",
|
|
2007
|
+
task.error && /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
2008
|
+
"(",
|
|
2009
|
+
task.error,
|
|
2010
|
+
")"
|
|
2011
|
+
] })
|
|
2012
|
+
] }, task.id || i);
|
|
2013
|
+
}),
|
|
2014
|
+
exec.tasks.length > maxVisible && /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
2015
|
+
" ... and ",
|
|
2016
|
+
exec.tasks.length - maxVisible,
|
|
2017
|
+
" more"
|
|
2018
|
+
] }),
|
|
2019
|
+
failedTasks > 0 && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { color: "red", children: [
|
|
2020
|
+
failedTasks,
|
|
2021
|
+
" task(s) failed"
|
|
2022
|
+
] }) })
|
|
2023
|
+
] });
|
|
2024
|
+
};
|
|
2025
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
2026
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: "EXECUTION MONITOR" }),
|
|
2027
|
+
loading && /* @__PURE__ */ jsx11(Text11, { children: "Loading session..." }),
|
|
2028
|
+
!loading && !session?.currentExecution && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
|
|
2029
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "No active execution." }),
|
|
2030
|
+
/* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
2031
|
+
"Run a skill with: skillkit run ",
|
|
2032
|
+
"<skill>"
|
|
2033
|
+
] })
|
|
2034
|
+
] }),
|
|
2035
|
+
!loading && session?.currentExecution && renderExecution(session.currentExecution),
|
|
2036
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
2037
|
+
session?.currentExecution?.status === "running" ? "p=pause " : "",
|
|
2038
|
+
session?.currentExecution?.status === "paused" ? "c=continue " : "",
|
|
2039
|
+
"r=refresh q=quit"
|
|
2040
|
+
] }) })
|
|
2041
|
+
] });
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
// src/screens/History.tsx
|
|
2045
|
+
import { useState as useState14, useEffect as useEffect11 } from "react";
|
|
2046
|
+
import { Box as Box12, Text as Text12, useInput as useInput10 } from "ink";
|
|
2047
|
+
import { createSessionManager as createSessionManager2 } from "@skillkit/core";
|
|
2048
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2049
|
+
function History({ rows = 24 }) {
|
|
2050
|
+
const [history, setHistory] = useState14([]);
|
|
2051
|
+
const [loading, setLoading] = useState14(true);
|
|
2052
|
+
const [sel, setSel] = useState14(0);
|
|
2053
|
+
const [expanded, setExpanded] = useState14(false);
|
|
2054
|
+
const maxVisible = Math.max(5, rows - 8);
|
|
2055
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), history.length - maxVisible));
|
|
2056
|
+
const visible = history.slice(start, start + maxVisible);
|
|
2057
|
+
useEffect11(() => {
|
|
2058
|
+
loadHistory();
|
|
2059
|
+
}, []);
|
|
2060
|
+
const loadHistory = () => {
|
|
2061
|
+
setLoading(true);
|
|
2062
|
+
try {
|
|
2063
|
+
const manager = createSessionManager2(process.cwd());
|
|
2064
|
+
const h = manager.getHistory(50);
|
|
2065
|
+
setHistory(h);
|
|
2066
|
+
} catch {
|
|
2067
|
+
setHistory([]);
|
|
2068
|
+
}
|
|
2069
|
+
setLoading(false);
|
|
2070
|
+
};
|
|
2071
|
+
useInput10((input, key) => {
|
|
2072
|
+
if (loading) return;
|
|
2073
|
+
if (key.upArrow) {
|
|
2074
|
+
setSel((i) => Math.max(0, i - 1));
|
|
2075
|
+
setExpanded(false);
|
|
2076
|
+
} else if (key.downArrow) {
|
|
2077
|
+
setSel((i) => Math.min(history.length - 1, i + 1));
|
|
2078
|
+
setExpanded(false);
|
|
2079
|
+
} else if (input === "r") loadHistory();
|
|
2080
|
+
else if (key.return) setExpanded((e) => !e);
|
|
2081
|
+
});
|
|
2082
|
+
const formatDuration = (ms) => {
|
|
2083
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
2084
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
2085
|
+
return `${(ms / 6e4).toFixed(1)}m`;
|
|
2086
|
+
};
|
|
2087
|
+
const formatDate = (iso) => {
|
|
2088
|
+
const d = new Date(iso);
|
|
2089
|
+
const now = /* @__PURE__ */ new Date();
|
|
2090
|
+
const diff = now.getTime() - d.getTime();
|
|
2091
|
+
if (diff < 6e4) return "Just now";
|
|
2092
|
+
if (diff < 36e5) return `${Math.floor(diff / 6e4)}m ago`;
|
|
2093
|
+
if (diff < 864e5) return `${Math.floor(diff / 36e5)}h ago`;
|
|
2094
|
+
return d.toLocaleDateString();
|
|
2095
|
+
};
|
|
2096
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
2097
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, color: colors.primary, children: "EXECUTION HISTORY" }),
|
|
2098
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2099
|
+
history.length,
|
|
2100
|
+
" execution(s)"
|
|
2101
|
+
] }),
|
|
2102
|
+
loading && /* @__PURE__ */ jsx12(Text12, { children: "Loading history..." }),
|
|
2103
|
+
!loading && history.length === 0 && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
2104
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "No execution history." }),
|
|
2105
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2106
|
+
"Run a skill with: skillkit run ",
|
|
2107
|
+
"<skill>"
|
|
2108
|
+
] })
|
|
2109
|
+
] }),
|
|
2110
|
+
!loading && history.length > 0 && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
2111
|
+
start > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2112
|
+
" \u2191 ",
|
|
2113
|
+
start,
|
|
2114
|
+
" more"
|
|
2115
|
+
] }),
|
|
2116
|
+
visible.map((entry, i) => {
|
|
2117
|
+
const idx = start + i;
|
|
2118
|
+
const isSel = idx === sel;
|
|
2119
|
+
const icon = entry.status === "completed" ? symbols.success : entry.status === "failed" ? symbols.error : symbols.warning;
|
|
2120
|
+
const color = entry.status === "completed" ? "green" : entry.status === "failed" ? "red" : "yellow";
|
|
2121
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
2122
|
+
/* @__PURE__ */ jsxs12(Text12, { inverse: isSel, children: [
|
|
2123
|
+
isSel ? symbols.pointer : " ",
|
|
2124
|
+
/* @__PURE__ */ jsx12(Text12, { color, children: icon }),
|
|
2125
|
+
" ",
|
|
2126
|
+
entry.skillName.padEnd(25),
|
|
2127
|
+
" ",
|
|
2128
|
+
formatDate(entry.completedAt).padEnd(12),
|
|
2129
|
+
" ",
|
|
2130
|
+
formatDuration(entry.durationMs)
|
|
2131
|
+
] }),
|
|
2132
|
+
isSel && expanded && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginLeft: 3, children: [
|
|
2133
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2134
|
+
"Source: ",
|
|
2135
|
+
entry.skillSource
|
|
2136
|
+
] }),
|
|
2137
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2138
|
+
"Status: ",
|
|
2139
|
+
entry.status
|
|
2140
|
+
] }),
|
|
2141
|
+
entry.commits.length > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2142
|
+
"Commits: ",
|
|
2143
|
+
entry.commits.join(", ")
|
|
2144
|
+
] }),
|
|
2145
|
+
entry.filesModified.length > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2146
|
+
"Files: ",
|
|
2147
|
+
entry.filesModified.length,
|
|
2148
|
+
" modified"
|
|
2149
|
+
] }),
|
|
2150
|
+
entry.error && /* @__PURE__ */ jsxs12(Text12, { color: "red", children: [
|
|
2151
|
+
"Error: ",
|
|
2152
|
+
entry.error
|
|
2153
|
+
] })
|
|
2154
|
+
] })
|
|
2155
|
+
] }, idx);
|
|
2156
|
+
}),
|
|
2157
|
+
start + maxVisible < history.length && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
2158
|
+
" \u2193 ",
|
|
2159
|
+
history.length - start - maxVisible,
|
|
2160
|
+
" more"
|
|
2161
|
+
] })
|
|
2162
|
+
] }),
|
|
2163
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Enter=expand r=refresh q=quit" }) })
|
|
2164
|
+
] });
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
// src/screens/Marketplace.tsx
|
|
2168
|
+
import { useState as useState15, useEffect as useEffect12 } from "react";
|
|
2169
|
+
import { Box as Box13, Text as Text13, useInput as useInput11 } from "ink";
|
|
2170
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2171
|
+
var SKILL_SOURCES = [
|
|
2172
|
+
{ owner: "composioHQ", repo: "awesome-claude-code-skills", name: "Composio Curated" },
|
|
2173
|
+
{ owner: "anthropics", repo: "courses", name: "Anthropic Official" }
|
|
2174
|
+
];
|
|
2175
|
+
function Marketplace({ rows = 24 }) {
|
|
2176
|
+
const [skills, setSkills] = useState15([]);
|
|
2177
|
+
const [loading, setLoading] = useState15(true);
|
|
2178
|
+
const [error, setError] = useState15(null);
|
|
2179
|
+
const [sel, setSel] = useState15(0);
|
|
2180
|
+
const [search, setSearch] = useState15("");
|
|
2181
|
+
const [installing, setInstalling] = useState15(null);
|
|
2182
|
+
const filtered = skills.filter(
|
|
2183
|
+
(s) => s.name.toLowerCase().includes(search.toLowerCase()) || s.description.toLowerCase().includes(search.toLowerCase()) || s.tags?.some((t) => t.toLowerCase().includes(search.toLowerCase()))
|
|
2184
|
+
);
|
|
2185
|
+
const maxVisible = Math.max(5, rows - 10);
|
|
2186
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), filtered.length - maxVisible));
|
|
2187
|
+
const visible = filtered.slice(start, start + maxVisible);
|
|
2188
|
+
useEffect12(() => {
|
|
2189
|
+
loadMarketplace();
|
|
2190
|
+
}, []);
|
|
2191
|
+
const loadMarketplace = async () => {
|
|
2192
|
+
setLoading(true);
|
|
2193
|
+
setError(null);
|
|
2194
|
+
try {
|
|
2195
|
+
const allSkills = [];
|
|
2196
|
+
for (const source of SKILL_SOURCES) {
|
|
2197
|
+
try {
|
|
2198
|
+
const indexUrl = `https://raw.githubusercontent.com/${source.owner}/${source.repo}/main/skills.json`;
|
|
2199
|
+
const response = await fetch(indexUrl);
|
|
2200
|
+
if (response.ok) {
|
|
2201
|
+
const data = await response.json();
|
|
2202
|
+
if (Array.isArray(data)) {
|
|
2203
|
+
allSkills.push(...data.map((s) => ({
|
|
2204
|
+
name: String(s.name || "Unknown"),
|
|
2205
|
+
description: String(s.description || ""),
|
|
2206
|
+
source: source.name,
|
|
2207
|
+
repo: `${source.owner}/${source.repo}`,
|
|
2208
|
+
tags: Array.isArray(s.tags) ? s.tags : [],
|
|
2209
|
+
stars: typeof s.stars === "number" ? s.stars : void 0
|
|
2210
|
+
})));
|
|
2211
|
+
}
|
|
2212
|
+
} else {
|
|
2213
|
+
allSkills.push({
|
|
2214
|
+
name: source.repo,
|
|
2215
|
+
description: `Skills from ${source.name}`,
|
|
2216
|
+
source: source.name,
|
|
2217
|
+
repo: `${source.owner}/${source.repo}`
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
} catch {
|
|
2221
|
+
allSkills.push({
|
|
2222
|
+
name: source.repo,
|
|
2223
|
+
description: `Skills from ${source.name}`,
|
|
2224
|
+
source: source.name,
|
|
2225
|
+
repo: `${source.owner}/${source.repo}`
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
if (allSkills.length === 0) {
|
|
2230
|
+
allSkills.push(
|
|
2231
|
+
{ name: "typescript-strict", description: "Enable strict TypeScript mode", source: "Built-in", repo: "skillkit/skills", tags: ["typescript", "config"] },
|
|
2232
|
+
{ name: "eslint-setup", description: "Set up ESLint with recommended rules", source: "Built-in", repo: "skillkit/skills", tags: ["eslint", "linting"] },
|
|
2233
|
+
{ name: "prettier-config", description: "Configure Prettier formatting", source: "Built-in", repo: "skillkit/skills", tags: ["prettier", "formatting"] },
|
|
2234
|
+
{ name: "jest-setup", description: "Set up Jest testing framework", source: "Built-in", repo: "skillkit/skills", tags: ["jest", "testing"] },
|
|
2235
|
+
{ name: "nextjs-auth", description: "Add authentication to Next.js", source: "Community", repo: "community/skills", tags: ["nextjs", "auth"] }
|
|
2236
|
+
);
|
|
2237
|
+
}
|
|
2238
|
+
setSkills(allSkills);
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
setError(e instanceof Error ? e.message : "Failed to load marketplace");
|
|
2241
|
+
}
|
|
2242
|
+
setLoading(false);
|
|
2243
|
+
};
|
|
2244
|
+
useInput11((input, key) => {
|
|
2245
|
+
if (loading || installing) return;
|
|
2246
|
+
if (key.upArrow) setSel((i) => Math.max(0, i - 1));
|
|
2247
|
+
else if (key.downArrow) setSel((i) => Math.min(filtered.length - 1, i + 1));
|
|
2248
|
+
else if (input === "r") loadMarketplace();
|
|
2249
|
+
else if (input === "/") setSearch("");
|
|
2250
|
+
else if (key.backspace || key.delete) setSearch((s) => s.slice(0, -1));
|
|
2251
|
+
else if (key.return && filtered[sel]) {
|
|
2252
|
+
setInstalling(filtered[sel].name);
|
|
2253
|
+
setTimeout(() => setInstalling(null), 1500);
|
|
2254
|
+
} else if (input.length === 1 && /[a-zA-Z0-9-_]/.test(input)) {
|
|
2255
|
+
setSearch((s) => s + input);
|
|
2256
|
+
setSel(0);
|
|
2257
|
+
}
|
|
2258
|
+
});
|
|
2259
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
2260
|
+
/* @__PURE__ */ jsx13(Text13, { bold: true, color: colors.primary, children: "SKILL MARKETPLACE" }),
|
|
2261
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2262
|
+
skills.length,
|
|
2263
|
+
" skills from ",
|
|
2264
|
+
SKILL_SOURCES.length,
|
|
2265
|
+
" sources"
|
|
2266
|
+
] }),
|
|
2267
|
+
search && /* @__PURE__ */ jsxs13(Text13, { children: [
|
|
2268
|
+
"Search: ",
|
|
2269
|
+
/* @__PURE__ */ jsx13(Text13, { color: "yellow", children: search }),
|
|
2270
|
+
" (",
|
|
2271
|
+
filtered.length,
|
|
2272
|
+
" results)"
|
|
2273
|
+
] }),
|
|
2274
|
+
loading && /* @__PURE__ */ jsx13(Text13, { children: "Loading marketplace..." }),
|
|
2275
|
+
error && /* @__PURE__ */ jsx13(Text13, { color: "red", children: error }),
|
|
2276
|
+
installing && /* @__PURE__ */ jsxs13(Text13, { color: "yellow", children: [
|
|
2277
|
+
"Installing ",
|
|
2278
|
+
installing,
|
|
2279
|
+
"..."
|
|
2280
|
+
] }),
|
|
2281
|
+
!loading && !installing && filtered.length === 0 && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2282
|
+
"No skills found",
|
|
2283
|
+
search ? ` matching "${search}"` : "",
|
|
2284
|
+
"."
|
|
2285
|
+
] }) }),
|
|
2286
|
+
!loading && !installing && filtered.length > 0 && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
2287
|
+
start > 0 && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2288
|
+
" \u2191 ",
|
|
2289
|
+
start,
|
|
2290
|
+
" more"
|
|
2291
|
+
] }),
|
|
2292
|
+
visible.map((skill, i) => {
|
|
2293
|
+
const idx = start + i;
|
|
2294
|
+
const isSel = idx === sel;
|
|
2295
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
2296
|
+
/* @__PURE__ */ jsxs13(Text13, { inverse: isSel, children: [
|
|
2297
|
+
isSel ? symbols.pointer : " ",
|
|
2298
|
+
" ",
|
|
2299
|
+
skill.name.padEnd(25),
|
|
2300
|
+
" ",
|
|
2301
|
+
/* @__PURE__ */ jsx13(Text13, { dimColor: true, children: skill.source })
|
|
2302
|
+
] }),
|
|
2303
|
+
isSel && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginLeft: 3, children: [
|
|
2304
|
+
/* @__PURE__ */ jsx13(Text13, { dimColor: true, children: skill.description }),
|
|
2305
|
+
skill.tags && skill.tags.length > 0 && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2306
|
+
"Tags: ",
|
|
2307
|
+
skill.tags.join(", ")
|
|
2308
|
+
] }),
|
|
2309
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2310
|
+
"Repo: ",
|
|
2311
|
+
skill.repo
|
|
2312
|
+
] })
|
|
2313
|
+
] })
|
|
2314
|
+
] }, `${skill.repo}/${skill.name}`);
|
|
2315
|
+
}),
|
|
2316
|
+
start + maxVisible < filtered.length && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
2317
|
+
" \u2193 ",
|
|
2318
|
+
filtered.length - start - maxVisible,
|
|
2319
|
+
" more"
|
|
2320
|
+
] })
|
|
2321
|
+
] }),
|
|
2322
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Enter=install type=search r=refresh q=quit" }) })
|
|
2323
|
+
] });
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// src/screens/Memory.tsx
|
|
2327
|
+
import { useState as useState16, useEffect as useEffect13 } from "react";
|
|
2328
|
+
import { Box as Box14, Text as Text14, useInput as useInput12 } from "ink";
|
|
2329
|
+
import {
|
|
2330
|
+
ObservationStore,
|
|
2331
|
+
LearningStore,
|
|
2332
|
+
getMemoryStatus,
|
|
2333
|
+
getMemoryPaths,
|
|
2334
|
+
createMemoryInjector
|
|
2335
|
+
} from "@skillkit/core";
|
|
2336
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2337
|
+
function Memory({ rows = 24 }) {
|
|
2338
|
+
const [tab, setTab] = useState16("learnings");
|
|
2339
|
+
const [learnings, setLearnings] = useState16([]);
|
|
2340
|
+
const [observationCount, setObservationCount] = useState16(0);
|
|
2341
|
+
const [globalCount, setGlobalCount] = useState16(0);
|
|
2342
|
+
const [loading, setLoading] = useState16(true);
|
|
2343
|
+
const [sel, setSel] = useState16(0);
|
|
2344
|
+
const [expanded, setExpanded] = useState16(false);
|
|
2345
|
+
const [searchQuery, setSearchQuery] = useState16("");
|
|
2346
|
+
const [searchResults, setSearchResults] = useState16([]);
|
|
2347
|
+
const [isGlobal, setIsGlobal] = useState16(false);
|
|
2348
|
+
const maxVisible = Math.max(5, rows - 10);
|
|
2349
|
+
const currentList = tab === "search" ? searchResults : learnings;
|
|
2350
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), currentList.length - maxVisible));
|
|
2351
|
+
const visible = currentList.slice(start, start + maxVisible);
|
|
2352
|
+
useEffect13(() => {
|
|
2353
|
+
loadMemory();
|
|
2354
|
+
}, [isGlobal]);
|
|
2355
|
+
const loadMemory = () => {
|
|
2356
|
+
setLoading(true);
|
|
2357
|
+
try {
|
|
2358
|
+
const projectPath = process.cwd();
|
|
2359
|
+
const status = getMemoryStatus(projectPath);
|
|
2360
|
+
const store = new LearningStore(
|
|
2361
|
+
isGlobal ? "global" : "project",
|
|
2362
|
+
isGlobal ? void 0 : projectPath
|
|
2363
|
+
);
|
|
2364
|
+
setLearnings(store.getAll());
|
|
2365
|
+
if (status.hasObservations) {
|
|
2366
|
+
const obsStore = new ObservationStore(projectPath);
|
|
2367
|
+
setObservationCount(obsStore.count());
|
|
2368
|
+
} else {
|
|
2369
|
+
setObservationCount(0);
|
|
2370
|
+
}
|
|
2371
|
+
if (status.hasGlobalLearnings) {
|
|
2372
|
+
const globalStore = new LearningStore("global");
|
|
2373
|
+
setGlobalCount(globalStore.count());
|
|
2374
|
+
} else {
|
|
2375
|
+
setGlobalCount(0);
|
|
2376
|
+
}
|
|
2377
|
+
} catch {
|
|
2378
|
+
setLearnings([]);
|
|
2379
|
+
setObservationCount(0);
|
|
2380
|
+
setGlobalCount(0);
|
|
2381
|
+
}
|
|
2382
|
+
setLoading(false);
|
|
2383
|
+
};
|
|
2384
|
+
const handleSearch = (query) => {
|
|
2385
|
+
if (!query.trim()) {
|
|
2386
|
+
setSearchResults([]);
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2389
|
+
try {
|
|
2390
|
+
const projectPath = process.cwd();
|
|
2391
|
+
const injector = createMemoryInjector(projectPath);
|
|
2392
|
+
const results = injector.search(query, {
|
|
2393
|
+
includeGlobal: true,
|
|
2394
|
+
maxLearnings: 20,
|
|
2395
|
+
minRelevance: 0
|
|
2396
|
+
});
|
|
2397
|
+
setSearchResults(results.map((r) => r.learning));
|
|
2398
|
+
} catch {
|
|
2399
|
+
setSearchResults([]);
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
useInput12((input, key) => {
|
|
2403
|
+
if (loading) return;
|
|
2404
|
+
if (input === "1") {
|
|
2405
|
+
setTab("learnings");
|
|
2406
|
+
setSel(0);
|
|
2407
|
+
setExpanded(false);
|
|
2408
|
+
} else if (input === "2") {
|
|
2409
|
+
setTab("observations");
|
|
2410
|
+
setSel(0);
|
|
2411
|
+
setExpanded(false);
|
|
2412
|
+
} else if (input === "3") {
|
|
2413
|
+
setTab("search");
|
|
2414
|
+
setSel(0);
|
|
2415
|
+
setExpanded(false);
|
|
2416
|
+
} else if (key.upArrow) {
|
|
2417
|
+
setSel((i) => Math.max(0, i - 1));
|
|
2418
|
+
setExpanded(false);
|
|
2419
|
+
} else if (key.downArrow) {
|
|
2420
|
+
setSel((i) => Math.min(currentList.length - 1, i + 1));
|
|
2421
|
+
setExpanded(false);
|
|
2422
|
+
} else if (input === "f") loadMemory();
|
|
2423
|
+
else if (input === "g") setIsGlobal((g) => !g);
|
|
2424
|
+
else if (key.return) setExpanded((e) => !e);
|
|
2425
|
+
else if (tab === "search" && input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
2426
|
+
const newQuery = searchQuery + input;
|
|
2427
|
+
setSearchQuery(newQuery);
|
|
2428
|
+
handleSearch(newQuery);
|
|
2429
|
+
} else if (tab === "search" && key.backspace) {
|
|
2430
|
+
const newQuery = searchQuery.slice(0, -1);
|
|
2431
|
+
setSearchQuery(newQuery);
|
|
2432
|
+
handleSearch(newQuery);
|
|
2433
|
+
}
|
|
2434
|
+
});
|
|
2435
|
+
const ONE_MINUTE = 6e4;
|
|
2436
|
+
const ONE_HOUR = 36e5;
|
|
2437
|
+
const ONE_DAY = 864e5;
|
|
2438
|
+
function formatDate(iso) {
|
|
2439
|
+
const d = new Date(iso);
|
|
2440
|
+
const diff = Date.now() - d.getTime();
|
|
2441
|
+
if (diff < ONE_MINUTE) return "Just now";
|
|
2442
|
+
if (diff < ONE_HOUR) return `${Math.floor(diff / ONE_MINUTE)}m ago`;
|
|
2443
|
+
if (diff < ONE_DAY) return `${Math.floor(diff / ONE_HOUR)}h ago`;
|
|
2444
|
+
return d.toLocaleDateString();
|
|
2445
|
+
}
|
|
2446
|
+
function formatEffectiveness(eff) {
|
|
2447
|
+
if (eff === void 0) return " -";
|
|
2448
|
+
return eff.toString().padStart(3) + "%";
|
|
2449
|
+
}
|
|
2450
|
+
function getEffectivenessColor(eff) {
|
|
2451
|
+
if (eff === void 0) return void 0;
|
|
2452
|
+
if (eff >= 70) return "green";
|
|
2453
|
+
if (eff >= 40) return "yellow";
|
|
2454
|
+
return "red";
|
|
2455
|
+
}
|
|
2456
|
+
const renderLearnings = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
2457
|
+
currentList.length === 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
|
|
2458
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "No learnings found." }),
|
|
2459
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Run skills to capture learnings, or add manually:" }),
|
|
2460
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ' skillkit memory add --title "..." --content "..."' })
|
|
2461
|
+
] }),
|
|
2462
|
+
currentList.length > 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
|
|
2463
|
+
start > 0 && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2464
|
+
" ",
|
|
2465
|
+
symbols.arrowUp,
|
|
2466
|
+
" ",
|
|
2467
|
+
start,
|
|
2468
|
+
" more"
|
|
2469
|
+
] }),
|
|
2470
|
+
visible.map((learning, i) => {
|
|
2471
|
+
const idx = start + i;
|
|
2472
|
+
const isSel = idx === sel;
|
|
2473
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
2474
|
+
/* @__PURE__ */ jsxs14(Text14, { inverse: isSel, children: [
|
|
2475
|
+
isSel ? symbols.pointer : " ",
|
|
2476
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: symbols.bullet }),
|
|
2477
|
+
" ",
|
|
2478
|
+
learning.title.slice(0, 35).padEnd(35),
|
|
2479
|
+
" ",
|
|
2480
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: learning.tags.slice(0, 2).join(", ").slice(0, 15).padEnd(15) }),
|
|
2481
|
+
" ",
|
|
2482
|
+
/* @__PURE__ */ jsx14(Text14, { color: getEffectivenessColor(learning.effectiveness), children: formatEffectiveness(learning.effectiveness) }),
|
|
2483
|
+
" ",
|
|
2484
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: formatDate(learning.updatedAt) })
|
|
2485
|
+
] }),
|
|
2486
|
+
isSel && expanded && /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginLeft: 3, marginY: 1, children: [
|
|
2487
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2488
|
+
"ID: ",
|
|
2489
|
+
learning.id.slice(0, 8)
|
|
2490
|
+
] }),
|
|
2491
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2492
|
+
"Scope: ",
|
|
2493
|
+
learning.scope
|
|
2494
|
+
] }),
|
|
2495
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2496
|
+
"Source: ",
|
|
2497
|
+
learning.source
|
|
2498
|
+
] }),
|
|
2499
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2500
|
+
"Tags: ",
|
|
2501
|
+
learning.tags.join(", ")
|
|
2502
|
+
] }),
|
|
2503
|
+
learning.frameworks && learning.frameworks.length > 0 && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2504
|
+
"Frameworks: ",
|
|
2505
|
+
learning.frameworks.join(", ")
|
|
2506
|
+
] }),
|
|
2507
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2508
|
+
"Uses: ",
|
|
2509
|
+
learning.useCount
|
|
2510
|
+
] }),
|
|
2511
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { wrap: "wrap", children: [
|
|
2512
|
+
learning.content.slice(0, 300),
|
|
2513
|
+
learning.content.length > 300 ? "..." : ""
|
|
2514
|
+
] }) })
|
|
2515
|
+
] })
|
|
2516
|
+
] }, learning.id);
|
|
2517
|
+
}),
|
|
2518
|
+
start + maxVisible < currentList.length && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2519
|
+
" ",
|
|
2520
|
+
symbols.arrowDown,
|
|
2521
|
+
" ",
|
|
2522
|
+
currentList.length - start - maxVisible,
|
|
2523
|
+
" more"
|
|
2524
|
+
] })
|
|
2525
|
+
] })
|
|
2526
|
+
] });
|
|
2527
|
+
const renderObservations = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
|
|
2528
|
+
/* @__PURE__ */ jsxs14(Text14, { children: [
|
|
2529
|
+
"Session Observations: ",
|
|
2530
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: colors.primary, children: observationCount })
|
|
2531
|
+
] }),
|
|
2532
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Observations are raw captures from skill execution." }),
|
|
2533
|
+
observationCount > 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
|
|
2534
|
+
/* @__PURE__ */ jsx14(Text14, { children: "Compress observations into learnings:" }),
|
|
2535
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " skillkit memory compress" })
|
|
2536
|
+
] }),
|
|
2537
|
+
observationCount >= 50 && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { color: "yellow", children: [
|
|
2538
|
+
symbols.warning,
|
|
2539
|
+
" You have many uncompressed observations."
|
|
2540
|
+
] }) }),
|
|
2541
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Observations are stored at:" }) }),
|
|
2542
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2543
|
+
" ",
|
|
2544
|
+
getMemoryPaths(process.cwd()).observationsFile
|
|
2545
|
+
] })
|
|
2546
|
+
] });
|
|
2547
|
+
const renderSearch = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
|
|
2548
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
2549
|
+
/* @__PURE__ */ jsx14(Text14, { children: "Search: " }),
|
|
2550
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: searchQuery }),
|
|
2551
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.secondary, children: "_" })
|
|
2552
|
+
] }),
|
|
2553
|
+
searchQuery && searchResults.length === 0 && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2554
|
+
'No results found for "',
|
|
2555
|
+
searchQuery,
|
|
2556
|
+
'"'
|
|
2557
|
+
] }) }),
|
|
2558
|
+
searchResults.length > 0 && renderLearnings()
|
|
2559
|
+
] });
|
|
2560
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
2561
|
+
/* @__PURE__ */ jsx14(Text14, { bold: true, color: colors.primary, children: "MEMORY" }),
|
|
2562
|
+
/* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
2563
|
+
isGlobal ? "Global" : "Project",
|
|
2564
|
+
": ",
|
|
2565
|
+
learnings.length,
|
|
2566
|
+
" learning(s)",
|
|
2567
|
+
!isGlobal && globalCount > 0 && /* @__PURE__ */ jsxs14(Text14, { children: [
|
|
2568
|
+
" | Global: ",
|
|
2569
|
+
globalCount
|
|
2570
|
+
] })
|
|
2571
|
+
] }),
|
|
2572
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
2573
|
+
/* @__PURE__ */ jsx14(Text14, { inverse: tab === "learnings", children: "[1] Learnings" }),
|
|
2574
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " }),
|
|
2575
|
+
/* @__PURE__ */ jsx14(Text14, { inverse: tab === "observations", children: "[2] Observations" }),
|
|
2576
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " }),
|
|
2577
|
+
/* @__PURE__ */ jsx14(Text14, { inverse: tab === "search", children: "[3] Search" })
|
|
2578
|
+
] }),
|
|
2579
|
+
loading && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { children: "Loading..." }) }),
|
|
2580
|
+
!loading && tab === "learnings" && renderLearnings(),
|
|
2581
|
+
!loading && tab === "observations" && renderObservations(),
|
|
2582
|
+
!loading && tab === "search" && renderSearch(),
|
|
2583
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Enter=expand g=toggle global f=refresh 1-3=tabs" }) })
|
|
2584
|
+
] });
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
// src/screens/Team.tsx
|
|
2588
|
+
import { useState as useState17, useEffect as useEffect14 } from "react";
|
|
2589
|
+
import { Box as Box15, Text as Text15, useInput as useInput13 } from "ink";
|
|
2590
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2591
|
+
function Team({ rows = 24 }) {
|
|
2592
|
+
const [config, setConfig] = useState17(null);
|
|
2593
|
+
const [skills, setSkills] = useState17([]);
|
|
2594
|
+
const [loading, setLoading] = useState17(true);
|
|
2595
|
+
const [error, setError] = useState17(null);
|
|
2596
|
+
const [sel, setSel] = useState17(0);
|
|
2597
|
+
const [message, setMessage] = useState17(null);
|
|
2598
|
+
const maxVisible = Math.max(5, rows - 12);
|
|
2599
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), skills.length - maxVisible));
|
|
2600
|
+
const visible = skills.slice(start, start + maxVisible);
|
|
2601
|
+
useEffect14(() => {
|
|
2602
|
+
loadTeam();
|
|
2603
|
+
}, []);
|
|
2604
|
+
const loadTeam = async () => {
|
|
2605
|
+
setLoading(true);
|
|
2606
|
+
setError(null);
|
|
2607
|
+
try {
|
|
2608
|
+
const { createTeamManager } = await import("@skillkit/core");
|
|
2609
|
+
const manager = createTeamManager(process.cwd());
|
|
2610
|
+
const teamConfig = manager.load();
|
|
2611
|
+
if (!teamConfig) {
|
|
2612
|
+
setConfig(null);
|
|
2613
|
+
setSkills([]);
|
|
2614
|
+
setError("Team not initialized. Run `skillkit team init` first.");
|
|
2615
|
+
} else {
|
|
2616
|
+
setConfig(teamConfig);
|
|
2617
|
+
const sharedSkills = manager.listSharedSkills();
|
|
2618
|
+
setSkills(sharedSkills);
|
|
2619
|
+
setSel((s) => Math.min(s, Math.max(0, sharedSkills.length - 1)));
|
|
2620
|
+
}
|
|
2621
|
+
} catch (e) {
|
|
2622
|
+
setError(e instanceof Error ? e.message : "Failed to load team");
|
|
2623
|
+
}
|
|
2624
|
+
setLoading(false);
|
|
2625
|
+
};
|
|
2626
|
+
const syncTeam = async () => {
|
|
2627
|
+
if (!config) return;
|
|
2628
|
+
setLoading(true);
|
|
2629
|
+
setMessage(null);
|
|
2630
|
+
try {
|
|
2631
|
+
const { createTeamManager } = await import("@skillkit/core");
|
|
2632
|
+
const manager = createTeamManager(process.cwd());
|
|
2633
|
+
manager.load();
|
|
2634
|
+
const result = await manager.sync();
|
|
2635
|
+
const changes = [...result.added, ...result.updated];
|
|
2636
|
+
if (changes.length > 0) {
|
|
2637
|
+
setMessage(`Synced: ${changes.join(", ")}`);
|
|
2638
|
+
} else {
|
|
2639
|
+
setMessage("Already up to date");
|
|
2640
|
+
}
|
|
2641
|
+
const sharedSkills = manager.listSharedSkills();
|
|
2642
|
+
setSkills(sharedSkills);
|
|
2643
|
+
setSel((s) => Math.min(s, Math.max(0, sharedSkills.length - 1)));
|
|
2644
|
+
} catch (e) {
|
|
2645
|
+
setError(e instanceof Error ? e.message : "Sync failed");
|
|
2646
|
+
}
|
|
2647
|
+
setLoading(false);
|
|
2648
|
+
};
|
|
2649
|
+
const importSkill = async (skillName) => {
|
|
2650
|
+
if (!config) return;
|
|
2651
|
+
setLoading(true);
|
|
2652
|
+
setMessage(null);
|
|
2653
|
+
try {
|
|
2654
|
+
const { createTeamManager } = await import("@skillkit/core");
|
|
2655
|
+
const manager = createTeamManager(process.cwd());
|
|
2656
|
+
manager.load();
|
|
2657
|
+
const result = await manager.importSkill(skillName, { overwrite: false });
|
|
2658
|
+
if (result.success) {
|
|
2659
|
+
setMessage(`Imported: ${skillName}`);
|
|
2660
|
+
} else {
|
|
2661
|
+
setError(result.error || "Import failed");
|
|
2662
|
+
}
|
|
2663
|
+
} catch (e) {
|
|
2664
|
+
setError(e instanceof Error ? e.message : "Import failed");
|
|
2665
|
+
}
|
|
2666
|
+
setLoading(false);
|
|
2667
|
+
};
|
|
2668
|
+
useInput13((input, key) => {
|
|
2669
|
+
if (loading) return;
|
|
2670
|
+
if (skills.length === 0 && (key.upArrow || key.downArrow)) return;
|
|
2671
|
+
if (key.upArrow) setSel((i) => Math.max(0, i - 1));
|
|
2672
|
+
else if (key.downArrow) setSel((i) => Math.min(Math.max(0, skills.length - 1), i + 1));
|
|
2673
|
+
else if (input === "r") loadTeam();
|
|
2674
|
+
else if (input === "s") syncTeam();
|
|
2675
|
+
else if (key.return && skills[sel]) {
|
|
2676
|
+
importSkill(skills[sel].name);
|
|
2677
|
+
}
|
|
2678
|
+
});
|
|
2679
|
+
if (loading) {
|
|
2680
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
|
|
2681
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.primary, bold: true, children: "Team Collaboration" }),
|
|
2682
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: colors.secondaryDim, children: [
|
|
2683
|
+
symbols.spinner[0],
|
|
2684
|
+
" Loading..."
|
|
2685
|
+
] }) })
|
|
2686
|
+
] });
|
|
2687
|
+
}
|
|
2688
|
+
if (!config) {
|
|
2689
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
|
|
2690
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.primary, bold: true, children: "Team Collaboration" }),
|
|
2691
|
+
/* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
2692
|
+
/* @__PURE__ */ jsxs15(Text15, { color: colors.secondaryDim, children: [
|
|
2693
|
+
symbols.warning,
|
|
2694
|
+
" Team not initialized"
|
|
2695
|
+
] }),
|
|
2696
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.secondaryDim, dimColor: true, children: 'Run: skillkit team init --name "Team Name" --registry <url>' })
|
|
2697
|
+
] }),
|
|
2698
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "[r] Refresh" }) })
|
|
2699
|
+
] });
|
|
2700
|
+
}
|
|
2701
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 1, children: [
|
|
2702
|
+
/* @__PURE__ */ jsxs15(Text15, { color: colors.primary, bold: true, children: [
|
|
2703
|
+
"Team: ",
|
|
2704
|
+
config.teamName
|
|
2705
|
+
] }),
|
|
2706
|
+
/* @__PURE__ */ jsxs15(Text15, { color: colors.secondaryDim, dimColor: true, children: [
|
|
2707
|
+
"Registry: ",
|
|
2708
|
+
config.registryUrl
|
|
2709
|
+
] }),
|
|
2710
|
+
error && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
|
|
2711
|
+
symbols.error,
|
|
2712
|
+
" ",
|
|
2713
|
+
error
|
|
2714
|
+
] }) }),
|
|
2715
|
+
message && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "green", children: [
|
|
2716
|
+
symbols.success,
|
|
2717
|
+
" ",
|
|
2718
|
+
message
|
|
2719
|
+
] }) }),
|
|
2720
|
+
/* @__PURE__ */ jsxs15(Box15, { marginTop: 1, flexDirection: "column", children: [
|
|
2721
|
+
/* @__PURE__ */ jsxs15(Text15, { color: colors.secondaryDim, bold: true, children: [
|
|
2722
|
+
"Shared Skills (",
|
|
2723
|
+
skills.length,
|
|
2724
|
+
")"
|
|
2725
|
+
] }),
|
|
2726
|
+
skills.length === 0 ? /* @__PURE__ */ jsx15(Text15, { color: colors.secondaryDim, dimColor: true, children: "No shared skills. Use `skillkit team share --name <skill>` to share." }) : /* @__PURE__ */ jsx15(Box15, { flexDirection: "column", marginTop: 1, children: visible.map((skill, i) => {
|
|
2727
|
+
const actualIndex = start + i;
|
|
2728
|
+
const isSelected = actualIndex === sel;
|
|
2729
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
|
|
2730
|
+
/* @__PURE__ */ jsxs15(Text15, { children: [
|
|
2731
|
+
isSelected ? symbols.pointer : " ",
|
|
2732
|
+
" ",
|
|
2733
|
+
/* @__PURE__ */ jsx15(Text15, { color: isSelected ? colors.primary : colors.secondaryDim, bold: isSelected, children: skill.name }),
|
|
2734
|
+
/* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
|
|
2735
|
+
" v",
|
|
2736
|
+
skill.version
|
|
2737
|
+
] }),
|
|
2738
|
+
/* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
|
|
2739
|
+
" by ",
|
|
2740
|
+
skill.author
|
|
2741
|
+
] }),
|
|
2742
|
+
skill.downloads !== void 0 && /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
|
|
2743
|
+
" | ",
|
|
2744
|
+
skill.downloads,
|
|
2745
|
+
" downloads"
|
|
2746
|
+
] })
|
|
2747
|
+
] }),
|
|
2748
|
+
skill.description && isSelected && /* @__PURE__ */ jsxs15(Text15, { color: colors.secondaryDim, dimColor: true, children: [
|
|
2749
|
+
" ",
|
|
2750
|
+
skill.description
|
|
2751
|
+
] })
|
|
2752
|
+
] }, skill.name);
|
|
2753
|
+
}) })
|
|
2754
|
+
] }),
|
|
2755
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, borderStyle: "single", borderColor: colors.borderDim, paddingX: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "[\u2191\u2193] Navigate [Enter] Import [s] Sync [r] Refresh" }) })
|
|
2756
|
+
] });
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
// src/screens/Plugins.tsx
|
|
2760
|
+
import { useState as useState18, useEffect as useEffect15 } from "react";
|
|
2761
|
+
import { Box as Box16, Text as Text16, useInput as useInput14 } from "ink";
|
|
2762
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2763
|
+
function Plugins({ rows = 24 }) {
|
|
2764
|
+
const [plugins, setPlugins] = useState18([]);
|
|
2765
|
+
const [loading, setLoading] = useState18(true);
|
|
2766
|
+
const [error, setError] = useState18(null);
|
|
2767
|
+
const [sel, setSel] = useState18(0);
|
|
2768
|
+
const [message, setMessage] = useState18(null);
|
|
2769
|
+
const maxVisible = Math.max(5, rows - 12);
|
|
2770
|
+
const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), plugins.length - maxVisible));
|
|
2771
|
+
const visible = plugins.slice(start, start + maxVisible);
|
|
2772
|
+
useEffect15(() => {
|
|
2773
|
+
loadPlugins();
|
|
2774
|
+
}, []);
|
|
2775
|
+
const loadPlugins = async () => {
|
|
2776
|
+
setLoading(true);
|
|
2777
|
+
setError(null);
|
|
2778
|
+
try {
|
|
2779
|
+
const { createPluginManager, loadPluginsFromDirectory } = await import("@skillkit/core");
|
|
2780
|
+
const { join: join6 } = await import("path");
|
|
2781
|
+
const manager = createPluginManager(process.cwd());
|
|
2782
|
+
const pluginsDir = join6(process.cwd(), ".skillkit", "plugins");
|
|
2783
|
+
try {
|
|
2784
|
+
const loadedPlugins = await loadPluginsFromDirectory(pluginsDir);
|
|
2785
|
+
for (const plugin of loadedPlugins) {
|
|
2786
|
+
if (!manager.getPlugin(plugin.metadata.name)) {
|
|
2787
|
+
await manager.register(plugin);
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
} catch (err) {
|
|
2791
|
+
if (err && typeof err === "object" && "code" in err && err.code !== "ENOENT") {
|
|
2792
|
+
throw err;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
const allPlugins = manager.listPlugins();
|
|
2796
|
+
const pluginInfos = allPlugins.map((p) => {
|
|
2797
|
+
const plugin = manager.getPlugin(p.name);
|
|
2798
|
+
return {
|
|
2799
|
+
name: p.name,
|
|
2800
|
+
version: p.version,
|
|
2801
|
+
description: p.description,
|
|
2802
|
+
author: p.author,
|
|
2803
|
+
enabled: manager.isPluginEnabled(p.name),
|
|
2804
|
+
translators: plugin?.translators?.map((t) => t.agentType),
|
|
2805
|
+
providers: plugin?.providers?.map((pr) => pr.providerName),
|
|
2806
|
+
commands: plugin?.commands?.map((c) => c.name)
|
|
2807
|
+
};
|
|
2808
|
+
});
|
|
2809
|
+
setPlugins(pluginInfos);
|
|
2810
|
+
} catch (e) {
|
|
2811
|
+
setError(e instanceof Error ? e.message : "Failed to load plugins");
|
|
2812
|
+
}
|
|
2813
|
+
setLoading(false);
|
|
2814
|
+
};
|
|
2815
|
+
const togglePlugin = async (pluginName, currentEnabled) => {
|
|
2816
|
+
setLoading(true);
|
|
2817
|
+
setMessage(null);
|
|
2818
|
+
try {
|
|
2819
|
+
const { createPluginManager, loadPluginsFromDirectory } = await import("@skillkit/core");
|
|
2820
|
+
const { join: join6 } = await import("path");
|
|
2821
|
+
const manager = createPluginManager(process.cwd());
|
|
2822
|
+
const pluginsDir = join6(process.cwd(), ".skillkit", "plugins");
|
|
2823
|
+
try {
|
|
2824
|
+
const loadedPlugins = await loadPluginsFromDirectory(pluginsDir);
|
|
2825
|
+
for (const plugin of loadedPlugins) {
|
|
2826
|
+
if (!manager.getPlugin(plugin.metadata.name)) {
|
|
2827
|
+
await manager.register(plugin);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
} catch (err) {
|
|
2831
|
+
if (err && typeof err === "object" && "code" in err && err.code !== "ENOENT") {
|
|
2832
|
+
throw err;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
if (currentEnabled) {
|
|
2836
|
+
manager.disablePlugin(pluginName);
|
|
2837
|
+
setMessage(`Disabled: ${pluginName}`);
|
|
2838
|
+
} else {
|
|
2839
|
+
manager.enablePlugin(pluginName);
|
|
2840
|
+
setMessage(`Enabled: ${pluginName}`);
|
|
2841
|
+
}
|
|
2842
|
+
await loadPlugins();
|
|
2843
|
+
} catch (e) {
|
|
2844
|
+
setError(e instanceof Error ? e.message : "Toggle failed");
|
|
2845
|
+
setLoading(false);
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
useInput14((input, key) => {
|
|
2849
|
+
if (loading) return;
|
|
2850
|
+
if (plugins.length === 0 && (key.upArrow || key.downArrow)) return;
|
|
2851
|
+
if (key.upArrow) setSel((i) => Math.max(0, i - 1));
|
|
2852
|
+
else if (key.downArrow) setSel((i) => Math.min(Math.max(0, plugins.length - 1), i + 1));
|
|
2853
|
+
else if (input === "r") loadPlugins();
|
|
2854
|
+
else if (input === "e" && plugins[sel]) {
|
|
2855
|
+
togglePlugin(plugins[sel].name, plugins[sel].enabled);
|
|
2856
|
+
} else if (key.return && plugins[sel]) {
|
|
2857
|
+
togglePlugin(plugins[sel].name, plugins[sel].enabled);
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
if (loading) {
|
|
2861
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
|
|
2862
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.primary, bold: true, children: "Plugin Manager" }),
|
|
2863
|
+
/* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: colors.secondaryDim, children: [
|
|
2864
|
+
symbols.spinner[0],
|
|
2865
|
+
" Loading..."
|
|
2866
|
+
] }) })
|
|
2867
|
+
] });
|
|
2868
|
+
}
|
|
2869
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", padding: 1, children: [
|
|
2870
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.primary, bold: true, children: "Plugin Manager" }),
|
|
2871
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.secondaryDim, dimColor: true, children: "Manage SkillKit extensions" }),
|
|
2872
|
+
error && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "red", children: [
|
|
2873
|
+
symbols.error,
|
|
2874
|
+
" ",
|
|
2875
|
+
error
|
|
2876
|
+
] }) }),
|
|
2877
|
+
message && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "green", children: [
|
|
2878
|
+
symbols.success,
|
|
2879
|
+
" ",
|
|
2880
|
+
message
|
|
2881
|
+
] }) }),
|
|
2882
|
+
/* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
2883
|
+
/* @__PURE__ */ jsxs16(Text16, { color: colors.secondaryDim, bold: true, children: [
|
|
2884
|
+
"Installed Plugins (",
|
|
2885
|
+
plugins.length,
|
|
2886
|
+
")"
|
|
2887
|
+
] }),
|
|
2888
|
+
plugins.length === 0 ? /* @__PURE__ */ jsxs16(Box16, { marginTop: 1, flexDirection: "column", children: [
|
|
2889
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.secondaryDim, dimColor: true, children: "No plugins installed." }),
|
|
2890
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.secondaryDim, dimColor: true, children: "Use: skillkit plugin install --source <path-or-package>" })
|
|
2891
|
+
] }) : /* @__PURE__ */ jsx16(Box16, { flexDirection: "column", marginTop: 1, children: visible.map((plugin, i) => {
|
|
2892
|
+
const actualIndex = start + i;
|
|
2893
|
+
const isSelected = actualIndex === sel;
|
|
2894
|
+
const statusColor = plugin.enabled ? "green" : "gray";
|
|
2895
|
+
const statusText = plugin.enabled ? "enabled" : "disabled";
|
|
2896
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
2897
|
+
/* @__PURE__ */ jsxs16(Text16, { children: [
|
|
2898
|
+
isSelected ? symbols.pointer : " ",
|
|
2899
|
+
" ",
|
|
2900
|
+
/* @__PURE__ */ jsx16(Text16, { color: isSelected ? colors.primary : colors.secondaryDim, bold: isSelected, children: plugin.name }),
|
|
2901
|
+
/* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
2902
|
+
" v",
|
|
2903
|
+
plugin.version
|
|
2904
|
+
] }),
|
|
2905
|
+
/* @__PURE__ */ jsxs16(Text16, { color: statusColor, children: [
|
|
2906
|
+
" [",
|
|
2907
|
+
statusText,
|
|
2908
|
+
"]"
|
|
2909
|
+
] })
|
|
2910
|
+
] }),
|
|
2911
|
+
isSelected && /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginLeft: 3, children: [
|
|
2912
|
+
plugin.description && /* @__PURE__ */ jsx16(Text16, { color: colors.secondaryDim, dimColor: true, children: plugin.description }),
|
|
2913
|
+
plugin.author && /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
2914
|
+
"Author: ",
|
|
2915
|
+
plugin.author
|
|
2916
|
+
] }),
|
|
2917
|
+
plugin.translators && plugin.translators.length > 0 && /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
2918
|
+
"Translators: ",
|
|
2919
|
+
plugin.translators.join(", ")
|
|
2920
|
+
] }),
|
|
2921
|
+
plugin.providers && plugin.providers.length > 0 && /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
2922
|
+
"Providers: ",
|
|
2923
|
+
plugin.providers.join(", ")
|
|
2924
|
+
] }),
|
|
2925
|
+
plugin.commands && plugin.commands.length > 0 && /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
2926
|
+
"Commands: ",
|
|
2927
|
+
plugin.commands.join(", ")
|
|
2928
|
+
] })
|
|
2929
|
+
] })
|
|
2930
|
+
] }, plugin.name);
|
|
2931
|
+
}) })
|
|
2932
|
+
] }),
|
|
2933
|
+
/* @__PURE__ */ jsx16(Box16, { marginTop: 1, borderStyle: "single", borderColor: colors.borderDim, paddingX: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "[\u2191\u2193] Navigate [e/Enter] Toggle Enable/Disable [r] Refresh" }) })
|
|
2934
|
+
] });
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// src/App.tsx
|
|
2938
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1817
2939
|
function App() {
|
|
1818
|
-
const [screen, setScreen] =
|
|
2940
|
+
const [screen, setScreen] = useState19("home");
|
|
1819
2941
|
const { exit } = useApp();
|
|
1820
2942
|
const { stdout } = useStdout();
|
|
1821
2943
|
const cols = stdout?.columns || 80;
|
|
1822
2944
|
const rows = stdout?.rows || 24;
|
|
1823
2945
|
const showSidebar = cols >= 70;
|
|
1824
|
-
|
|
2946
|
+
const NAV_KEYS = {
|
|
2947
|
+
h: "home",
|
|
2948
|
+
m: "marketplace",
|
|
2949
|
+
b: "browse",
|
|
2950
|
+
w: "workflow",
|
|
2951
|
+
x: "execute",
|
|
2952
|
+
y: "history",
|
|
2953
|
+
r: "recommend",
|
|
2954
|
+
t: "translate",
|
|
2955
|
+
c: "context",
|
|
2956
|
+
e: "memory",
|
|
2957
|
+
i: "installed",
|
|
2958
|
+
s: "sync",
|
|
2959
|
+
a: "team",
|
|
2960
|
+
p: "plugins",
|
|
2961
|
+
",": "settings"
|
|
2962
|
+
};
|
|
2963
|
+
useInput15((input, key) => {
|
|
1825
2964
|
if (input === "q") {
|
|
1826
2965
|
exit();
|
|
1827
2966
|
return;
|
|
@@ -1830,65 +2969,75 @@ function App() {
|
|
|
1830
2969
|
setScreen("home");
|
|
1831
2970
|
return;
|
|
1832
2971
|
}
|
|
1833
|
-
|
|
1834
|
-
if (
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
if (input === ",") setScreen("settings");
|
|
1838
|
-
if (input === "r") setScreen("recommend");
|
|
1839
|
-
if (input === "t") setScreen("translate");
|
|
1840
|
-
if (input === "c") setScreen("context");
|
|
2972
|
+
const targetScreen = NAV_KEYS[input];
|
|
2973
|
+
if (targetScreen) {
|
|
2974
|
+
setScreen(targetScreen);
|
|
2975
|
+
}
|
|
1841
2976
|
});
|
|
1842
2977
|
const renderScreen = () => {
|
|
1843
2978
|
switch (screen) {
|
|
1844
2979
|
case "home":
|
|
1845
|
-
return /* @__PURE__ */
|
|
2980
|
+
return /* @__PURE__ */ jsx17(Home, { onNavigate: setScreen, cols, rows });
|
|
1846
2981
|
case "browse":
|
|
1847
|
-
return /* @__PURE__ */
|
|
2982
|
+
return /* @__PURE__ */ jsx17(Browse, { cols, rows });
|
|
1848
2983
|
case "installed":
|
|
1849
|
-
return /* @__PURE__ */
|
|
2984
|
+
return /* @__PURE__ */ jsx17(Installed, { cols, rows });
|
|
1850
2985
|
case "sync":
|
|
1851
|
-
return /* @__PURE__ */
|
|
2986
|
+
return /* @__PURE__ */ jsx17(Sync, { cols, rows });
|
|
1852
2987
|
case "settings":
|
|
1853
|
-
return /* @__PURE__ */
|
|
2988
|
+
return /* @__PURE__ */ jsx17(Settings, { cols, rows });
|
|
1854
2989
|
case "recommend":
|
|
1855
|
-
return /* @__PURE__ */
|
|
2990
|
+
return /* @__PURE__ */ jsx17(Recommend, { cols, rows });
|
|
1856
2991
|
case "translate":
|
|
1857
|
-
return /* @__PURE__ */
|
|
2992
|
+
return /* @__PURE__ */ jsx17(Translate, { cols, rows });
|
|
1858
2993
|
case "context":
|
|
1859
|
-
return /* @__PURE__ */
|
|
2994
|
+
return /* @__PURE__ */ jsx17(Context, { cols, rows });
|
|
2995
|
+
case "workflow":
|
|
2996
|
+
return /* @__PURE__ */ jsx17(Workflow, { cols, rows });
|
|
2997
|
+
case "execute":
|
|
2998
|
+
return /* @__PURE__ */ jsx17(Execute, { cols, rows });
|
|
2999
|
+
case "history":
|
|
3000
|
+
return /* @__PURE__ */ jsx17(History, { cols, rows });
|
|
3001
|
+
case "marketplace":
|
|
3002
|
+
return /* @__PURE__ */ jsx17(Marketplace, { cols, rows });
|
|
3003
|
+
case "memory":
|
|
3004
|
+
return /* @__PURE__ */ jsx17(Memory, { cols, rows });
|
|
3005
|
+
case "team":
|
|
3006
|
+
return /* @__PURE__ */ jsx17(Team, { cols, rows });
|
|
3007
|
+
case "plugins":
|
|
3008
|
+
return /* @__PURE__ */ jsx17(Plugins, { cols, rows });
|
|
1860
3009
|
}
|
|
1861
3010
|
};
|
|
1862
3011
|
const contentHeight = rows - 2;
|
|
1863
|
-
return /* @__PURE__ */
|
|
1864
|
-
/* @__PURE__ */
|
|
1865
|
-
showSidebar && /* @__PURE__ */
|
|
1866
|
-
/* @__PURE__ */
|
|
3012
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", height: rows, children: [
|
|
3013
|
+
/* @__PURE__ */ jsxs17(Box17, { flexDirection: "row", height: contentHeight, children: [
|
|
3014
|
+
showSidebar && /* @__PURE__ */ jsx17(Sidebar, { screen, onNavigate: setScreen }),
|
|
3015
|
+
/* @__PURE__ */ jsx17(Box17, { flexDirection: "column", flexGrow: 1, marginLeft: 1, children: renderScreen() })
|
|
1867
3016
|
] }),
|
|
1868
|
-
/* @__PURE__ */
|
|
3017
|
+
/* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "h Home m Market b Browse i Inst w Wflow x Exec a Team p Plug r Rec t Trans c Ctx e Mem s Sync , Cfg q Quit" }) })
|
|
1869
3018
|
] });
|
|
1870
3019
|
}
|
|
1871
3020
|
|
|
1872
3021
|
// src/components/Header.tsx
|
|
1873
|
-
import { Box as
|
|
1874
|
-
import { jsx as
|
|
3022
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
3023
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1875
3024
|
function Header({ title, subtitle, count }) {
|
|
1876
|
-
return /* @__PURE__ */
|
|
1877
|
-
/* @__PURE__ */
|
|
1878
|
-
/* @__PURE__ */
|
|
1879
|
-
count !== void 0 && /* @__PURE__ */
|
|
3025
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", marginBottom: 1, children: [
|
|
3026
|
+
/* @__PURE__ */ jsxs18(Box18, { justifyContent: "space-between", children: [
|
|
3027
|
+
/* @__PURE__ */ jsx18(Text18, { color: colors.primary, bold: true, children: title.toUpperCase() }),
|
|
3028
|
+
count !== void 0 && /* @__PURE__ */ jsxs18(Text18, { color: colors.secondaryDim, children: [
|
|
1880
3029
|
symbols.star,
|
|
1881
3030
|
" ",
|
|
1882
3031
|
count
|
|
1883
3032
|
] })
|
|
1884
3033
|
] }),
|
|
1885
|
-
subtitle && /* @__PURE__ */
|
|
3034
|
+
subtitle && /* @__PURE__ */ jsx18(Text18, { color: colors.secondaryDim, dimColor: true, children: subtitle })
|
|
1886
3035
|
] });
|
|
1887
3036
|
}
|
|
1888
3037
|
|
|
1889
3038
|
// src/components/SkillList.tsx
|
|
1890
|
-
import { Box as
|
|
1891
|
-
import { jsx as
|
|
3039
|
+
import { Box as Box19, Text as Text19 } from "ink";
|
|
3040
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1892
3041
|
function formatInstalls(count) {
|
|
1893
3042
|
if (count >= 1e3) {
|
|
1894
3043
|
return `${(count / 1e3).toFixed(1)}K`;
|
|
@@ -1904,13 +3053,13 @@ function SkillList({
|
|
|
1904
3053
|
maxVisible = 10
|
|
1905
3054
|
}) {
|
|
1906
3055
|
if (skills.length === 0) {
|
|
1907
|
-
return /* @__PURE__ */
|
|
3056
|
+
return /* @__PURE__ */ jsx19(Box19, { children: /* @__PURE__ */ jsx19(Text19, { color: colors.secondaryDim, dimColor: true, children: "No skills found" }) });
|
|
1908
3057
|
}
|
|
1909
3058
|
const startIndex = Math.max(0, selectedIndex - Math.floor(maxVisible / 2));
|
|
1910
3059
|
const visibleSkills = skills.slice(startIndex, startIndex + maxVisible);
|
|
1911
3060
|
const actualStartIndex = startIndex;
|
|
1912
|
-
return /* @__PURE__ */
|
|
1913
|
-
showRank && /* @__PURE__ */
|
|
3061
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
3062
|
+
showRank && /* @__PURE__ */ jsx19(Box19, { marginBottom: 1, children: /* @__PURE__ */ jsxs19(Text19, { color: colors.secondaryDim, children: [
|
|
1914
3063
|
" # SKILL",
|
|
1915
3064
|
showSource && " SOURCE",
|
|
1916
3065
|
showInstalls && " INSTALLS"
|
|
@@ -1920,9 +3069,9 @@ function SkillList({
|
|
|
1920
3069
|
const isSelected = realIndex === selectedIndex;
|
|
1921
3070
|
const skillName = skill.name.padEnd(28).slice(0, 28);
|
|
1922
3071
|
const sourceName = skill.source ? skill.source.slice(0, 25) : "";
|
|
1923
|
-
return /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
|
|
3072
|
+
return /* @__PURE__ */ jsxs19(Box19, { children: [
|
|
3073
|
+
/* @__PURE__ */ jsxs19(
|
|
3074
|
+
Text19,
|
|
1926
3075
|
{
|
|
1927
3076
|
color: isSelected ? colors.primary : colors.secondary,
|
|
1928
3077
|
bold: isSelected,
|
|
@@ -1935,14 +3084,14 @@ function SkillList({
|
|
|
1935
3084
|
]
|
|
1936
3085
|
}
|
|
1937
3086
|
),
|
|
1938
|
-
showSource && /* @__PURE__ */
|
|
3087
|
+
showSource && /* @__PURE__ */ jsxs19(Text19, { color: colors.secondaryDim, dimColor: !isSelected, children: [
|
|
1939
3088
|
" ",
|
|
1940
3089
|
sourceName
|
|
1941
3090
|
] }),
|
|
1942
|
-
showInstalls && skill.installs !== void 0 && /* @__PURE__ */
|
|
3091
|
+
showInstalls && skill.installs !== void 0 && /* @__PURE__ */ jsx19(Text19, { color: colors.secondaryDim, children: formatInstalls(skill.installs).padStart(8) })
|
|
1943
3092
|
] }, `${skill.source}-${skill.name}`);
|
|
1944
3093
|
}),
|
|
1945
|
-
skills.length > maxVisible && /* @__PURE__ */
|
|
3094
|
+
skills.length > maxVisible && /* @__PURE__ */ jsx19(Box19, { marginTop: 1, children: /* @__PURE__ */ jsxs19(Text19, { color: colors.secondaryDim, dimColor: true, children: [
|
|
1946
3095
|
"Showing ",
|
|
1947
3096
|
startIndex + 1,
|
|
1948
3097
|
"-",
|
|
@@ -1954,11 +3103,11 @@ function SkillList({
|
|
|
1954
3103
|
}
|
|
1955
3104
|
|
|
1956
3105
|
// src/components/StatusBar.tsx
|
|
1957
|
-
import { Box as
|
|
1958
|
-
import { jsx as
|
|
3106
|
+
import { Box as Box20, Text as Text20 } from "ink";
|
|
3107
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1959
3108
|
function StatusBar({ shortcuts, message }) {
|
|
1960
|
-
return /* @__PURE__ */
|
|
1961
|
-
|
|
3109
|
+
return /* @__PURE__ */ jsxs20(
|
|
3110
|
+
Box20,
|
|
1962
3111
|
{
|
|
1963
3112
|
borderStyle: "single",
|
|
1964
3113
|
borderColor: colors.borderDim,
|
|
@@ -1969,11 +3118,11 @@ function StatusBar({ shortcuts, message }) {
|
|
|
1969
3118
|
paddingX: 1,
|
|
1970
3119
|
justifyContent: "space-between",
|
|
1971
3120
|
children: [
|
|
1972
|
-
/* @__PURE__ */
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
/* @__PURE__ */
|
|
3121
|
+
/* @__PURE__ */ jsx20(Box20, { gap: 2, children: shortcuts.map((shortcut, idx) => /* @__PURE__ */ jsxs20(Box20, { gap: 1, children: [
|
|
3122
|
+
/* @__PURE__ */ jsx20(Text20, { color: colors.primary, bold: true, children: shortcut.key }),
|
|
3123
|
+
/* @__PURE__ */ jsx20(Text20, { color: colors.secondaryDim, children: shortcut.label })
|
|
1975
3124
|
] }, idx)) }),
|
|
1976
|
-
message && /* @__PURE__ */
|
|
3125
|
+
message && /* @__PURE__ */ jsxs20(Text20, { color: colors.success, children: [
|
|
1977
3126
|
symbols.check,
|
|
1978
3127
|
" ",
|
|
1979
3128
|
message
|
|
@@ -1984,44 +3133,44 @@ function StatusBar({ shortcuts, message }) {
|
|
|
1984
3133
|
}
|
|
1985
3134
|
|
|
1986
3135
|
// src/components/SearchInput.tsx
|
|
1987
|
-
import { Box as
|
|
1988
|
-
import
|
|
1989
|
-
import { jsx as
|
|
3136
|
+
import { Box as Box21, Text as Text21 } from "ink";
|
|
3137
|
+
import TextInput2 from "ink-text-input";
|
|
3138
|
+
import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1990
3139
|
function SearchInput({
|
|
1991
3140
|
value,
|
|
1992
3141
|
onChange,
|
|
1993
3142
|
placeholder = "Search skills...",
|
|
1994
3143
|
isFocused = false
|
|
1995
3144
|
}) {
|
|
1996
|
-
return /* @__PURE__ */
|
|
1997
|
-
|
|
3145
|
+
return /* @__PURE__ */ jsxs21(
|
|
3146
|
+
Box21,
|
|
1998
3147
|
{
|
|
1999
3148
|
borderStyle: "single",
|
|
2000
3149
|
borderColor: isFocused ? colors.primary : colors.borderDim,
|
|
2001
3150
|
paddingX: 1,
|
|
2002
3151
|
children: [
|
|
2003
|
-
/* @__PURE__ */
|
|
2004
|
-
isFocused ? /* @__PURE__ */
|
|
2005
|
-
|
|
3152
|
+
/* @__PURE__ */ jsx21(Text21, { color: colors.secondaryDim, children: "/ " }),
|
|
3153
|
+
isFocused ? /* @__PURE__ */ jsx21(
|
|
3154
|
+
TextInput2,
|
|
2006
3155
|
{
|
|
2007
3156
|
value,
|
|
2008
3157
|
onChange,
|
|
2009
3158
|
placeholder
|
|
2010
3159
|
}
|
|
2011
|
-
) : /* @__PURE__ */
|
|
2012
|
-
/* @__PURE__ */
|
|
2013
|
-
/* @__PURE__ */
|
|
3160
|
+
) : /* @__PURE__ */ jsx21(Text21, { color: value ? colors.secondary : colors.secondaryDim, children: value || placeholder }),
|
|
3161
|
+
/* @__PURE__ */ jsx21(Box21, { flexGrow: 1 }),
|
|
3162
|
+
/* @__PURE__ */ jsx21(Text21, { color: colors.secondaryDim, children: "/" })
|
|
2014
3163
|
]
|
|
2015
3164
|
}
|
|
2016
3165
|
);
|
|
2017
3166
|
}
|
|
2018
3167
|
|
|
2019
3168
|
// src/hooks/useKeyboard.ts
|
|
2020
|
-
import { useState as
|
|
2021
|
-
import { useInput as
|
|
3169
|
+
import { useState as useState20, useCallback as useCallback3, useEffect as useEffect16 } from "react";
|
|
3170
|
+
import { useInput as useInput16, useApp as useApp2 } from "ink";
|
|
2022
3171
|
function useKeyboard(options = {}) {
|
|
2023
3172
|
const { exit } = useApp2();
|
|
2024
|
-
|
|
3173
|
+
useInput16((input, key) => {
|
|
2025
3174
|
if (options.disabled) return;
|
|
2026
3175
|
if (input === "q" || key.ctrl && input === "c") {
|
|
2027
3176
|
exit();
|
|
@@ -2065,8 +3214,8 @@ function useKeyboard(options = {}) {
|
|
|
2065
3214
|
});
|
|
2066
3215
|
}
|
|
2067
3216
|
function useListNavigation(listLength, initialIndex = 0) {
|
|
2068
|
-
const [selectedIndex, setSelectedIndex] =
|
|
2069
|
-
|
|
3217
|
+
const [selectedIndex, setSelectedIndex] = useState20(initialIndex);
|
|
3218
|
+
useEffect16(() => {
|
|
2070
3219
|
if (selectedIndex >= listLength && listLength > 0) {
|
|
2071
3220
|
setSelectedIndex(listLength - 1);
|
|
2072
3221
|
}
|
|
@@ -2083,11 +3232,122 @@ function useListNavigation(listLength, initialIndex = 0) {
|
|
|
2083
3232
|
return { selectedIndex, setSelectedIndex, moveUp, moveDown, reset };
|
|
2084
3233
|
}
|
|
2085
3234
|
|
|
3235
|
+
// src/hooks/useMemory.ts
|
|
3236
|
+
import { useState as useState21, useEffect as useEffect17, useCallback as useCallback4 } from "react";
|
|
3237
|
+
import {
|
|
3238
|
+
LearningStore as LearningStore2,
|
|
3239
|
+
ObservationStore as ObservationStore2,
|
|
3240
|
+
getMemoryStatus as getMemoryStatus2,
|
|
3241
|
+
createMemoryInjector as createMemoryInjector2
|
|
3242
|
+
} from "@skillkit/core";
|
|
3243
|
+
function useMemory() {
|
|
3244
|
+
const [learnings, setLearnings] = useState21([]);
|
|
3245
|
+
const [observations, setObservations] = useState21([]);
|
|
3246
|
+
const [status, setStatus] = useState21(null);
|
|
3247
|
+
const [loading, setLoading] = useState21(true);
|
|
3248
|
+
const [error, setError] = useState21(null);
|
|
3249
|
+
const [isGlobal, setIsGlobal] = useState21(false);
|
|
3250
|
+
const projectPath = process.cwd();
|
|
3251
|
+
const refresh = useCallback4(() => {
|
|
3252
|
+
setLoading(true);
|
|
3253
|
+
setError(null);
|
|
3254
|
+
try {
|
|
3255
|
+
const memStatus = getMemoryStatus2(projectPath);
|
|
3256
|
+
setStatus(memStatus);
|
|
3257
|
+
const learningStore = new LearningStore2(
|
|
3258
|
+
isGlobal ? "global" : "project",
|
|
3259
|
+
isGlobal ? void 0 : projectPath
|
|
3260
|
+
);
|
|
3261
|
+
setLearnings(learningStore.getAll());
|
|
3262
|
+
if (memStatus.hasObservations) {
|
|
3263
|
+
const obsStore = new ObservationStore2(projectPath);
|
|
3264
|
+
setObservations(obsStore.getAll());
|
|
3265
|
+
} else {
|
|
3266
|
+
setObservations([]);
|
|
3267
|
+
}
|
|
3268
|
+
} catch (err) {
|
|
3269
|
+
setError(err instanceof Error ? err.message : "Failed to load memory");
|
|
3270
|
+
setLearnings([]);
|
|
3271
|
+
setObservations([]);
|
|
3272
|
+
} finally {
|
|
3273
|
+
setLoading(false);
|
|
3274
|
+
}
|
|
3275
|
+
}, [projectPath, isGlobal]);
|
|
3276
|
+
const search = useCallback4(
|
|
3277
|
+
(query) => {
|
|
3278
|
+
if (!query.trim()) {
|
|
3279
|
+
return [];
|
|
3280
|
+
}
|
|
3281
|
+
try {
|
|
3282
|
+
const injector = createMemoryInjector2(projectPath);
|
|
3283
|
+
const results = injector.search(query, {
|
|
3284
|
+
includeGlobal: true,
|
|
3285
|
+
maxLearnings: 50,
|
|
3286
|
+
minRelevance: 0
|
|
3287
|
+
});
|
|
3288
|
+
return results.map((r) => r.learning);
|
|
3289
|
+
} catch {
|
|
3290
|
+
return [];
|
|
3291
|
+
}
|
|
3292
|
+
},
|
|
3293
|
+
[projectPath]
|
|
3294
|
+
);
|
|
3295
|
+
const deleteLearning = useCallback4(
|
|
3296
|
+
(id) => {
|
|
3297
|
+
try {
|
|
3298
|
+
const store = new LearningStore2(
|
|
3299
|
+
isGlobal ? "global" : "project",
|
|
3300
|
+
isGlobal ? void 0 : projectPath
|
|
3301
|
+
);
|
|
3302
|
+
const result = store.delete(id);
|
|
3303
|
+
if (result) {
|
|
3304
|
+
refresh();
|
|
3305
|
+
}
|
|
3306
|
+
return result;
|
|
3307
|
+
} catch {
|
|
3308
|
+
return false;
|
|
3309
|
+
}
|
|
3310
|
+
},
|
|
3311
|
+
[projectPath, isGlobal, refresh]
|
|
3312
|
+
);
|
|
3313
|
+
const deleteObservation = useCallback4(
|
|
3314
|
+
(id) => {
|
|
3315
|
+
try {
|
|
3316
|
+
const store = new ObservationStore2(projectPath);
|
|
3317
|
+
const result = store.delete(id);
|
|
3318
|
+
if (result) {
|
|
3319
|
+
refresh();
|
|
3320
|
+
}
|
|
3321
|
+
return result;
|
|
3322
|
+
} catch {
|
|
3323
|
+
return false;
|
|
3324
|
+
}
|
|
3325
|
+
},
|
|
3326
|
+
[projectPath, refresh]
|
|
3327
|
+
);
|
|
3328
|
+
useEffect17(() => {
|
|
3329
|
+
refresh();
|
|
3330
|
+
}, [refresh]);
|
|
3331
|
+
return {
|
|
3332
|
+
learnings,
|
|
3333
|
+
observations,
|
|
3334
|
+
status,
|
|
3335
|
+
loading,
|
|
3336
|
+
error,
|
|
3337
|
+
isGlobal,
|
|
3338
|
+
setIsGlobal,
|
|
3339
|
+
refresh,
|
|
3340
|
+
search,
|
|
3341
|
+
deleteLearning,
|
|
3342
|
+
deleteObservation
|
|
3343
|
+
};
|
|
3344
|
+
}
|
|
3345
|
+
|
|
2086
3346
|
// src/index.tsx
|
|
2087
|
-
import { jsx as
|
|
3347
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
2088
3348
|
function startTUI() {
|
|
2089
3349
|
process.stdout.write("\x1B[2J\x1B[0f");
|
|
2090
|
-
const { waitUntilExit, clear } = render(/* @__PURE__ */
|
|
3350
|
+
const { waitUntilExit, clear } = render(/* @__PURE__ */ jsx22(App, {}), {
|
|
2091
3351
|
exitOnCtrlC: true
|
|
2092
3352
|
});
|
|
2093
3353
|
return waitUntilExit().then(() => {
|
|
@@ -2098,9 +3358,14 @@ export {
|
|
|
2098
3358
|
App,
|
|
2099
3359
|
Browse,
|
|
2100
3360
|
Context,
|
|
3361
|
+
Execute,
|
|
2101
3362
|
Header,
|
|
3363
|
+
History,
|
|
2102
3364
|
Home,
|
|
2103
3365
|
Installed,
|
|
3366
|
+
Marketplace,
|
|
3367
|
+
Memory,
|
|
3368
|
+
Plugins,
|
|
2104
3369
|
Recommend,
|
|
2105
3370
|
SearchInput,
|
|
2106
3371
|
Settings,
|
|
@@ -2108,7 +3373,9 @@ export {
|
|
|
2108
3373
|
SkillList,
|
|
2109
3374
|
StatusBar,
|
|
2110
3375
|
Sync,
|
|
3376
|
+
Team,
|
|
2111
3377
|
Translate,
|
|
3378
|
+
Workflow,
|
|
2112
3379
|
colors,
|
|
2113
3380
|
logo,
|
|
2114
3381
|
startTUI,
|
|
@@ -2116,6 +3383,7 @@ export {
|
|
|
2116
3383
|
useKeyboard,
|
|
2117
3384
|
useListNavigation,
|
|
2118
3385
|
useMarketplace,
|
|
3386
|
+
useMemory,
|
|
2119
3387
|
useRecommend,
|
|
2120
3388
|
useSkills
|
|
2121
3389
|
};
|