allagents 1.11.0 → 1.11.2-next.1

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/index.js +164 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34731,7 +34731,7 @@ function buildSearchQueries(query, owner) {
34731
34731
  const userClause = owner ? `user:${owner}` : "";
34732
34732
  const join26 = (...parts) => parts.filter(Boolean).join(" ");
34733
34733
  const queries = [
34734
- { priority: 1, label: "path", q: join26("filename:SKILL.md", `in:path ${pathTerm}`, userClause) }
34734
+ { priority: 1, label: "path", q: join26("filename:SKILL.md", `path:${pathTerm}`, userClause) }
34735
34735
  ];
34736
34736
  if (pathTerm !== trimmed2) {
34737
34737
  queries.push({ priority: 2, label: "hyphen", q: join26("filename:SKILL.md", pathTerm, userClause) });
@@ -34744,6 +34744,9 @@ function buildSearchQueries(query, owner) {
34744
34744
  }
34745
34745
  function classifyApiError(status, body) {
34746
34746
  const msg = typeof body === "object" && body !== null && "message" in body ? String(body.message ?? "") : "";
34747
+ if (status === 401) {
34748
+ return new SkillSearchError("GitHub Code Search requires authentication. Run `gh auth login` or set GITHUB_TOKEN.", "api");
34749
+ }
34747
34750
  if (status === 403 && /rate limit/i.test(msg)) {
34748
34751
  return new SkillSearchError("GitHub Code Search rate limit exceeded. Authenticate with `gh auth login` or set GITHUB_TOKEN to raise the quota.", "rate-limit");
34749
34752
  }
@@ -34752,6 +34755,21 @@ function classifyApiError(status, body) {
34752
34755
  }
34753
34756
  return new SkillSearchError(`GitHub Code Search returned ${status}${msg ? `: ${msg}` : ""}.`, "api");
34754
34757
  }
34758
+ async function resolveGhToken() {
34759
+ const env2 = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
34760
+ if (env2)
34761
+ return env2;
34762
+ try {
34763
+ const { execFile } = await import("node:child_process");
34764
+ return await new Promise((resolve15) => {
34765
+ execFile("gh", ["auth", "token"], { timeout: 3000 }, (err, stdout) => {
34766
+ resolve15(err ? undefined : stdout.trim() || undefined);
34767
+ });
34768
+ });
34769
+ } catch {
34770
+ return;
34771
+ }
34772
+ }
34755
34773
  function qualifiedName(item) {
34756
34774
  return item.namespace ? `${item.namespace}/${item.name}` : item.name;
34757
34775
  }
@@ -34760,7 +34778,7 @@ function parseSkillPath(path, repoFallback) {
34760
34778
  const skillsIdx = parts.lastIndexOf("skills");
34761
34779
  if (skillsIdx !== -1) {
34762
34780
  const afterSkills = parts.slice(skillsIdx + 1);
34763
- const meaningful = afterSkills[afterSkills.length - 1] === "SKILL.md" ? afterSkills.slice(0, -1) : afterSkills;
34781
+ const meaningful = afterSkills[afterSkills.length - 1]?.toLowerCase() === "skill.md" ? afterSkills.slice(0, -1) : afterSkills;
34764
34782
  if (meaningful.length >= 2) {
34765
34783
  const namespace = meaningful[0] ?? "";
34766
34784
  const name = meaningful[1] ?? "";
@@ -34768,11 +34786,14 @@ function parseSkillPath(path, repoFallback) {
34768
34786
  return { namespace, name };
34769
34787
  }
34770
34788
  if (meaningful.length === 1 && meaningful[0]) {
34771
- return { namespace: "", name: meaningful[0] };
34789
+ const nsFromPlugin = skillsIdx >= 2 && parts[skillsIdx - 2] === "plugins" ? parts[skillsIdx - 1] ?? "" : "";
34790
+ return { namespace: nsFromPlugin, name: meaningful[0] };
34772
34791
  }
34773
34792
  }
34774
- if (parts.length >= 2) {
34775
- const parent = parts[parts.length - 2];
34793
+ const lastPart = parts[parts.length - 1]?.toLowerCase() ?? "";
34794
+ const fileIdx = lastPart.endsWith(".md") ? parts.length - 2 : parts.length - 1;
34795
+ if (fileIdx >= 0) {
34796
+ const parent = parts[fileIdx];
34776
34797
  if (parent)
34777
34798
  return { namespace: "", name: parent };
34778
34799
  }
@@ -34810,7 +34831,8 @@ async function runOneQuery(q3, page, limit, token, fetchFn) {
34810
34831
  repo,
34811
34832
  path,
34812
34833
  description: item.repository?.description ?? "",
34813
- sha: item.sha ?? ""
34834
+ sha: item.sha ?? "",
34835
+ stars: item.repository?.stargazers_count ?? 0
34814
34836
  };
34815
34837
  });
34816
34838
  return {
@@ -34825,8 +34847,8 @@ async function searchSkills(query, options2 = {}, deps = {}) {
34825
34847
  const logger = deps.logger ?? ((msg) => process.stderr.write(`${msg}
34826
34848
  `));
34827
34849
  const page = options2.page ?? 1;
34828
- const limit = options2.limit ?? 30;
34829
- const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
34850
+ const limit = options2.limit ?? 15;
34851
+ const token = await (deps.tokenResolver ?? resolveGhToken)();
34830
34852
  const queries = buildSearchQueries(query, options2.owner);
34831
34853
  const settled = await Promise.allSettled(queries.map((entry) => runOneQuery(entry.q, page, limit, token, fetchFn)));
34832
34854
  const primaryIdx = queries.findIndex((q3) => q3.priority === 4);
@@ -34850,11 +34872,18 @@ async function searchSkills(query, options2 = {}, deps = {}) {
34850
34872
  buckets.sort((a, b) => a.priority - b.priority);
34851
34873
  const mergedItems = buckets.flatMap((b) => b.result.items);
34852
34874
  const deduped = dedupeItems(mergedItems);
34875
+ const visible = deduped.filter((item) => {
34876
+ const firstSegment = item.path.split("/")[0] ?? "";
34877
+ return !firstSegment.startsWith(".");
34878
+ });
34879
+ await fetchStarsForItems(visible, token, fetchFn);
34880
+ visible.sort((a, b) => b.stars - a.stars);
34881
+ const finalItems = visible.slice(0, limit);
34853
34882
  return {
34854
34883
  query,
34855
- items: deduped,
34856
- total: deduped.length,
34857
- truncated: buckets.some((b) => b.result.truncated)
34884
+ items: finalItems,
34885
+ total: finalItems.length,
34886
+ truncated: buckets.some((b) => b.result.truncated) || visible.length > limit
34858
34887
  };
34859
34888
  }
34860
34889
  function dedupeItems(items) {
@@ -34869,6 +34898,31 @@ function dedupeItems(items) {
34869
34898
  }
34870
34899
  return out;
34871
34900
  }
34901
+ async function fetchStarsForItems(items, token, fetchFn) {
34902
+ const uniqueRepos = [...new Set(items.map((i2) => i2.repo))];
34903
+ const headers = {
34904
+ Accept: "application/vnd.github+json",
34905
+ "X-GitHub-Api-Version": "2022-11-28",
34906
+ "User-Agent": "allagents-cli"
34907
+ };
34908
+ if (token)
34909
+ headers.Authorization = `token ${token}`;
34910
+ const starsMap = new Map;
34911
+ await Promise.allSettled(uniqueRepos.map(async (repo) => {
34912
+ try {
34913
+ const res = await fetchFn(`https://api.github.com/repos/${repo}`, { headers });
34914
+ if (!res.ok)
34915
+ return;
34916
+ const body = await res.json();
34917
+ starsMap.set(repo, body.stargazers_count ?? 0);
34918
+ } catch {}
34919
+ }));
34920
+ for (const item of items) {
34921
+ const s = starsMap.get(item.repo);
34922
+ if (s !== undefined)
34923
+ item.stars = s;
34924
+ }
34925
+ }
34872
34926
  var OWNER_REGEX, COULD_BE_OWNER_REGEX, SkillSearchError;
34873
34927
  var init_skill_search = __esm(() => {
34874
34928
  OWNER_REGEX = /^[A-Za-z0-9-]{1,39}$/;
@@ -41853,7 +41907,7 @@ var package_default;
41853
41907
  var init_package = __esm(() => {
41854
41908
  package_default = {
41855
41909
  name: "allagents",
41856
- version: "1.11.0",
41910
+ version: "1.11.2-next.1",
41857
41911
  packageManager: "bun@1.3.12",
41858
41912
  description: "CLI tool for managing multi-repo AI agent workspaces with plugin synchronization",
41859
41913
  type: "module",
@@ -44700,7 +44754,7 @@ var skillsRemoveMeta = {
44700
44754
  };
44701
44755
  var skillsSearchMeta = {
44702
44756
  command: "skill search",
44703
- description: "Search GitHub for skills by querying SKILL.md files via the Code Search API",
44757
+ description: "Search GitHub for skills by querying SKILL.md files via the Code Search API. Results are sorted by star count. In TTY mode, shows a filter-as-you-type picker and offers to install the selected skill.",
44704
44758
  whenToUse: 'To discover available skills from public GitHub repositories without leaving the CLI. Bridges "I want a skill that does X" → install.',
44705
44759
  examples: [
44706
44760
  "allagents skill search terraform",
@@ -44708,18 +44762,18 @@ var skillsSearchMeta = {
44708
44762
  "allagents skill search docs --page 2 --limit 10",
44709
44763
  "allagents --json skill search docs --limit 5"
44710
44764
  ],
44711
- expectedOutput: "Ranked list of matching skills with repo, path, and description",
44765
+ expectedOutput: "Skills sorted by star count: repo, skill name, stars, description. In TTY mode, followed by a filter-as-you-type install prompt.",
44712
44766
  positionals: [
44713
44767
  { name: "query", type: "string", required: true, description: "Search query (≥2 characters)." }
44714
44768
  ],
44715
44769
  options: [
44716
44770
  { flag: "--owner", type: "string", description: "Scope to a single GitHub owner (org or user)." },
44717
44771
  { flag: "--page", type: "string", description: "Result page (1-indexed, default 1)." },
44718
- { flag: "--limit", type: "string", description: "Results per page (1–100, default 30)." }
44772
+ { flag: "--limit", type: "string", description: "Results per page (1–100, default 15)." }
44719
44773
  ],
44720
44774
  outputSchema: {
44721
44775
  query: "string",
44722
- items: [{ name: "string", repo: "string", path: "string", description: "string", sha: "string" }],
44776
+ items: [{ name: "string", namespace: "string", repo: "string", path: "string", description: "string", sha: "string", stars: "number" }],
44723
44777
  total: "number",
44724
44778
  truncated: "boolean"
44725
44779
  }
@@ -45736,6 +45790,78 @@ Use --plugin to specify: allagents skill add ${skill} --plugin <name>`;
45736
45790
  }
45737
45791
  }
45738
45792
  });
45793
+ function printSearchResults(items, query, truncated) {
45794
+ console.log(`
45795
+ Showing ${items.length} result${items.length !== 1 ? "s" : ""} for "${query}"${truncated ? " (truncated)" : ""}
45796
+ `);
45797
+ for (const item of items) {
45798
+ const repoCol = item.repo.padEnd(30);
45799
+ const nameCol = qualifiedName(item).padEnd(24);
45800
+ const stars = item.stars > 0 ? source_default.yellow(`★ ${item.stars}`) : "";
45801
+ const desc = item.description ? source_default.dim(item.description.length > 60 ? `${item.description.slice(0, 57)}...` : item.description) : "";
45802
+ const starsAndDesc = [stars, desc].filter(Boolean).join(" ");
45803
+ console.log(` ${source_default.cyan(repoCol)} ${source_default.bold(nameCol)} ${starsAndDesc}`);
45804
+ }
45805
+ console.log("");
45806
+ }
45807
+ async function installFromSearch(repo) {
45808
+ const p = await Promise.resolve().then(() => (init_dist2(), exports_dist));
45809
+ const workspacePath = process.cwd();
45810
+ const isInstalledProject = hasProjectConfig(workspacePath) ? await hasPlugin(repo, workspacePath) : false;
45811
+ const isInstalledUser = await hasUserPlugin(repo);
45812
+ if (isInstalledProject || isInstalledUser) {
45813
+ const scopeLabel = isInstalledUser ? "user" : "project";
45814
+ p.log.info(`Plugin ${source_default.bold(repo)} is already installed (${scopeLabel} scope).`);
45815
+ return false;
45816
+ }
45817
+ const scopeChoice = await p.select({
45818
+ message: "Install scope",
45819
+ options: [
45820
+ { label: "Project (this workspace)", value: "project" },
45821
+ { label: "User (global)", value: "user" }
45822
+ ]
45823
+ });
45824
+ if (p.isCancel(scopeChoice))
45825
+ return false;
45826
+ const s = p.spinner();
45827
+ s.start("Installing plugin...");
45828
+ try {
45829
+ if (scopeChoice === "project") {
45830
+ const result = await addPlugin(repo, workspacePath);
45831
+ if (!result.success) {
45832
+ s.stop("Installation failed");
45833
+ p.log.error(result.error ?? "Unknown error");
45834
+ return false;
45835
+ }
45836
+ s.message("Syncing...");
45837
+ const syncResult = await syncWorkspace(workspacePath);
45838
+ s.stop("Installed and synced");
45839
+ const lines = formatVerboseSyncLines(syncResult);
45840
+ if (lines.length > 0)
45841
+ p.note(lines.join(`
45842
+ `), `Installed: ${repo}`);
45843
+ } else {
45844
+ const result = await addUserPlugin(repo);
45845
+ if (!result.success) {
45846
+ s.stop("Installation failed");
45847
+ p.log.error(result.error ?? "Unknown error");
45848
+ return false;
45849
+ }
45850
+ s.message("Syncing...");
45851
+ const syncResult = await syncUserWorkspace();
45852
+ s.stop("Installed and synced");
45853
+ const lines = formatVerboseSyncLines(syncResult);
45854
+ if (lines.length > 0)
45855
+ p.note(lines.join(`
45856
+ `), `Installed: ${repo}`);
45857
+ }
45858
+ return true;
45859
+ } catch (err) {
45860
+ s.stop("Installation failed");
45861
+ p.log.error(err instanceof Error ? err.message : String(err));
45862
+ return false;
45863
+ }
45864
+ }
45739
45865
  var searchCmd = import_cmd_ts3.command({
45740
45866
  name: "search",
45741
45867
  description: buildDescription(skillsSearchMeta),
@@ -45754,7 +45880,7 @@ var searchCmd = import_cmd_ts3.command({
45754
45880
  limit: import_cmd_ts3.option({
45755
45881
  type: import_cmd_ts3.optional(import_cmd_ts3.string),
45756
45882
  long: "limit",
45757
- description: "Results per page (1–100, default 30)."
45883
+ description: "Results per page (1–100, default 15)."
45758
45884
  })
45759
45885
  },
45760
45886
  handler: async ({ query, owner, page, limit }) => {
@@ -45801,13 +45927,28 @@ var searchCmd = import_cmd_ts3.command({
45801
45927
  console.log(`No skills found for "${query}".`);
45802
45928
  return;
45803
45929
  }
45804
- console.log(`Found ${result.total} skill(s)${result.truncated ? " (results truncated)" : ""}:`);
45805
- for (const item of result.items) {
45806
- const repoCol = item.repo.padEnd(28);
45807
- const nameCol = item.name.padEnd(28);
45808
- const desc = item.description ? ` ${item.description}` : "";
45809
- console.log(` ${repoCol} ${nameCol}${desc}`);
45930
+ const isTTY = process.stdout.isTTY && process.stdin.isTTY;
45931
+ if (!isTTY) {
45932
+ printSearchResults(result.items, query, result.truncated);
45933
+ return;
45934
+ }
45935
+ const { autocomplete, isCancel } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
45936
+ printSearchResults(result.items, query, result.truncated);
45937
+ const options2 = result.items.map((item) => ({
45938
+ label: `${qualifiedName(item)} ${source_default.dim(item.repo)}`,
45939
+ value: item.repo,
45940
+ hint: `${item.stars > 0 ? `★${item.stars} ` : ""}${item.description ?? ""}`
45941
+ }));
45942
+ options2.push({ label: "Cancel", value: "__cancel__", hint: "" });
45943
+ const selected = await autocomplete({
45944
+ message: `Select a skill to install (type to filter ${result.items.length} results)`,
45945
+ options: options2,
45946
+ placeholder: "Type to filter..."
45947
+ });
45948
+ if (isCancel(selected) || selected === "__cancel__") {
45949
+ return;
45810
45950
  }
45951
+ await installFromSearch(selected);
45811
45952
  } catch (error) {
45812
45953
  if (error instanceof SkillSearchError) {
45813
45954
  const exitCode = error.kind === "validation" ? 2 : 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allagents",
3
- "version": "1.11.0",
3
+ "version": "1.11.2-next.1",
4
4
  "packageManager": "bun@1.3.12",
5
5
  "description": "CLI tool for managing multi-repo AI agent workspaces with plugin synchronization",
6
6
  "type": "module",