@skillkit/tui 1.3.1 → 1.4.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/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 useState12 } from "react";
6
- import { Box as Box10, Text as Text10, useInput as useInput8, useApp, useStdout } from "ink";
5
+ import { useState as useState17 } from "react";
6
+ import { Box as Box15, Text as Text15, useInput as useInput13, 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,23 @@ var logo = `
41
47
  // src/components/Sidebar.tsx
42
48
  import { jsx, jsxs } from "react/jsx-runtime";
43
49
  var NAV = [
44
- { id: "home", label: "Home" },
45
- { id: "browse", label: "Browse" },
46
- { id: "recommend", label: "Recommend" },
47
- { id: "translate", label: "Translate" },
48
- { id: "context", label: "Context" },
49
- { id: "installed", label: "List" },
50
- { id: "sync", label: "Sync" },
51
- { id: "settings", label: "Config" }
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
+ // Tools
59
+ { id: "recommend", label: "Recommend", key: "r" },
60
+ { id: "translate", label: "Translate", key: "t" },
61
+ { id: "context", label: "Context", key: "c" },
62
+ { id: "memory", label: "Memory", key: "e" },
63
+ // Management
64
+ { id: "installed", label: "Installed", key: "i" },
65
+ { id: "sync", label: "Sync", key: "s" },
66
+ { id: "settings", label: "Config", key: "," }
52
67
  ];
53
68
  function Sidebar({ screen }) {
54
69
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 14, borderStyle: "single", paddingX: 1, children: [
@@ -58,12 +73,17 @@ function Sidebar({ screen }) {
58
73
  item.label
59
74
  ] }, item.id)),
60
75
  /* @__PURE__ */ jsx(Text, { children: " " }),
61
- NAV.slice(3, 5).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
76
+ NAV.slice(3, 6).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
62
77
  screen === item.id ? symbols.bullet : " ",
63
78
  item.label
64
79
  ] }, item.id)),
65
80
  /* @__PURE__ */ jsx(Text, { children: " " }),
66
- NAV.slice(5).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
81
+ NAV.slice(6, 10).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
82
+ screen === item.id ? symbols.bullet : " ",
83
+ item.label
84
+ ] }, item.id)),
85
+ /* @__PURE__ */ jsx(Text, { children: " " }),
86
+ NAV.slice(10).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
67
87
  screen === item.id ? symbols.bullet : " ",
68
88
  item.label
69
89
  ] }, item.id)),
@@ -722,174 +742,21 @@ function Settings({}) {
722
742
 
723
743
  // src/screens/Recommend.tsx
724
744
  import { useState as useState9 } from "react";
725
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
726
- import { join as join4 } from "path";
745
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
746
+ import { join as join3 } from "path";
727
747
  import { Box as Box7, Text as Text7, useInput as useInput5 } from "ink";
728
748
 
729
749
  // src/hooks/useRecommend.ts
730
750
  import { useState as useState8, useCallback as useCallback2, useEffect as useEffect5 } from "react";
731
751
  import {
732
752
  RecommendationEngine,
733
- ContextManager
753
+ ContextManager,
754
+ loadIndex as loadIndexFromCache,
755
+ saveIndex,
756
+ buildSkillIndex,
757
+ isIndexStale,
758
+ KNOWN_SKILL_REPOS
734
759
  } 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
760
  function useRecommend(projectPath = process.cwd()) {
894
761
  const [recommendations, setRecommendations] = useState8([]);
895
762
  const [searchResults, setSearchResults] = useState8([]);
@@ -900,25 +767,17 @@ function useRecommend(projectPath = process.cwd()) {
900
767
  const [indexStatus, setIndexStatus] = useState8("missing");
901
768
  const [engine] = useState8(() => new RecommendationEngine());
902
769
  const loadIndex = useCallback2(() => {
903
- if (!existsSync2(INDEX_PATH)) {
770
+ const index = loadIndexFromCache();
771
+ if (!index) {
904
772
  setIndexStatus("missing");
905
773
  return null;
906
774
  }
907
- try {
908
- const content = readFileSync2(INDEX_PATH, "utf-8");
909
- const index = JSON.parse(content);
910
- const lastUpdated = new Date(index.lastUpdated);
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;
775
+ if (isIndexStale(index)) {
776
+ setIndexStatus("stale");
777
+ } else {
778
+ setIndexStatus("fresh");
921
779
  }
780
+ return index;
922
781
  }, []);
923
782
  const getProjectProfile = useCallback2(() => {
924
783
  try {
@@ -978,37 +837,17 @@ function useRecommend(projectPath = process.cwd()) {
978
837
  const updateIndex = useCallback2(() => {
979
838
  setLoading(true);
980
839
  setError(null);
981
- try {
982
- const sampleIndex = {
983
- version: 1,
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 });
840
+ buildSkillIndex(KNOWN_SKILL_REPOS).then(({ index, errors }) => {
841
+ if (errors.length > 0) {
842
+ console.warn("Index update warnings:", errors);
1004
843
  }
1005
- writeFileSync(INDEX_PATH, JSON.stringify(sampleIndex, null, 2));
844
+ saveIndex(index);
1006
845
  setIndexStatus("fresh");
1007
846
  loadRecommendations();
1008
- } catch (err) {
847
+ }).catch((err) => {
1009
848
  setError(err instanceof Error ? err.message : "Failed to update index");
1010
849
  setLoading(false);
1011
- }
850
+ });
1012
851
  }, [loadRecommendations]);
1013
852
  const search = useCallback2((query) => {
1014
853
  if (!query.trim()) {
@@ -1126,11 +965,11 @@ function Recommend({ rows = 24 }) {
1126
965
  const targetAgentType = agentType || await detectAgent2();
1127
966
  const adapter = getAdapter3(targetAgentType);
1128
967
  const installDir = getInstallDir(false, targetAgentType);
1129
- if (!existsSync3(installDir)) {
1130
- mkdirSync3(installDir, { recursive: true });
968
+ if (!existsSync2(installDir)) {
969
+ mkdirSync2(installDir, { recursive: true });
1131
970
  }
1132
- const targetPath = join4(installDir, skillName);
1133
- if (existsSync3(targetPath)) {
971
+ const targetPath = join3(installDir, skillName);
972
+ if (existsSync2(targetPath)) {
1134
973
  rmSync2(targetPath, { recursive: true, force: true });
1135
974
  }
1136
975
  cpSync2(skill.path, targetPath, { recursive: true, dereference: true });
@@ -1334,8 +1173,8 @@ function Recommend({ rows = 24 }) {
1334
1173
 
1335
1174
  // src/screens/Translate.tsx
1336
1175
  import { useState as useState10, useEffect as useEffect6 } from "react";
1337
- import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync4 } from "fs";
1338
- import { join as join5 } from "path";
1176
+ import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
1177
+ import { join as join4 } from "path";
1339
1178
  import { Box as Box8, Text as Text8, useInput as useInput6 } from "ink";
1340
1179
  import {
1341
1180
  translateSkill,
@@ -1357,13 +1196,13 @@ function Translate({ rows = 24 }) {
1357
1196
  const loadSkills = () => {
1358
1197
  const installDir = getInstallDir(false);
1359
1198
  const foundSkills = [];
1360
- if (existsSync4(installDir)) {
1199
+ if (existsSync3(installDir)) {
1361
1200
  const dirs = readdirSync(installDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
1362
1201
  for (const dir of dirs) {
1363
- const skillPath = join5(installDir, dir);
1364
- const skillMdPath = join5(skillPath, "SKILL.md");
1365
- if (existsSync4(skillMdPath)) {
1366
- const content = readFileSync3(skillMdPath, "utf-8");
1202
+ const skillPath = join4(installDir, dir);
1203
+ const skillMdPath = join4(skillPath, "SKILL.md");
1204
+ if (existsSync3(skillMdPath)) {
1205
+ const content = readFileSync2(skillMdPath, "utf-8");
1367
1206
  foundSkills.push({
1368
1207
  name: dir,
1369
1208
  path: skillPath,
@@ -1413,13 +1252,13 @@ function Translate({ rows = 24 }) {
1413
1252
  return;
1414
1253
  }
1415
1254
  const adapter = getAdapter4(selectedAgent.type);
1416
- const targetDir = adapter?.skillsDir ? join5(process.cwd(), adapter.skillsDir) : join5(process.cwd(), `.${selectedAgent.type}/skills/`);
1417
- if (!existsSync4(targetDir)) {
1418
- mkdirSync4(targetDir, { recursive: true });
1255
+ const targetDir = adapter?.skillsDir ? join4(process.cwd(), adapter.skillsDir) : join4(process.cwd(), `.${selectedAgent.type}/skills/`);
1256
+ if (!existsSync3(targetDir)) {
1257
+ mkdirSync3(targetDir, { recursive: true });
1419
1258
  }
1420
1259
  const filename = translationResult.filename || `${selectedSkill.name}.md`;
1421
- const targetPath = join5(targetDir, filename);
1422
- writeFileSync2(targetPath, translationResult.content, "utf-8");
1260
+ const targetPath = join4(targetDir, filename);
1261
+ writeFileSync(targetPath, translationResult.content, "utf-8");
1423
1262
  setResult({
1424
1263
  success: true,
1425
1264
  message: `Translated ${selectedSkill.name} to ${selectedAgent.name} format`,
@@ -1812,16 +1651,780 @@ function Context({ rows = 24 }) {
1812
1651
  ] });
1813
1652
  }
1814
1653
 
1815
- // src/App.tsx
1654
+ // src/screens/Workflow.tsx
1655
+ import { useState as useState12, useEffect as useEffect8 } from "react";
1656
+ import { Box as Box10, Text as Text10, useInput as useInput8 } from "ink";
1657
+ import { listWorkflows } from "@skillkit/core";
1816
1658
  import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1659
+ function Workflow({ rows = 24 }) {
1660
+ const [workflows, setWorkflows] = useState12([]);
1661
+ const [loading, setLoading] = useState12(true);
1662
+ const [sel, setSel] = useState12(0);
1663
+ const [running, setRunning] = useState12(null);
1664
+ const [error, setError] = useState12(null);
1665
+ const maxVisible = Math.max(5, rows - 8);
1666
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), workflows.length - maxVisible));
1667
+ const visible = workflows.slice(start, start + maxVisible);
1668
+ useEffect8(() => {
1669
+ loadWorkflows();
1670
+ }, []);
1671
+ const loadWorkflows = () => {
1672
+ setLoading(true);
1673
+ setError(null);
1674
+ try {
1675
+ const wfs = listWorkflows(process.cwd());
1676
+ setWorkflows(wfs);
1677
+ } catch (e) {
1678
+ setError(e instanceof Error ? e.message : "Failed to load workflows");
1679
+ }
1680
+ setLoading(false);
1681
+ };
1682
+ useInput8((input, key) => {
1683
+ if (loading || running) return;
1684
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
1685
+ else if (key.downArrow) setSel((i) => Math.min(workflows.length - 1, i + 1));
1686
+ else if (input === "r") loadWorkflows();
1687
+ else if (key.return && workflows[sel]) {
1688
+ setRunning(workflows[sel].name);
1689
+ setTimeout(() => setRunning(null), 2e3);
1690
+ }
1691
+ });
1692
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
1693
+ /* @__PURE__ */ jsx10(Text10, { bold: true, color: colors.primary, children: "WORKFLOWS" }),
1694
+ /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
1695
+ workflows.length,
1696
+ " workflow(s) found"
1697
+ ] }),
1698
+ loading && /* @__PURE__ */ jsx10(Text10, { children: "Loading workflows..." }),
1699
+ error && /* @__PURE__ */ jsx10(Text10, { color: "red", children: error }),
1700
+ running && /* @__PURE__ */ jsxs10(Text10, { color: "yellow", children: [
1701
+ "Running: ",
1702
+ running,
1703
+ "..."
1704
+ ] }),
1705
+ !loading && !running && workflows.length === 0 && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
1706
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "No workflows found." }),
1707
+ /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Create one with: skillkit workflow create" })
1708
+ ] }),
1709
+ !loading && !running && workflows.length > 0 && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
1710
+ start > 0 && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
1711
+ " \u2191 ",
1712
+ start,
1713
+ " more"
1714
+ ] }),
1715
+ visible.map((wf, i) => {
1716
+ const idx = start + i;
1717
+ const isSel = idx === sel;
1718
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
1719
+ /* @__PURE__ */ jsxs10(Text10, { inverse: isSel, children: [
1720
+ isSel ? symbols.pointer : " ",
1721
+ " ",
1722
+ wf.name
1723
+ ] }),
1724
+ isSel && wf.description && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
1725
+ " ",
1726
+ wf.description
1727
+ ] }),
1728
+ isSel && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
1729
+ " ",
1730
+ wf.waves.length,
1731
+ " wave(s), ",
1732
+ wf.waves.reduce((acc, w) => acc + w.skills.length, 0),
1733
+ " skill(s)"
1734
+ ] })
1735
+ ] }, wf.name);
1736
+ }),
1737
+ start + maxVisible < workflows.length && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
1738
+ " \u2193 ",
1739
+ workflows.length - start - maxVisible,
1740
+ " more"
1741
+ ] })
1742
+ ] }),
1743
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "Enter=run r=refresh q=quit" }) })
1744
+ ] });
1745
+ }
1746
+
1747
+ // src/screens/Execute.tsx
1748
+ import { useState as useState13, useEffect as useEffect9 } from "react";
1749
+ import { Box as Box11, Text as Text11, useInput as useInput9 } from "ink";
1750
+ import { createSessionManager } from "@skillkit/core";
1751
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1752
+ function Execute({ rows = 24 }) {
1753
+ const [session, setSession] = useState13(null);
1754
+ const [loading, setLoading] = useState13(true);
1755
+ const maxVisible = Math.max(5, rows - 10);
1756
+ useEffect9(() => {
1757
+ loadSession();
1758
+ const interval = setInterval(loadSession, 1e3);
1759
+ return () => clearInterval(interval);
1760
+ }, []);
1761
+ const loadSession = () => {
1762
+ try {
1763
+ const manager = createSessionManager(process.cwd());
1764
+ const state = manager.get();
1765
+ setSession(state);
1766
+ } catch {
1767
+ setSession(null);
1768
+ }
1769
+ setLoading(false);
1770
+ };
1771
+ useInput9((input, _key) => {
1772
+ if (input === "r") loadSession();
1773
+ else if (input === "p" && session?.currentExecution?.status === "running") {
1774
+ const manager = createSessionManager(process.cwd());
1775
+ manager.pause();
1776
+ loadSession();
1777
+ } else if (input === "c" && session?.currentExecution?.status === "paused") {
1778
+ const manager = createSessionManager(process.cwd());
1779
+ manager.resume();
1780
+ loadSession();
1781
+ }
1782
+ });
1783
+ const renderExecution = (exec) => {
1784
+ const completedTasks = exec.tasks.filter((t) => t.status === "completed").length;
1785
+ const failedTasks = exec.tasks.filter((t) => t.status === "failed").length;
1786
+ const progress = exec.totalSteps > 0 ? Math.round(completedTasks / exec.totalSteps * 100) : 0;
1787
+ const statusColor = exec.status === "running" ? "yellow" : exec.status === "completed" ? "green" : exec.status === "paused" ? "blue" : exec.status === "failed" ? "red" : "white";
1788
+ const visibleTasks = exec.tasks.slice(0, maxVisible);
1789
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
1790
+ /* @__PURE__ */ jsx11(Text11, { bold: true, children: exec.skillName }),
1791
+ /* @__PURE__ */ jsxs11(Text11, { children: [
1792
+ "Source: ",
1793
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: exec.skillSource })
1794
+ ] }),
1795
+ /* @__PURE__ */ jsxs11(Text11, { children: [
1796
+ "Status: ",
1797
+ /* @__PURE__ */ jsx11(Text11, { color: statusColor, children: exec.status.toUpperCase() })
1798
+ ] }),
1799
+ /* @__PURE__ */ jsxs11(Text11, { children: [
1800
+ "Progress: ",
1801
+ completedTasks,
1802
+ "/",
1803
+ exec.totalSteps,
1804
+ " (",
1805
+ progress,
1806
+ "%)"
1807
+ ] }),
1808
+ /* @__PURE__ */ jsxs11(Box11, { marginY: 1, children: [
1809
+ /* @__PURE__ */ jsx11(Text11, { children: "[" }),
1810
+ /* @__PURE__ */ jsx11(Text11, { color: "green", children: "\u2588".repeat(Math.floor(progress / 5)) }),
1811
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2591".repeat(20 - Math.floor(progress / 5)) }),
1812
+ /* @__PURE__ */ jsx11(Text11, { children: "]" })
1813
+ ] }),
1814
+ /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Tasks:" }),
1815
+ visibleTasks.map((task, i) => {
1816
+ 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;
1817
+ const color = task.status === "completed" ? "green" : task.status === "failed" ? "red" : task.status === "in_progress" ? "yellow" : task.status === "paused" ? "blue" : "white";
1818
+ return /* @__PURE__ */ jsxs11(Text11, { color, children: [
1819
+ icon,
1820
+ " ",
1821
+ task.name,
1822
+ " ",
1823
+ task.error && /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
1824
+ "(",
1825
+ task.error,
1826
+ ")"
1827
+ ] })
1828
+ ] }, task.id || i);
1829
+ }),
1830
+ exec.tasks.length > maxVisible && /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
1831
+ " ... and ",
1832
+ exec.tasks.length - maxVisible,
1833
+ " more"
1834
+ ] }),
1835
+ failedTasks > 0 && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { color: "red", children: [
1836
+ failedTasks,
1837
+ " task(s) failed"
1838
+ ] }) })
1839
+ ] });
1840
+ };
1841
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
1842
+ /* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: "EXECUTION MONITOR" }),
1843
+ loading && /* @__PURE__ */ jsx11(Text11, { children: "Loading session..." }),
1844
+ !loading && !session?.currentExecution && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
1845
+ /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "No active execution." }),
1846
+ /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
1847
+ "Run a skill with: skillkit run ",
1848
+ "<skill>"
1849
+ ] })
1850
+ ] }),
1851
+ !loading && session?.currentExecution && renderExecution(session.currentExecution),
1852
+ /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
1853
+ session?.currentExecution?.status === "running" ? "p=pause " : "",
1854
+ session?.currentExecution?.status === "paused" ? "c=continue " : "",
1855
+ "r=refresh q=quit"
1856
+ ] }) })
1857
+ ] });
1858
+ }
1859
+
1860
+ // src/screens/History.tsx
1861
+ import { useState as useState14, useEffect as useEffect10 } from "react";
1862
+ import { Box as Box12, Text as Text12, useInput as useInput10 } from "ink";
1863
+ import { createSessionManager as createSessionManager2 } from "@skillkit/core";
1864
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1865
+ function History({ rows = 24 }) {
1866
+ const [history, setHistory] = useState14([]);
1867
+ const [loading, setLoading] = useState14(true);
1868
+ const [sel, setSel] = useState14(0);
1869
+ const [expanded, setExpanded] = useState14(false);
1870
+ const maxVisible = Math.max(5, rows - 8);
1871
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), history.length - maxVisible));
1872
+ const visible = history.slice(start, start + maxVisible);
1873
+ useEffect10(() => {
1874
+ loadHistory();
1875
+ }, []);
1876
+ const loadHistory = () => {
1877
+ setLoading(true);
1878
+ try {
1879
+ const manager = createSessionManager2(process.cwd());
1880
+ const h = manager.getHistory(50);
1881
+ setHistory(h);
1882
+ } catch {
1883
+ setHistory([]);
1884
+ }
1885
+ setLoading(false);
1886
+ };
1887
+ useInput10((input, key) => {
1888
+ if (loading) return;
1889
+ if (key.upArrow) {
1890
+ setSel((i) => Math.max(0, i - 1));
1891
+ setExpanded(false);
1892
+ } else if (key.downArrow) {
1893
+ setSel((i) => Math.min(history.length - 1, i + 1));
1894
+ setExpanded(false);
1895
+ } else if (input === "r") loadHistory();
1896
+ else if (key.return) setExpanded((e) => !e);
1897
+ });
1898
+ const formatDuration = (ms) => {
1899
+ if (ms < 1e3) return `${ms}ms`;
1900
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
1901
+ return `${(ms / 6e4).toFixed(1)}m`;
1902
+ };
1903
+ const formatDate = (iso) => {
1904
+ const d = new Date(iso);
1905
+ const now = /* @__PURE__ */ new Date();
1906
+ const diff = now.getTime() - d.getTime();
1907
+ if (diff < 6e4) return "Just now";
1908
+ if (diff < 36e5) return `${Math.floor(diff / 6e4)}m ago`;
1909
+ if (diff < 864e5) return `${Math.floor(diff / 36e5)}h ago`;
1910
+ return d.toLocaleDateString();
1911
+ };
1912
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1913
+ /* @__PURE__ */ jsx12(Text12, { bold: true, color: colors.primary, children: "EXECUTION HISTORY" }),
1914
+ /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1915
+ history.length,
1916
+ " execution(s)"
1917
+ ] }),
1918
+ loading && /* @__PURE__ */ jsx12(Text12, { children: "Loading history..." }),
1919
+ !loading && history.length === 0 && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
1920
+ /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "No execution history." }),
1921
+ /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1922
+ "Run a skill with: skillkit run ",
1923
+ "<skill>"
1924
+ ] })
1925
+ ] }),
1926
+ !loading && history.length > 0 && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
1927
+ start > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1928
+ " \u2191 ",
1929
+ start,
1930
+ " more"
1931
+ ] }),
1932
+ visible.map((entry, i) => {
1933
+ const idx = start + i;
1934
+ const isSel = idx === sel;
1935
+ const icon = entry.status === "completed" ? symbols.success : entry.status === "failed" ? symbols.error : symbols.warning;
1936
+ const color = entry.status === "completed" ? "green" : entry.status === "failed" ? "red" : "yellow";
1937
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1938
+ /* @__PURE__ */ jsxs12(Text12, { inverse: isSel, children: [
1939
+ isSel ? symbols.pointer : " ",
1940
+ /* @__PURE__ */ jsx12(Text12, { color, children: icon }),
1941
+ " ",
1942
+ entry.skillName.padEnd(25),
1943
+ " ",
1944
+ formatDate(entry.completedAt).padEnd(12),
1945
+ " ",
1946
+ formatDuration(entry.durationMs)
1947
+ ] }),
1948
+ isSel && expanded && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginLeft: 3, children: [
1949
+ /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1950
+ "Source: ",
1951
+ entry.skillSource
1952
+ ] }),
1953
+ /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1954
+ "Status: ",
1955
+ entry.status
1956
+ ] }),
1957
+ entry.commits.length > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1958
+ "Commits: ",
1959
+ entry.commits.join(", ")
1960
+ ] }),
1961
+ entry.filesModified.length > 0 && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1962
+ "Files: ",
1963
+ entry.filesModified.length,
1964
+ " modified"
1965
+ ] }),
1966
+ entry.error && /* @__PURE__ */ jsxs12(Text12, { color: "red", children: [
1967
+ "Error: ",
1968
+ entry.error
1969
+ ] })
1970
+ ] })
1971
+ ] }, idx);
1972
+ }),
1973
+ start + maxVisible < history.length && /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
1974
+ " \u2193 ",
1975
+ history.length - start - maxVisible,
1976
+ " more"
1977
+ ] })
1978
+ ] }),
1979
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Enter=expand r=refresh q=quit" }) })
1980
+ ] });
1981
+ }
1982
+
1983
+ // src/screens/Marketplace.tsx
1984
+ import { useState as useState15, useEffect as useEffect11 } from "react";
1985
+ import { Box as Box13, Text as Text13, useInput as useInput11 } from "ink";
1986
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1987
+ var SKILL_SOURCES = [
1988
+ { owner: "composioHQ", repo: "awesome-claude-code-skills", name: "Composio Curated" },
1989
+ { owner: "anthropics", repo: "courses", name: "Anthropic Official" }
1990
+ ];
1991
+ function Marketplace({ rows = 24 }) {
1992
+ const [skills, setSkills] = useState15([]);
1993
+ const [loading, setLoading] = useState15(true);
1994
+ const [error, setError] = useState15(null);
1995
+ const [sel, setSel] = useState15(0);
1996
+ const [search, setSearch] = useState15("");
1997
+ const [installing, setInstalling] = useState15(null);
1998
+ const filtered = skills.filter(
1999
+ (s) => s.name.toLowerCase().includes(search.toLowerCase()) || s.description.toLowerCase().includes(search.toLowerCase()) || s.tags?.some((t) => t.toLowerCase().includes(search.toLowerCase()))
2000
+ );
2001
+ const maxVisible = Math.max(5, rows - 10);
2002
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), filtered.length - maxVisible));
2003
+ const visible = filtered.slice(start, start + maxVisible);
2004
+ useEffect11(() => {
2005
+ loadMarketplace();
2006
+ }, []);
2007
+ const loadMarketplace = async () => {
2008
+ setLoading(true);
2009
+ setError(null);
2010
+ try {
2011
+ const allSkills = [];
2012
+ for (const source of SKILL_SOURCES) {
2013
+ try {
2014
+ const indexUrl = `https://raw.githubusercontent.com/${source.owner}/${source.repo}/main/skills.json`;
2015
+ const response = await fetch(indexUrl);
2016
+ if (response.ok) {
2017
+ const data = await response.json();
2018
+ if (Array.isArray(data)) {
2019
+ allSkills.push(...data.map((s) => ({
2020
+ name: String(s.name || "Unknown"),
2021
+ description: String(s.description || ""),
2022
+ source: source.name,
2023
+ repo: `${source.owner}/${source.repo}`,
2024
+ tags: Array.isArray(s.tags) ? s.tags : [],
2025
+ stars: typeof s.stars === "number" ? s.stars : void 0
2026
+ })));
2027
+ }
2028
+ } else {
2029
+ allSkills.push({
2030
+ name: source.repo,
2031
+ description: `Skills from ${source.name}`,
2032
+ source: source.name,
2033
+ repo: `${source.owner}/${source.repo}`
2034
+ });
2035
+ }
2036
+ } catch {
2037
+ allSkills.push({
2038
+ name: source.repo,
2039
+ description: `Skills from ${source.name}`,
2040
+ source: source.name,
2041
+ repo: `${source.owner}/${source.repo}`
2042
+ });
2043
+ }
2044
+ }
2045
+ if (allSkills.length === 0) {
2046
+ allSkills.push(
2047
+ { name: "typescript-strict", description: "Enable strict TypeScript mode", source: "Built-in", repo: "skillkit/skills", tags: ["typescript", "config"] },
2048
+ { name: "eslint-setup", description: "Set up ESLint with recommended rules", source: "Built-in", repo: "skillkit/skills", tags: ["eslint", "linting"] },
2049
+ { name: "prettier-config", description: "Configure Prettier formatting", source: "Built-in", repo: "skillkit/skills", tags: ["prettier", "formatting"] },
2050
+ { name: "jest-setup", description: "Set up Jest testing framework", source: "Built-in", repo: "skillkit/skills", tags: ["jest", "testing"] },
2051
+ { name: "nextjs-auth", description: "Add authentication to Next.js", source: "Community", repo: "community/skills", tags: ["nextjs", "auth"] }
2052
+ );
2053
+ }
2054
+ setSkills(allSkills);
2055
+ } catch (e) {
2056
+ setError(e instanceof Error ? e.message : "Failed to load marketplace");
2057
+ }
2058
+ setLoading(false);
2059
+ };
2060
+ useInput11((input, key) => {
2061
+ if (loading || installing) return;
2062
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
2063
+ else if (key.downArrow) setSel((i) => Math.min(filtered.length - 1, i + 1));
2064
+ else if (input === "r") loadMarketplace();
2065
+ else if (input === "/") setSearch("");
2066
+ else if (key.backspace || key.delete) setSearch((s) => s.slice(0, -1));
2067
+ else if (key.return && filtered[sel]) {
2068
+ setInstalling(filtered[sel].name);
2069
+ setTimeout(() => setInstalling(null), 1500);
2070
+ } else if (input.length === 1 && /[a-zA-Z0-9-_]/.test(input)) {
2071
+ setSearch((s) => s + input);
2072
+ setSel(0);
2073
+ }
2074
+ });
2075
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
2076
+ /* @__PURE__ */ jsx13(Text13, { bold: true, color: colors.primary, children: "SKILL MARKETPLACE" }),
2077
+ /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2078
+ skills.length,
2079
+ " skills from ",
2080
+ SKILL_SOURCES.length,
2081
+ " sources"
2082
+ ] }),
2083
+ search && /* @__PURE__ */ jsxs13(Text13, { children: [
2084
+ "Search: ",
2085
+ /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: search }),
2086
+ " (",
2087
+ filtered.length,
2088
+ " results)"
2089
+ ] }),
2090
+ loading && /* @__PURE__ */ jsx13(Text13, { children: "Loading marketplace..." }),
2091
+ error && /* @__PURE__ */ jsx13(Text13, { color: "red", children: error }),
2092
+ installing && /* @__PURE__ */ jsxs13(Text13, { color: "yellow", children: [
2093
+ "Installing ",
2094
+ installing,
2095
+ "..."
2096
+ ] }),
2097
+ !loading && !installing && filtered.length === 0 && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2098
+ "No skills found",
2099
+ search ? ` matching "${search}"` : "",
2100
+ "."
2101
+ ] }) }),
2102
+ !loading && !installing && filtered.length > 0 && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
2103
+ start > 0 && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2104
+ " \u2191 ",
2105
+ start,
2106
+ " more"
2107
+ ] }),
2108
+ visible.map((skill, i) => {
2109
+ const idx = start + i;
2110
+ const isSel = idx === sel;
2111
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
2112
+ /* @__PURE__ */ jsxs13(Text13, { inverse: isSel, children: [
2113
+ isSel ? symbols.pointer : " ",
2114
+ " ",
2115
+ skill.name.padEnd(25),
2116
+ " ",
2117
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: skill.source })
2118
+ ] }),
2119
+ isSel && /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginLeft: 3, children: [
2120
+ /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: skill.description }),
2121
+ skill.tags && skill.tags.length > 0 && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2122
+ "Tags: ",
2123
+ skill.tags.join(", ")
2124
+ ] }),
2125
+ /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2126
+ "Repo: ",
2127
+ skill.repo
2128
+ ] })
2129
+ ] })
2130
+ ] }, `${skill.repo}/${skill.name}`);
2131
+ }),
2132
+ start + maxVisible < filtered.length && /* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
2133
+ " \u2193 ",
2134
+ filtered.length - start - maxVisible,
2135
+ " more"
2136
+ ] })
2137
+ ] }),
2138
+ /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Enter=install type=search r=refresh q=quit" }) })
2139
+ ] });
2140
+ }
2141
+
2142
+ // src/screens/Memory.tsx
2143
+ import { useState as useState16, useEffect as useEffect12 } from "react";
2144
+ import { Box as Box14, Text as Text14, useInput as useInput12 } from "ink";
2145
+ import {
2146
+ ObservationStore,
2147
+ LearningStore,
2148
+ getMemoryStatus,
2149
+ getMemoryPaths,
2150
+ createMemoryInjector
2151
+ } from "@skillkit/core";
2152
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2153
+ function Memory({ rows = 24 }) {
2154
+ const [tab, setTab] = useState16("learnings");
2155
+ const [learnings, setLearnings] = useState16([]);
2156
+ const [observationCount, setObservationCount] = useState16(0);
2157
+ const [globalCount, setGlobalCount] = useState16(0);
2158
+ const [loading, setLoading] = useState16(true);
2159
+ const [sel, setSel] = useState16(0);
2160
+ const [expanded, setExpanded] = useState16(false);
2161
+ const [searchQuery, setSearchQuery] = useState16("");
2162
+ const [searchResults, setSearchResults] = useState16([]);
2163
+ const [isGlobal, setIsGlobal] = useState16(false);
2164
+ const maxVisible = Math.max(5, rows - 10);
2165
+ const currentList = tab === "search" ? searchResults : learnings;
2166
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), currentList.length - maxVisible));
2167
+ const visible = currentList.slice(start, start + maxVisible);
2168
+ useEffect12(() => {
2169
+ loadMemory();
2170
+ }, [isGlobal]);
2171
+ const loadMemory = () => {
2172
+ setLoading(true);
2173
+ try {
2174
+ const projectPath = process.cwd();
2175
+ const status = getMemoryStatus(projectPath);
2176
+ const store = new LearningStore(
2177
+ isGlobal ? "global" : "project",
2178
+ isGlobal ? void 0 : projectPath
2179
+ );
2180
+ setLearnings(store.getAll());
2181
+ if (status.hasObservations) {
2182
+ const obsStore = new ObservationStore(projectPath);
2183
+ setObservationCount(obsStore.count());
2184
+ } else {
2185
+ setObservationCount(0);
2186
+ }
2187
+ if (status.hasGlobalLearnings) {
2188
+ const globalStore = new LearningStore("global");
2189
+ setGlobalCount(globalStore.count());
2190
+ } else {
2191
+ setGlobalCount(0);
2192
+ }
2193
+ } catch {
2194
+ setLearnings([]);
2195
+ setObservationCount(0);
2196
+ setGlobalCount(0);
2197
+ }
2198
+ setLoading(false);
2199
+ };
2200
+ const handleSearch = (query) => {
2201
+ if (!query.trim()) {
2202
+ setSearchResults([]);
2203
+ return;
2204
+ }
2205
+ try {
2206
+ const projectPath = process.cwd();
2207
+ const injector = createMemoryInjector(projectPath);
2208
+ const results = injector.search(query, {
2209
+ includeGlobal: true,
2210
+ maxLearnings: 20,
2211
+ minRelevance: 0
2212
+ });
2213
+ setSearchResults(results.map((r) => r.learning));
2214
+ } catch {
2215
+ setSearchResults([]);
2216
+ }
2217
+ };
2218
+ useInput12((input, key) => {
2219
+ if (loading) return;
2220
+ if (input === "1") {
2221
+ setTab("learnings");
2222
+ setSel(0);
2223
+ setExpanded(false);
2224
+ } else if (input === "2") {
2225
+ setTab("observations");
2226
+ setSel(0);
2227
+ setExpanded(false);
2228
+ } else if (input === "3") {
2229
+ setTab("search");
2230
+ setSel(0);
2231
+ setExpanded(false);
2232
+ } else if (key.upArrow) {
2233
+ setSel((i) => Math.max(0, i - 1));
2234
+ setExpanded(false);
2235
+ } else if (key.downArrow) {
2236
+ setSel((i) => Math.min(currentList.length - 1, i + 1));
2237
+ setExpanded(false);
2238
+ } else if (input === "f") loadMemory();
2239
+ else if (input === "g") setIsGlobal((g) => !g);
2240
+ else if (key.return) setExpanded((e) => !e);
2241
+ else if (tab === "search" && input && input.length === 1 && !key.ctrl && !key.meta) {
2242
+ const newQuery = searchQuery + input;
2243
+ setSearchQuery(newQuery);
2244
+ handleSearch(newQuery);
2245
+ } else if (tab === "search" && key.backspace) {
2246
+ const newQuery = searchQuery.slice(0, -1);
2247
+ setSearchQuery(newQuery);
2248
+ handleSearch(newQuery);
2249
+ }
2250
+ });
2251
+ const ONE_MINUTE = 6e4;
2252
+ const ONE_HOUR = 36e5;
2253
+ const ONE_DAY = 864e5;
2254
+ function formatDate(iso) {
2255
+ const d = new Date(iso);
2256
+ const diff = Date.now() - d.getTime();
2257
+ if (diff < ONE_MINUTE) return "Just now";
2258
+ if (diff < ONE_HOUR) return `${Math.floor(diff / ONE_MINUTE)}m ago`;
2259
+ if (diff < ONE_DAY) return `${Math.floor(diff / ONE_HOUR)}h ago`;
2260
+ return d.toLocaleDateString();
2261
+ }
2262
+ function formatEffectiveness(eff) {
2263
+ if (eff === void 0) return " -";
2264
+ return eff.toString().padStart(3) + "%";
2265
+ }
2266
+ function getEffectivenessColor(eff) {
2267
+ if (eff === void 0) return void 0;
2268
+ if (eff >= 70) return "green";
2269
+ if (eff >= 40) return "yellow";
2270
+ return "red";
2271
+ }
2272
+ const renderLearnings = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
2273
+ currentList.length === 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
2274
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "No learnings found." }),
2275
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Run skills to capture learnings, or add manually:" }),
2276
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ' skillkit memory add --title "..." --content "..."' })
2277
+ ] }),
2278
+ currentList.length > 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
2279
+ start > 0 && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2280
+ " ",
2281
+ symbols.arrowUp,
2282
+ " ",
2283
+ start,
2284
+ " more"
2285
+ ] }),
2286
+ visible.map((learning, i) => {
2287
+ const idx = start + i;
2288
+ const isSel = idx === sel;
2289
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
2290
+ /* @__PURE__ */ jsxs14(Text14, { inverse: isSel, children: [
2291
+ isSel ? symbols.pointer : " ",
2292
+ /* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: symbols.bullet }),
2293
+ " ",
2294
+ learning.title.slice(0, 35).padEnd(35),
2295
+ " ",
2296
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: learning.tags.slice(0, 2).join(", ").slice(0, 15).padEnd(15) }),
2297
+ " ",
2298
+ /* @__PURE__ */ jsx14(Text14, { color: getEffectivenessColor(learning.effectiveness), children: formatEffectiveness(learning.effectiveness) }),
2299
+ " ",
2300
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: formatDate(learning.updatedAt) })
2301
+ ] }),
2302
+ isSel && expanded && /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginLeft: 3, marginY: 1, children: [
2303
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2304
+ "ID: ",
2305
+ learning.id.slice(0, 8)
2306
+ ] }),
2307
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2308
+ "Scope: ",
2309
+ learning.scope
2310
+ ] }),
2311
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2312
+ "Source: ",
2313
+ learning.source
2314
+ ] }),
2315
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2316
+ "Tags: ",
2317
+ learning.tags.join(", ")
2318
+ ] }),
2319
+ learning.frameworks && learning.frameworks.length > 0 && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2320
+ "Frameworks: ",
2321
+ learning.frameworks.join(", ")
2322
+ ] }),
2323
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2324
+ "Uses: ",
2325
+ learning.useCount
2326
+ ] }),
2327
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { wrap: "wrap", children: [
2328
+ learning.content.slice(0, 300),
2329
+ learning.content.length > 300 ? "..." : ""
2330
+ ] }) })
2331
+ ] })
2332
+ ] }, learning.id);
2333
+ }),
2334
+ start + maxVisible < currentList.length && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2335
+ " ",
2336
+ symbols.arrowDown,
2337
+ " ",
2338
+ currentList.length - start - maxVisible,
2339
+ " more"
2340
+ ] })
2341
+ ] })
2342
+ ] });
2343
+ const renderObservations = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
2344
+ /* @__PURE__ */ jsxs14(Text14, { children: [
2345
+ "Session Observations: ",
2346
+ /* @__PURE__ */ jsx14(Text14, { bold: true, color: colors.primary, children: observationCount })
2347
+ ] }),
2348
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Observations are raw captures from skill execution." }),
2349
+ observationCount > 0 && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
2350
+ /* @__PURE__ */ jsx14(Text14, { children: "Compress observations into learnings:" }),
2351
+ /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " skillkit memory compress" })
2352
+ ] }),
2353
+ observationCount >= 50 && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { color: "yellow", children: [
2354
+ symbols.warning,
2355
+ " You have many uncompressed observations."
2356
+ ] }) }),
2357
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Observations are stored at:" }) }),
2358
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2359
+ " ",
2360
+ getMemoryPaths(process.cwd()).observationsFile
2361
+ ] })
2362
+ ] });
2363
+ const renderSearch = () => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
2364
+ /* @__PURE__ */ jsxs14(Box14, { children: [
2365
+ /* @__PURE__ */ jsx14(Text14, { children: "Search: " }),
2366
+ /* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: searchQuery }),
2367
+ /* @__PURE__ */ jsx14(Text14, { color: colors.secondary, children: "_" })
2368
+ ] }),
2369
+ searchQuery && searchResults.length === 0 && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2370
+ 'No results found for "',
2371
+ searchQuery,
2372
+ '"'
2373
+ ] }) }),
2374
+ searchResults.length > 0 && renderLearnings()
2375
+ ] });
2376
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
2377
+ /* @__PURE__ */ jsx14(Text14, { bold: true, color: colors.primary, children: "MEMORY" }),
2378
+ /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
2379
+ isGlobal ? "Global" : "Project",
2380
+ ": ",
2381
+ learnings.length,
2382
+ " learning(s)",
2383
+ !isGlobal && globalCount > 0 && /* @__PURE__ */ jsxs14(Text14, { children: [
2384
+ " | Global: ",
2385
+ globalCount
2386
+ ] })
2387
+ ] }),
2388
+ /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
2389
+ /* @__PURE__ */ jsx14(Text14, { inverse: tab === "learnings", children: "[1] Learnings" }),
2390
+ /* @__PURE__ */ jsx14(Text14, { children: " " }),
2391
+ /* @__PURE__ */ jsx14(Text14, { inverse: tab === "observations", children: "[2] Observations" }),
2392
+ /* @__PURE__ */ jsx14(Text14, { children: " " }),
2393
+ /* @__PURE__ */ jsx14(Text14, { inverse: tab === "search", children: "[3] Search" })
2394
+ ] }),
2395
+ loading && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { children: "Loading..." }) }),
2396
+ !loading && tab === "learnings" && renderLearnings(),
2397
+ !loading && tab === "observations" && renderObservations(),
2398
+ !loading && tab === "search" && renderSearch(),
2399
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Enter=expand g=toggle global f=refresh 1-3=tabs" }) })
2400
+ ] });
2401
+ }
2402
+
2403
+ // src/App.tsx
2404
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1817
2405
  function App() {
1818
- const [screen, setScreen] = useState12("home");
2406
+ const [screen, setScreen] = useState17("home");
1819
2407
  const { exit } = useApp();
1820
2408
  const { stdout } = useStdout();
1821
2409
  const cols = stdout?.columns || 80;
1822
2410
  const rows = stdout?.rows || 24;
1823
2411
  const showSidebar = cols >= 70;
1824
- useInput8((input, key) => {
2412
+ const NAV_KEYS = {
2413
+ h: "home",
2414
+ m: "marketplace",
2415
+ b: "browse",
2416
+ w: "workflow",
2417
+ x: "execute",
2418
+ y: "history",
2419
+ r: "recommend",
2420
+ t: "translate",
2421
+ c: "context",
2422
+ e: "memory",
2423
+ i: "installed",
2424
+ s: "sync",
2425
+ ",": "settings"
2426
+ };
2427
+ useInput13((input, key) => {
1825
2428
  if (input === "q") {
1826
2429
  exit();
1827
2430
  return;
@@ -1830,65 +2433,71 @@ function App() {
1830
2433
  setScreen("home");
1831
2434
  return;
1832
2435
  }
1833
- if (input === "h") setScreen("home");
1834
- if (input === "b") setScreen("browse");
1835
- if (input === "l") setScreen("installed");
1836
- if (input === "s") setScreen("sync");
1837
- if (input === ",") setScreen("settings");
1838
- if (input === "r") setScreen("recommend");
1839
- if (input === "t") setScreen("translate");
1840
- if (input === "c") setScreen("context");
2436
+ const targetScreen = NAV_KEYS[input];
2437
+ if (targetScreen) {
2438
+ setScreen(targetScreen);
2439
+ }
1841
2440
  });
1842
2441
  const renderScreen = () => {
1843
2442
  switch (screen) {
1844
2443
  case "home":
1845
- return /* @__PURE__ */ jsx10(Home, { onNavigate: setScreen, cols, rows });
2444
+ return /* @__PURE__ */ jsx15(Home, { onNavigate: setScreen, cols, rows });
1846
2445
  case "browse":
1847
- return /* @__PURE__ */ jsx10(Browse, { cols, rows });
2446
+ return /* @__PURE__ */ jsx15(Browse, { cols, rows });
1848
2447
  case "installed":
1849
- return /* @__PURE__ */ jsx10(Installed, { cols, rows });
2448
+ return /* @__PURE__ */ jsx15(Installed, { cols, rows });
1850
2449
  case "sync":
1851
- return /* @__PURE__ */ jsx10(Sync, { cols, rows });
2450
+ return /* @__PURE__ */ jsx15(Sync, { cols, rows });
1852
2451
  case "settings":
1853
- return /* @__PURE__ */ jsx10(Settings, { cols, rows });
2452
+ return /* @__PURE__ */ jsx15(Settings, { cols, rows });
1854
2453
  case "recommend":
1855
- return /* @__PURE__ */ jsx10(Recommend, { cols, rows });
2454
+ return /* @__PURE__ */ jsx15(Recommend, { cols, rows });
1856
2455
  case "translate":
1857
- return /* @__PURE__ */ jsx10(Translate, { cols, rows });
2456
+ return /* @__PURE__ */ jsx15(Translate, { cols, rows });
1858
2457
  case "context":
1859
- return /* @__PURE__ */ jsx10(Context, { cols, rows });
2458
+ return /* @__PURE__ */ jsx15(Context, { cols, rows });
2459
+ case "workflow":
2460
+ return /* @__PURE__ */ jsx15(Workflow, { cols, rows });
2461
+ case "execute":
2462
+ return /* @__PURE__ */ jsx15(Execute, { cols, rows });
2463
+ case "history":
2464
+ return /* @__PURE__ */ jsx15(History, { cols, rows });
2465
+ case "marketplace":
2466
+ return /* @__PURE__ */ jsx15(Marketplace, { cols, rows });
2467
+ case "memory":
2468
+ return /* @__PURE__ */ jsx15(Memory, { cols, rows });
1860
2469
  }
1861
2470
  };
1862
2471
  const contentHeight = rows - 2;
1863
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", height: rows, children: [
1864
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", height: contentHeight, children: [
1865
- showSidebar && /* @__PURE__ */ jsx10(Sidebar, { screen, onNavigate: setScreen }),
1866
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", flexGrow: 1, marginLeft: 1, children: renderScreen() })
2472
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", height: rows, children: [
2473
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "row", height: contentHeight, children: [
2474
+ showSidebar && /* @__PURE__ */ jsx15(Sidebar, { screen, onNavigate: setScreen }),
2475
+ /* @__PURE__ */ jsx15(Box15, { flexDirection: "column", flexGrow: 1, marginLeft: 1, children: renderScreen() })
1867
2476
  ] }),
1868
- /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "h Home b Browse r Rec t Trans c Ctx l List s Sync , Config q Quit" }) })
2477
+ /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "h Home m Market b Browse i Inst w Wflow x Exec y Hist r Rec t Trans c Ctx e Mem s Sync , Cfg q Quit" }) })
1869
2478
  ] });
