yourskills 0.4.0 → 0.4.3

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.
Files changed (2) hide show
  1. package/dist/main.js +92 -29
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -909,6 +909,24 @@ function SearchInput({
909
909
  });
910
910
  }
911
911
 
912
+ // src/ui/viewport.ts
913
+ import { useWindowSize as useWindowSize2 } from "ink";
914
+ var MIN_ROWS = 3;
915
+ var MAX_ROWS = 20;
916
+ function useViewport({
917
+ cursor,
918
+ total,
919
+ chrome
920
+ }) {
921
+ const { rows } = useWindowSize2();
922
+ const size = Math.max(MIN_ROWS, Math.min(MAX_ROWS, rows - chrome));
923
+ const first = Math.max(0, Math.min(cursor - Math.floor(size / 2), total - size));
924
+ return { first, size };
925
+ }
926
+ function position(cursor, total) {
927
+ return `${total > 0 ? cursor + 1 : 0}/${total}`;
928
+ }
929
+
912
930
  // src/ui/command.tsx
913
931
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
914
932
  function filterCommands(groups, query) {
@@ -923,6 +941,20 @@ function filterCommands(groups, query) {
923
941
  function flattenCommands(groups) {
924
942
  return groups.flatMap((group) => group.items);
925
943
  }
944
+ function windowGroups(groups, first, count) {
945
+ const out = [];
946
+ let index = 0;
947
+ for (const group of groups) {
948
+ const items = group.items.filter((_, i) => {
949
+ const row = index + i;
950
+ return row >= first && row < first + count;
951
+ });
952
+ index += group.items.length;
953
+ if (items.length > 0)
954
+ out.push({ group: group.group, items });
955
+ }
956
+ return out;
957
+ }
926
958
  var POINTER = 2;
927
959
  var GAP2 = 2;
928
960
  var LABEL_CAP = 22;
@@ -969,6 +1001,7 @@ function CommandPalette({
969
1001
  query,
970
1002
  cursor,
971
1003
  width,
1004
+ chrome = 11,
972
1005
  placeholder = "type a command or search",
973
1006
  emptyMessage = "No matching commands."
974
1007
  }) {
@@ -977,6 +1010,12 @@ function CommandPalette({
977
1010
  const current = rows[cursor];
978
1011
  const interior = width - FRAME_CHROME;
979
1012
  const column = valueColumn(rows);
1013
+ const { first, size } = useViewport({
1014
+ cursor,
1015
+ total: rows.length,
1016
+ chrome: chrome + Math.max(0, visible.length * 2 - 1)
1017
+ });
1018
+ const paged = windowGroups(visible, first, size);
980
1019
  return /* @__PURE__ */ jsxs5(Box3, {
981
1020
  flexDirection: "column",
982
1021
  children: [
@@ -998,7 +1037,7 @@ function CommandPalette({
998
1037
  rows.length === 0 ? /* @__PURE__ */ jsx5(Text4, {
999
1038
  dimColor: true,
1000
1039
  children: emptyMessage
1001
- }) : visible.map((group, i) => /* @__PURE__ */ jsxs5(Box3, {
1040
+ }) : paged.map((group, i) => /* @__PURE__ */ jsxs5(Box3, {
1002
1041
  flexDirection: "column",
1003
1042
  children: [
1004
1043
  i > 0 ? /* @__PURE__ */ jsx5(Divider, {
@@ -1159,6 +1198,7 @@ function LoginScreen({
1159
1198
  const { exit } = useApp();
1160
1199
  const width = useFrameWidth();
1161
1200
  const [state, setState] = useState3({ phase: "starting" });
1201
+ const [finished, setFinished] = useState3(false);
1162
1202
  useEffect2(() => {
1163
1203
  let live = true;
1164
1204
  (async () => {
@@ -1179,15 +1219,18 @@ function LoginScreen({
1179
1219
  }
1180
1220
  if (!live)
1181
1221
  return;
1222
+ setFinished(true);
1182
1223
  if (onDone)
1183
1224
  onDone();
1184
- else
1185
- exit();
1186
1225
  })();
1187
1226
  return () => {
1188
1227
  live = false;
1189
1228
  };
1190
- }, [exit, onError, onDone]);
1229
+ }, [onError, onDone]);
1230
+ useEffect2(() => {
1231
+ if (finished && !onDone)
1232
+ exit();
1233
+ }, [finished, onDone, exit]);
1191
1234
  if (state.phase === "done") {
1192
1235
  return /* @__PURE__ */ jsx8(Frame, {
1193
1236
  title: "login",
@@ -1485,7 +1528,7 @@ function catalogReport(title, skills) {
1485
1528
  };
1486
1529
  }
1487
1530
  // src/catalog/screens/browser.tsx
1488
- import { Box as Box9, Text as Text11, useApp as useApp5, useInput as useInput5, useWindowSize as useWindowSize2 } from "ink";
1531
+ import { Box as Box9, Text as Text11, useApp as useApp5, useInput as useInput5 } from "ink";
1489
1532
  import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo2, useState as useState7 } from "react";
1490
1533
 
1491
1534
  // src/manifest/manifest.ts
@@ -1597,7 +1640,8 @@ import { createRequire } from "node:module";
1597
1640
  import { dirname as dirname3, join as join5 } from "node:path";
1598
1641
  function skillsAddArgv(location, opts = {}) {
1599
1642
  const path = location.path.replace(/^\/+|\/+$/g, "");
1600
- const spec = `${location.source}${path ? `/${path}` : ""}#${location.ref}`;
1643
+ const at = location.ref ? `#${location.ref}` : "";
1644
+ const spec = `${location.source}${path ? `/${path}` : ""}${at}`;
1601
1645
  const argv = ["add", spec, "--yes"];
1602
1646
  if (opts.scope !== "project")
1603
1647
  argv.push("--global");
@@ -1676,7 +1720,7 @@ function manifestEntryFor(location, reached, bundle) {
1676
1720
  return {
1677
1721
  name: location.skillName,
1678
1722
  externalId: location.externalId,
1679
- ref: location.ref,
1723
+ ref: location.ref ?? "",
1680
1724
  source: location.source,
1681
1725
  path,
1682
1726
  ...bundle ? { bundle } : {},
@@ -1907,7 +1951,7 @@ async function adoptSkills(client, where, plan) {
1907
1951
  if (event.kind === "installed")
1908
1952
  outcome.adopted.push({
1909
1953
  name: event.location.skillName,
1910
- ref: event.location.ref
1954
+ ref: event.location.ref ?? ""
1911
1955
  });
1912
1956
  else if (event.kind === "failed")
1913
1957
  outcome.failed.push({ name: event.name, message: event.message });
@@ -1946,7 +1990,7 @@ function importReport(nearest, plan, outcome) {
1946
1990
  lines.push({
1947
1991
  mark: "ok",
1948
1992
  text: row.name.padEnd(width),
1949
- note: `adopted at ${row.ref.slice(0, 7)}`
1993
+ note: row.ref ? `adopted at ${row.ref.slice(0, 7)}` : "adopted, unpinned"
1950
1994
  });
1951
1995
  for (const name of outcome.pending)
1952
1996
  lines.push({
@@ -2002,7 +2046,8 @@ import { useEffect as useEffect4, useState as useState5 } from "react";
2002
2046
 
2003
2047
  // src/install/lines.ts
2004
2048
  function where(location) {
2005
- return `${location.source}/${location.path}@${location.ref.slice(0, 8)}`;
2049
+ const at = location.ref ? `@${location.ref.slice(0, 8)}` : " (unpinned)";
2050
+ return `${location.source}/${location.path}${at}`;
2006
2051
  }
2007
2052
  function put(lines, name, progress, deprecated = false) {
2008
2053
  const at = lines.findIndex((l) => l.name === name);
@@ -2232,13 +2277,15 @@ function Installer({
2232
2277
  return;
2233
2278
  setDone(true);
2234
2279
  onDone?.(summarise(current));
2235
- if (exitWhenDone)
2236
- exit();
2237
2280
  })();
2238
2281
  return () => {
2239
2282
  live = false;
2240
2283
  };
2241
- }, [stream, onDone, exit, exitWhenDone]);
2284
+ }, [stream, onDone]);
2285
+ useEffect4(() => {
2286
+ if (done && exitWhenDone)
2287
+ exit();
2288
+ }, [done, exit, exitWhenDone]);
2242
2289
  const counts = done ? receipt(lines) : null;
2243
2290
  const pending = counts?.pending ?? 0;
2244
2291
  const questions = counts?.questions ?? 0;
@@ -2777,9 +2824,6 @@ function runFor(command, where, connect) {
2777
2824
  // src/catalog/screens/browser.tsx
2778
2825
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2779
2826
  var TABS = ["bundles", "skills"];
2780
- function pageSize(rows) {
2781
- return Math.max(3, Math.min(20, rows - 11));
2782
- }
2783
2827
  function matches(row, query) {
2784
2828
  if (query.length === 0)
2785
2829
  return true;
@@ -2817,7 +2861,6 @@ function BrowserScreen({
2817
2861
  }) {
2818
2862
  const { exit } = useApp5();
2819
2863
  const width = useFrameWidth();
2820
- const { rows: terminalRows } = useWindowSize2();
2821
2864
  const [catalog, setCatalog] = useState7(null);
2822
2865
  const [tab, setTab] = useState7(initialTab);
2823
2866
  const [query, setQuery] = useState7(initialQuery);
@@ -2860,6 +2903,11 @@ function BrowserScreen({
2860
2903
  setCursor((c) => Math.max(0, Math.min(c, visible.length - 1)));
2861
2904
  }, [visible.length]);
2862
2905
  const selected = picked[tab];
2906
+ const { first, size } = useViewport({
2907
+ cursor,
2908
+ total: visible.length,
2909
+ chrome: 11
2910
+ });
2863
2911
  const start = useCallback2(() => {
2864
2912
  const names = selected.size > 0 ? [...selected] : visible[cursor] ? [visible[cursor].name] : [];
2865
2913
  if (names.length === 0)
@@ -2875,9 +2923,9 @@ function BrowserScreen({
2875
2923
  } else if (key.downArrow) {
2876
2924
  setCursor((c) => Math.min(visible.length - 1, c + 1));
2877
2925
  } else if (key.pageUp) {
2878
- setCursor((c) => Math.max(0, c - pageSize(terminalRows)));
2926
+ setCursor((c) => Math.max(0, c - size));
2879
2927
  } else if (key.pageDown) {
2880
- setCursor((c) => Math.min(visible.length - 1, c + pageSize(terminalRows)));
2928
+ setCursor((c) => Math.min(visible.length - 1, c + size));
2881
2929
  } else if (key.tab) {
2882
2930
  setTab((t) => t === "bundles" ? "skills" : "bundles");
2883
2931
  setCursor(0);
@@ -2935,9 +2983,7 @@ function BrowserScreen({
2935
2983
  })
2936
2984
  });
2937
2985
  }
2938
- const size = pageSize(terminalRows);
2939
- const first = Math.max(0, Math.min(cursor - Math.floor(size / 2), visible.length - size));
2940
- const page = visible.slice(Math.max(0, first), Math.max(0, first) + size);
2986
+ const page = visible.slice(first, first + size);
2941
2987
  const names = nameWidth(visible.length > 0 ? visible : catalog[tab]);
2942
2988
  return /* @__PURE__ */ jsx13(Frame, {
2943
2989
  title: "yourskills",
@@ -2974,7 +3020,7 @@ function BrowserScreen({
2974
3020
  width: width - 2,
2975
3021
  names,
2976
3022
  selectable: true,
2977
- cursor: Math.max(0, first) + i === cursor,
3023
+ cursor: first + i === cursor,
2978
3024
  selected: selected.has(row.name)
2979
3025
  }, row.name)),
2980
3026
  /* @__PURE__ */ jsx13(Divider, {
@@ -2984,7 +3030,7 @@ function BrowserScreen({
2984
3030
  children: [
2985
3031
  /* @__PURE__ */ jsx13(Text11, {
2986
3032
  dimColor: true,
2987
- children: `${visible.length > 0 ? cursor + 1 : 0}/${visible.length}`
3033
+ children: position(cursor, visible.length)
2988
3034
  }),
2989
3035
  selected.size > 0 ? /* @__PURE__ */ jsx13(Text11, {
2990
3036
  color: tone.notice,
@@ -3026,7 +3072,6 @@ function CatalogScreen({
3026
3072
  if (!live)
3027
3073
  return;
3028
3074
  setRows(result);
3029
- exit();
3030
3075
  }).catch((error) => {
3031
3076
  if (live)
3032
3077
  onError(error);
@@ -3034,7 +3079,11 @@ function CatalogScreen({
3034
3079
  return () => {
3035
3080
  live = false;
3036
3081
  };
3037
- }, [load, exit, onError]);
3082
+ }, [load, onError]);
3083
+ useEffect7(() => {
3084
+ if (rows !== null)
3085
+ exit();
3086
+ }, [rows, exit]);
3038
3087
  if (rows === null) {
3039
3088
  return /* @__PURE__ */ jsx14(Frame, {
3040
3089
  title,
@@ -5768,7 +5817,7 @@ import { realpathSync } from "node:fs";
5768
5817
  // package.json
5769
5818
  var package_default = {
5770
5819
  name: "yourskills",
5771
- version: "0.4.0",
5820
+ version: "0.4.3",
5772
5821
  description: "Browse, install and keep up to date the agent skills and bundles your team publishes on yourskills.",
5773
5822
  license: "UNLICENSED",
5774
5823
  homepage: "https://yourskills.store",
@@ -8545,11 +8594,20 @@ function PickScreen({
8545
8594
  useEffect8(() => {
8546
8595
  setCursor((c) => Math.max(0, Math.min(c, visible.length - 1)));
8547
8596
  }, [visible.length]);
8597
+ const { first, size } = useViewport({
8598
+ cursor,
8599
+ total: visible.length,
8600
+ chrome: 9
8601
+ });
8548
8602
  useInput6((input, key) => {
8549
8603
  if (key.upArrow) {
8550
8604
  setCursor((c) => Math.max(0, c - 1));
8551
8605
  } else if (key.downArrow) {
8552
8606
  setCursor((c) => Math.min(visible.length - 1, c + 1));
8607
+ } else if (key.pageUp) {
8608
+ setCursor((c) => Math.max(0, c - size));
8609
+ } else if (key.pageDown) {
8610
+ setCursor((c) => Math.min(visible.length - 1, c + size));
8553
8611
  } else if (key.return) {
8554
8612
  const names = picked.size > 0 ? [...picked] : visible[cursor] ? [visible[cursor].name] : [];
8555
8613
  if (names.length > 0)
@@ -8580,6 +8638,7 @@ function PickScreen({
8580
8638
  }
8581
8639
  });
8582
8640
  const names = nameWidth(rows);
8641
+ const page = visible.slice(first, first + size);
8583
8642
  return /* @__PURE__ */ jsx16(Frame, {
8584
8643
  title,
8585
8644
  width,
@@ -8607,12 +8666,12 @@ function PickScreen({
8607
8666
  }) : visible.length === 0 ? /* @__PURE__ */ jsx16(Text14, {
8608
8667
  dimColor: true,
8609
8668
  children: `Nothing matches "${query}".`
8610
- }) : visible.map((row, i) => /* @__PURE__ */ jsx16(SkillRow, {
8669
+ }) : page.map((row, i) => /* @__PURE__ */ jsx16(SkillRow, {
8611
8670
  row,
8612
8671
  width: width - 2,
8613
8672
  names,
8614
8673
  selectable: true,
8615
- cursor: i === cursor,
8674
+ cursor: first + i === cursor,
8616
8675
  selected: single ? row.name === marked : picked.has(row.name)
8617
8676
  }, row.name)),
8618
8677
  /* @__PURE__ */ jsx16(Divider, {
@@ -8620,6 +8679,10 @@ function PickScreen({
8620
8679
  }),
8621
8680
  /* @__PURE__ */ jsxs14(Box12, {
8622
8681
  children: [
8682
+ /* @__PURE__ */ jsx16(Text14, {
8683
+ dimColor: true,
8684
+ children: `${position(cursor, visible.length)} `
8685
+ }),
8623
8686
  picked.size > 0 && !single ? /* @__PURE__ */ jsx16(Text14, {
8624
8687
  color: tone.notice,
8625
8688
  children: `${mark.selected} ${picked.size} marked `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yourskills",
3
- "version": "0.4.0",
3
+ "version": "0.4.3",
4
4
  "description": "Browse, install and keep up to date the agent skills and bundles your team publishes on yourskills.",
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://yourskills.store",