1870
2479
  }
1871
2480
 
1872
2481
  // src/components/Header.tsx
1873
- import { Box as Box11, Text as Text11 } from "ink";
1874
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2482
+ import { Box as Box16, Text as Text16 } from "ink";
2483
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
1875
2484
  function Header({ title, subtitle, count }) {
1876
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginBottom: 1, children: [
1877
- /* @__PURE__ */ jsxs11(Box11, { justifyContent: "space-between", children: [
1878
- /* @__PURE__ */ jsx11(Text11, { color: colors.primary, bold: true, children: title.toUpperCase() }),
1879
- count !== void 0 && /* @__PURE__ */ jsxs11(Text11, { color: colors.secondaryDim, children: [
2485
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginBottom: 1, children: [
2486
+ /* @__PURE__ */ jsxs16(Box16, { justifyContent: "space-between", children: [
2487
+ /* @__PURE__ */ jsx16(Text16, { color: colors.primary, bold: true, children: title.toUpperCase() }),
2488
+ count !== void 0 && /* @__PURE__ */ jsxs16(Text16, { color: colors.secondaryDim, children: [
1880
2489
  symbols.star,
1881
2490
  " ",
1882
2491
  count
1883
2492
  ] })
1884
2493
  ] }),
1885
- subtitle && /* @__PURE__ */ jsx11(Text11, { color: colors.secondaryDim, dimColor: true, children: subtitle })
2494
+ subtitle && /* @__PURE__ */ jsx16(Text16, { color: colors.secondaryDim, dimColor: true, children: subtitle })
1886
2495
  ] });
1887
2496
  }
1888
2497
 
1889
2498
  // src/components/SkillList.tsx
1890
- import { Box as Box12, Text as Text12 } from "ink";
1891
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2499
+ import { Box as Box17, Text as Text17 } from "ink";
2500
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1892
2501
  function formatInstalls(count) {
1893
2502
  if (count >= 1e3) {
1894
2503
  return `${(count / 1e3).toFixed(1)}K`;
@@ -1904,13 +2513,13 @@ function SkillList({
1904
2513
  maxVisible = 10
1905
2514
  }) {
1906
2515
  if (skills.length === 0) {
1907
- return /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text12, { color: colors.secondaryDim, dimColor: true, children: "No skills found" }) });
2516
+ return /* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsx17(Text17, { color: colors.secondaryDim, dimColor: true, children: "No skills found" }) });
1908
2517
  }
1909
2518
  const startIndex = Math.max(0, selectedIndex - Math.floor(maxVisible / 2));
1910
2519
  const visibleSkills = skills.slice(startIndex, startIndex + maxVisible);
1911
2520
  const actualStartIndex = startIndex;
1912
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
1913
- showRank && /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.secondaryDim, children: [
2521
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
2522
+ showRank && /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs17(Text17, { color: colors.secondaryDim, children: [
1914
2523
  " # SKILL",
1915
2524
  showSource && " SOURCE",
1916
2525
  showInstalls && " INSTALLS"
@@ -1920,9 +2529,9 @@ function SkillList({
1920
2529
  const isSelected = realIndex === selectedIndex;
1921
2530
  const skillName = skill.name.padEnd(28).slice(0, 28);
1922
2531
  const sourceName = skill.source ? skill.source.slice(0, 25) : "";
1923
- return /* @__PURE__ */ jsxs12(Box12, { children: [
1924
- /* @__PURE__ */ jsxs12(
1925
- Text12,
2532
+ return /* @__PURE__ */ jsxs17(Box17, { children: [
2533
+ /* @__PURE__ */ jsxs17(
2534
+ Text17,
1926
2535
  {
1927
2536
  color: isSelected ? colors.primary : colors.secondary,
1928
2537
  bold: isSelected,
@@ -1935,14 +2544,14 @@ function SkillList({
1935
2544
  ]
1936
2545
  }
1937
2546
  ),
1938
- showSource && /* @__PURE__ */ jsxs12(Text12, { color: colors.secondaryDim, dimColor: !isSelected, children: [
2547
+ showSource && /* @__PURE__ */ jsxs17(Text17, { color: colors.secondaryDim, dimColor: !isSelected, children: [
1939
2548
  " ",
1940
2549
  sourceName
1941
2550
  ] }),
1942
- showInstalls && skill.installs !== void 0 && /* @__PURE__ */ jsx12(Text12, { color: colors.secondaryDim, children: formatInstalls(skill.installs).padStart(8) })
2551
+ showInstalls && skill.installs !== void 0 && /* @__PURE__ */ jsx17(Text17, { color: colors.secondaryDim, children: formatInstalls(skill.installs).padStart(8) })
1943
2552
  ] }, `${skill.source}-${skill.name}`);
1944
2553
  }),
1945
- skills.length > maxVisible && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text12, { color: colors.secondaryDim, dimColor: true, children: [
2554
+ skills.length > maxVisible && /* @__PURE__ */ jsx17(Box17, { marginTop: 1, children: /* @__PURE__ */ jsxs17(Text17, { color: colors.secondaryDim, dimColor: true, children: [
1946
2555
  "Showing ",
1947
2556
  startIndex + 1,
1948
2557
  "-",
@@ -1954,11 +2563,11 @@ function SkillList({
1954
2563
  }
1955
2564
 
1956
2565
  // src/components/StatusBar.tsx
1957
- import { Box as Box13, Text as Text13 } from "ink";
1958
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
2566
+ import { Box as Box18, Text as Text18 } from "ink";
2567
+ import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
1959
2568
  function StatusBar({ shortcuts, message }) {
1960
- return /* @__PURE__ */ jsxs13(
1961
- Box13,
2569
+ return /* @__PURE__ */ jsxs18(
2570
+ Box18,
1962
2571
  {
1963
2572
  borderStyle: "single",
1964
2573
  borderColor: colors.borderDim,
@@ -1969,11 +2578,11 @@ function StatusBar({ shortcuts, message }) {
1969
2578
  paddingX: 1,
1970
2579
  justifyContent: "space-between",
1971
2580
  children: [
1972
- /* @__PURE__ */ jsx13(Box13, { gap: 2, children: shortcuts.map((shortcut, idx) => /* @__PURE__ */ jsxs13(Box13, { gap: 1, children: [
1973
- /* @__PURE__ */ jsx13(Text13, { color: colors.primary, bold: true, children: shortcut.key }),
1974
- /* @__PURE__ */ jsx13(Text13, { color: colors.secondaryDim, children: shortcut.label })
2581
+ /* @__PURE__ */ jsx18(Box18, { gap: 2, children: shortcuts.map((shortcut, idx) => /* @__PURE__ */ jsxs18(Box18, { gap: 1, children: [
2582
+ /* @__PURE__ */ jsx18(Text18, { color: colors.primary, bold: true, children: shortcut.key }),
2583
+ /* @__PURE__ */ jsx18(Text18, { color: colors.secondaryDim, children: shortcut.label })
1975
2584
  ] }, idx)) }),
1976
- message && /* @__PURE__ */ jsxs13(Text13, { color: colors.success, children: [
2585
+ message && /* @__PURE__ */ jsxs18(Text18, { color: colors.success, children: [
1977
2586
  symbols.check,
1978
2587
  " ",
1979
2588
  message
@@ -1984,44 +2593,44 @@ function StatusBar({ shortcuts, message }) {
1984
2593
  }
1985
2594
 
1986
2595
  // src/components/SearchInput.tsx
1987
- import { Box as Box14, Text as Text14 } from "ink";
2596
+ import { Box as Box19, Text as Text19 } from "ink";
1988
2597
  import TextInput from "ink-text-input";
1989
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2598
+ import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
1990
2599
  function SearchInput({
1991
2600
  value,
1992
2601
  onChange,
1993
2602
  placeholder = "Search skills...",
1994
2603
  isFocused = false
1995
2604
  }) {
1996
- return /* @__PURE__ */ jsxs14(
1997
- Box14,
2605
+ return /* @__PURE__ */ jsxs19(
2606
+ Box19,
1998
2607
  {
1999
2608
  borderStyle: "single",
2000
2609
  borderColor: isFocused ? colors.primary : colors.borderDim,
2001
2610
  paddingX: 1,
2002
2611
  children: [
2003
- /* @__PURE__ */ jsx14(Text14, { color: colors.secondaryDim, children: "/ " }),
2004
- isFocused ? /* @__PURE__ */ jsx14(
2612
+ /* @__PURE__ */ jsx19(Text19, { color: colors.secondaryDim, children: "/ " }),
2613
+ isFocused ? /* @__PURE__ */ jsx19(
2005
2614
  TextInput,
2006
2615
  {
2007
2616
  value,
2008
2617
  onChange,
2009
2618
  placeholder
2010
2619
  }
2011
- ) : /* @__PURE__ */ jsx14(Text14, { color: value ? colors.secondary : colors.secondaryDim, children: value || placeholder }),
2012
- /* @__PURE__ */ jsx14(Box14, { flexGrow: 1 }),
2013
- /* @__PURE__ */ jsx14(Text14, { color: colors.secondaryDim, children: "/" })
2620
+ ) : /* @__PURE__ */ jsx19(Text19, { color: value ? colors.secondary : colors.secondaryDim, children: value || placeholder }),
2621
+ /* @__PURE__ */ jsx19(Box19, { flexGrow: 1 }),
2622
+ /* @__PURE__ */ jsx19(Text19, { color: colors.secondaryDim, children: "/" })
2014
2623
  ]
2015
2624
  }
2016
2625
  );
2017
2626
  }
2018
2627
 
2019
2628
  // src/hooks/useKeyboard.ts
2020
- import { useState as useState13, useCallback as useCallback3, useEffect as useEffect8 } from "react";
2021
- import { useInput as useInput9, useApp as useApp2 } from "ink";
2629
+ import { useState as useState18, useCallback as useCallback3, useEffect as useEffect13 } from "react";
2630
+ import { useInput as useInput14, useApp as useApp2 } from "ink";
2022
2631
  function useKeyboard(options = {}) {
2023
2632
  const { exit } = useApp2();
2024
- useInput9((input, key) => {
2633
+ useInput14((input, key) => {
2025
2634
  if (options.disabled) return;
2026
2635
  if (input === "q" || key.ctrl && input === "c") {
2027
2636
  exit();
@@ -2065,8 +2674,8 @@ function useKeyboard(options = {}) {
2065
2674
  });
2066
2675
  }
2067
2676
  function useListNavigation(listLength, initialIndex = 0) {
2068
- const [selectedIndex, setSelectedIndex] = useState13(initialIndex);
2069
- useEffect8(() => {
2677
+ const [selectedIndex, setSelectedIndex] = useState18(initialIndex);
2678
+ useEffect13(() => {
2070
2679
  if (selectedIndex >= listLength && listLength > 0) {
2071
2680
  setSelectedIndex(listLength - 1);
2072
2681
  }
@@ -2083,11 +2692,122 @@ function useListNavigation(listLength, initialIndex = 0) {
2083
2692
  return { selectedIndex, setSelectedIndex, moveUp, moveDown, reset };
2084
2693
  }
2085
2694
 
2695
+ // src/hooks/useMemory.ts
2696
+ import { useState as useState19, useEffect as useEffect14, useCallback as useCallback4 } from "react";
2697
+ import {
2698
+ LearningStore as LearningStore2,
2699
+ ObservationStore as ObservationStore2,
2700
+ getMemoryStatus as getMemoryStatus2,
2701
+ createMemoryInjector as createMemoryInjector2
2702
+ } from "@skillkit/core";
2703
+ function useMemory() {
2704
+ const [learnings, setLearnings] = useState19([]);
2705
+ const [observations, setObservations] = useState19([]);
2706
+ const [status, setStatus] = useState19(null);
2707
+ const [loading, setLoading] = useState19(true);
2708
+ const [error, setError] = useState19(null);
2709
+ const [isGlobal, setIsGlobal] = useState19(false);
2710
+ const projectPath = process.cwd();
2711
+ const refresh = useCallback4(() => {
2712
+ setLoading(true);
2713
+ setError(null);
2714
+ try {
2715
+ const memStatus = getMemoryStatus2(projectPath);
2716
+ setStatus(memStatus);
2717
+ const learningStore = new LearningStore2(
2718
+ isGlobal ? "global" : "project",
2719
+ isGlobal ? void 0 : projectPath
2720
+ );
2721
+ setLearnings(learningStore.getAll());
2722
+ if (memStatus.hasObservations) {
2723
+ const obsStore = new ObservationStore2(projectPath);
2724
+ setObservations(obsStore.getAll());
2725
+ } else {
2726
+ setObservations([]);
2727
+ }
2728
+ } catch (err) {
2729
+ setError(err instanceof Error ? err.message : "Failed to load memory");
2730
+ setLearnings([]);
2731
+ setObservations([]);
2732
+ } finally {
2733
+ setLoading(false);
2734
+ }
2735
+ }, [projectPath, isGlobal]);
2736
+ const search = useCallback4(
2737
+ (query) => {
2738
+ if (!query.trim()) {
2739
+ return [];
2740
+ }
2741
+ try {
2742
+ const injector = createMemoryInjector2(projectPath);
2743
+ const results = injector.search(query, {
2744
+ includeGlobal: true,
2745
+ maxLearnings: 50,
2746
+ minRelevance: 0
2747
+ });
2748
+ return results.map((r) => r.learning);
2749
+ } catch {
2750
+ return [];
2751
+ }
2752
+ },
2753
+ [projectPath]
2754
+ );
2755
+ const deleteLearning = useCallback4(
2756
+ (id) => {
2757
+ try {
2758
+ const store = new LearningStore2(
2759
+ isGlobal ? "global" : "project",
2760
+ isGlobal ? void 0 : projectPath
2761
+ );
2762
+ const result = store.delete(id);
2763
+ if (result) {
2764
+ refresh();
2765
+ }
2766
+ return result;
2767
+ } catch {
2768
+ return false;
2769
+ }
2770
+ },
2771
+ [projectPath, isGlobal, refresh]
2772
+ );
2773
+ const deleteObservation = useCallback4(
2774
+ (id) => {
2775
+ try {
2776
+ const store = new ObservationStore2(projectPath);
2777
+ const result = store.delete(id);
2778
+ if (result) {
2779
+ refresh();
2780
+ }
2781
+ return result;
2782
+ } catch {
2783
+ return false;
2784
+ }
2785
+ },
2786
+ [projectPath, refresh]
2787
+ );
2788
+ useEffect14(() => {
2789
+ refresh();
2790
+ }, [refresh]);
2791
+ return {
2792
+ learnings,
2793
+ observations,
2794
+ status,
2795
+ loading,
2796
+ error,
2797
+ isGlobal,
2798
+ setIsGlobal,
2799
+ refresh,
2800
+ search,
2801
+ deleteLearning,
2802
+ deleteObservation
2803
+ };
2804
+ }
2805
+
2086
2806
  // src/index.tsx
2087
- import { jsx as jsx15 } from "react/jsx-runtime";
2807
+ import { jsx as jsx20 } from "react/jsx-runtime";
2088
2808
  function startTUI() {
2089
2809
  process.stdout.write("\x1B[2J\x1B[0f");
2090
- const { waitUntilExit, clear } = render(/* @__PURE__ */ jsx15(App, {}), {
2810
+ const { waitUntilExit, clear } = render(/* @__PURE__ */ jsx20(App, {}), {
2091
2811
  exitOnCtrlC: true
2092
2812
  });
2093
2813
  return waitUntilExit().then(() => {
@@ -2098,9 +2818,13 @@ export {
2098
2818
  App,
2099
2819
  Browse,
2100
2820
  Context,
2821
+ Execute,
2101
2822
  Header,
2823
+ History,
2102
2824
  Home,
2103
2825
  Installed,
2826
+ Marketplace,
2827
+ Memory,
2104
2828
  Recommend,
2105
2829
  SearchInput,
2106
2830
  Settings,
@@ -2109,6 +2833,7 @@ export {
2109
2833
  StatusBar,
2110
2834
  Sync,
2111
2835
  Translate,
2836
+ Workflow,
2112
2837
  colors,
2113
2838
  logo,
2114
2839
  startTUI,
@@ -2116,6 +2841,7 @@ export {
2116
2841
  useKeyboard,
2117
2842
  useListNavigation,
2118
2843
  useMarketplace,
2844
+ useMemory,
2119
2845
  useRecommend,
2120
2846
  useSkills
2121
2847
  };