agentshq 0.1.1 → 0.1.4

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/cli.mjs +72 -34
  2. package/package.json +48 -10
package/dist/cli.mjs CHANGED
@@ -31,29 +31,48 @@ const DEFAULT_REPO = "ulpi-io/agents";
31
31
  //#endregion
32
32
  //#region src/source-parser.ts
33
33
  /**
34
- * Extract owner/repo (or group/subgroup/repo for GitLab) from a parsed source
34
+ * Extract host/owner/repo (e.g., "github.com/ulpi-io/agents") from a parsed source
35
35
  * for lockfile tracking and telemetry.
36
36
  * Returns null for local paths or unparseable sources.
37
- * Supports any Git host with an owner/repo URL structure, including GitLab subgroups.
37
+ * The host is derived from the parsed source type:
38
+ * - github → github.com
39
+ * - gitlab → gitlab.com (or the actual host for self-hosted instances)
40
+ * - git → extracted from URL
41
+ * Bare owner/repo CLI input defaults to github.com.
38
42
  */
39
43
  function getOwnerRepo(parsed) {
40
44
  if (parsed.type === "local") return null;
41
- const sshMatch = parsed.url.match(/^git@[^:]+:(.+)$/);
45
+ const sshMatch = parsed.url.match(/^git@([^:]+):(.+)$/);
42
46
  if (sshMatch) {
43
- let path = sshMatch[1];
47
+ const host = sshMatch[1];
48
+ let path = sshMatch[2];
44
49
  path = path.replace(/\.git$/, "");
45
- if (path.includes("/")) return path;
50
+ if (path.includes("/")) return `${host}/${path}`;
46
51
  return null;
47
52
  }
48
53
  if (!parsed.url.startsWith("http://") && !parsed.url.startsWith("https://")) return null;
49
54
  try {
50
- let path = new URL(parsed.url).pathname.slice(1);
55
+ const url = new URL(parsed.url);
56
+ const host = url.hostname;
57
+ let path = url.pathname.slice(1);
51
58
  path = path.replace(/\.git$/, "");
52
- if (path.includes("/")) return path;
59
+ if (path.includes("/")) return `${host}/${path}`;
53
60
  } catch {}
54
61
  return null;
55
62
  }
56
63
  /**
64
+ * Strip the host prefix from a host/owner/repo string to get bare owner/repo.
65
+ * Returns null if the input doesn't have at least 3 segments (host/owner/repo).
66
+ * For GitLab subgroups, returns the full path after the host (e.g., "group/subgroup/repo").
67
+ */
68
+ function stripHost(hostOwnerRepo) {
69
+ const slashIndex = hostOwnerRepo.indexOf("/");
70
+ if (slashIndex === -1) return null;
71
+ const rest = hostOwnerRepo.slice(slashIndex + 1);
72
+ if (!rest.includes("/")) return null;
73
+ return rest;
74
+ }
75
+ /**
57
76
  * Extract owner and repo from an owner/repo string.
58
77
  * Returns null if the format is invalid.
59
78
  */
@@ -631,9 +650,9 @@ function detectFormat(filePath) {
631
650
  function parseFromFlatMd(content, filePath) {
632
651
  try {
633
652
  const { data, content: body } = (0, import_gray_matter.default)(content);
634
- const name = typeof data.name === "string" && data.name.length > 0 ? data.name : basename(filePath, ".md");
653
+ const name = typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
635
654
  const description = typeof data.description === "string" && data.description.length > 0 ? data.description : void 0;
636
- if (!name && !description) return null;
655
+ if (!name) return null;
637
656
  return {
638
657
  name,
639
658
  description: description ?? "",
@@ -1001,26 +1020,36 @@ async function discoverAgents(basePath, subpath, options) {
1001
1020
  join(searchPath, "agents/.system"),
1002
1021
  join(searchPath, ".agent/agents"),
1003
1022
  join(searchPath, ".agents/agents"),
1023
+ join(searchPath, ".augment/agents"),
1004
1024
  join(searchPath, ".claude/agents"),
1005
1025
  join(searchPath, ".cline/agents"),
1006
1026
  join(searchPath, ".codebuddy/agents"),
1007
1027
  join(searchPath, ".codex/agents"),
1008
1028
  join(searchPath, ".commandcode/agents"),
1009
1029
  join(searchPath, ".continue/agents"),
1030
+ join(searchPath, ".cortex/agents"),
1031
+ join(searchPath, ".crush/agents"),
1032
+ join(searchPath, ".factory/agents"),
1033
+ join(searchPath, ".gemini/agents"),
1010
1034
  join(searchPath, ".github/agents"),
1011
1035
  join(searchPath, ".goose/agents"),
1012
1036
  join(searchPath, ".iflow/agents"),
1013
1037
  join(searchPath, ".junie/agents"),
1014
1038
  join(searchPath, ".kilocode/agents"),
1015
1039
  join(searchPath, ".kiro/agents"),
1040
+ join(searchPath, ".kode/agents"),
1041
+ join(searchPath, ".mcpjam/agents"),
1016
1042
  join(searchPath, ".mux/agents"),
1017
1043
  join(searchPath, ".neovate/agents"),
1018
1044
  join(searchPath, ".opencode/agents"),
1019
1045
  join(searchPath, ".openhands/agents"),
1020
1046
  join(searchPath, ".pi/agents"),
1047
+ join(searchPath, ".pochi/agents"),
1021
1048
  join(searchPath, ".qoder/agents"),
1049
+ join(searchPath, ".qwen/agents"),
1022
1050
  join(searchPath, ".roo/agents"),
1023
1051
  join(searchPath, ".trae/agents"),
1052
+ join(searchPath, ".vibe/agents"),
1024
1053
  join(searchPath, ".windsurf/agents"),
1025
1054
  join(searchPath, ".zencoder/agents")
1026
1055
  ];
@@ -2916,7 +2945,7 @@ var WellKnownProvider = class {
2916
2945
  const wellKnownProvider = new WellKnownProvider();
2917
2946
  //#endregion
2918
2947
  //#region package.json
2919
- var version$1 = "0.1.1";
2948
+ var version$1 = "0.1.4";
2920
2949
  //#endregion
2921
2950
  //#region src/add.ts
2922
2951
  const isCancelled$1 = (value) => typeof value === "symbol";
@@ -3133,8 +3162,9 @@ async function handleWellKnownAgents(source, url, options, spinner) {
3133
3162
  options: agentDefs.map((s) => ({
3134
3163
  value: s,
3135
3164
  label: s.installName,
3136
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3165
+ hint: s.description
3137
3166
  })),
3167
+ initialValues: agentDefs,
3138
3168
  required: true
3139
3169
  });
3140
3170
  if (pD(selected)) {
@@ -3264,8 +3294,9 @@ async function handleWellKnownAgents(source, url, options, spinner) {
3264
3294
  if (await isSourcePrivate(sourceIdentifier) !== true) track({
3265
3295
  event: "install",
3266
3296
  source: sourceIdentifier,
3267
- agents: targetIdes.join(","),
3297
+ agents: selectedAgents.map((s) => s.installName).join(","),
3268
3298
  ...installGlobally && { global: "1" },
3299
+ ide: targetIdes.join(","),
3269
3300
  agentFiles: JSON.stringify(agentFiles),
3270
3301
  sourceType: "well-known"
3271
3302
  });
@@ -3479,7 +3510,7 @@ async function runAdd(args, options = {}) {
3479
3510
  grouped[groupName].push({
3480
3511
  value: s,
3481
3512
  label: getAgentDisplayName(s),
3482
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3513
+ hint: s.description
3483
3514
  });
3484
3515
  }
3485
3516
  selected = await be({
@@ -3492,8 +3523,9 @@ async function runAdd(args, options = {}) {
3492
3523
  options: sortedAgents.map((s) => ({
3493
3524
  value: s,
3494
3525
  label: getAgentDisplayName(s),
3495
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3526
+ hint: s.description
3496
3527
  })),
3528
+ initialValues: sortedAgents,
3497
3529
  required: true
3498
3530
  });
3499
3531
  if (pD(selected)) {
@@ -3504,7 +3536,8 @@ async function runAdd(args, options = {}) {
3504
3536
  selectedAgents = selected;
3505
3537
  }
3506
3538
  const ownerRepoForAudit = getOwnerRepo(parsed);
3507
- const ownerRepoParsed = ownerRepoForAudit ? parseOwnerRepo(ownerRepoForAudit) : null;
3539
+ const bareOwnerRepo = ownerRepoForAudit ? stripHost(ownerRepoForAudit) : null;
3540
+ const ownerRepoParsed = bareOwnerRepo ? parseOwnerRepo(bareOwnerRepo) : null;
3508
3541
  const repoIsPrivate = ownerRepoParsed ? await isRepoPrivate(ownerRepoParsed.owner, ownerRepoParsed.repo) : null;
3509
3542
  const auditPromise = ownerRepoForAudit && repoIsPrivate === false ? fetchAuditData(ownerRepoForAudit, selectedAgents.map((s) => getAgentDisplayName(s))) : Promise.resolve(null);
3510
3543
  let targetIdes;
@@ -3669,12 +3702,14 @@ async function runAdd(args, options = {}) {
3669
3702
  agentFiles[agentDef.name] = relativePath;
3670
3703
  }
3671
3704
  const normalizedSource = getOwnerRepo(parsed);
3705
+ const bareNormalizedSource = normalizedSource ? stripHost(normalizedSource) : null;
3672
3706
  const lockSource = parsed.url.startsWith("git@") ? parsed.url : normalizedSource;
3673
3707
  if (normalizedSource && repoIsPrivate !== true) track({
3674
3708
  event: "install",
3675
3709
  source: normalizedSource,
3676
- agents: targetIdes.join(","),
3710
+ agents: selectedAgents.map((s) => getAgentDisplayName(s)).join(","),
3677
3711
  ...installGlobally && { global: "1" },
3712
+ ide: targetIdes.join(","),
3678
3713
  agentFiles: JSON.stringify(agentFiles)
3679
3714
  });
3680
3715
  if (successful.length > 0 && installGlobally && normalizedSource) {
@@ -3684,8 +3719,8 @@ async function runAdd(args, options = {}) {
3684
3719
  if (successfulAgentNames.has(agentDisplayName)) try {
3685
3720
  let agentFolderHash = "";
3686
3721
  const agentPathValue = agentFiles[agentDef.name];
3687
- if (parsed.type === "github" && agentPathValue) {
3688
- const hash = await fetchAgentFolderHash(normalizedSource, agentPathValue, getGitHubToken());
3722
+ if (parsed.type === "github" && agentPathValue && bareNormalizedSource) {
3723
+ const hash = await fetchAgentFolderHash(bareNormalizedSource, agentPathValue, getGitHubToken());
3689
3724
  if (hash) agentFolderHash = hash;
3690
3725
  }
3691
3726
  const installs = {};
@@ -5107,26 +5142,29 @@ async function runCheck(args = []) {
5107
5142
  console.log(`${DIM}Checking ${totalAgents} agent(s) for updates...${RESET}`);
5108
5143
  const updates = [];
5109
5144
  const errors = [];
5110
- for (const [source, agents] of agentsBySource) for (const { name, entry } of agents) try {
5111
- const latestHash = await fetchAgentFolderHash(source, entry.agentPath, token);
5112
- if (!latestHash) {
5145
+ for (const [source, agents] of agentsBySource) {
5146
+ const bareSource = stripHost(source) ?? source;
5147
+ for (const { name, entry } of agents) try {
5148
+ const latestHash = await fetchAgentFolderHash(bareSource, entry.agentPath, token);
5149
+ if (!latestHash) {
5150
+ errors.push({
5151
+ name,
5152
+ source,
5153
+ error: "Could not fetch from GitHub"
5154
+ });
5155
+ continue;
5156
+ }
5157
+ if (latestHash !== entry.agentFolderHash) updates.push({
5158
+ name,
5159
+ source
5160
+ });
5161
+ } catch (err) {
5113
5162
  errors.push({
5114
5163
  name,
5115
5164
  source,
5116
- error: "Could not fetch from GitHub"
5165
+ error: err instanceof Error ? err.message : "Unknown error"
5117
5166
  });
5118
- continue;
5119
5167
  }
5120
- if (latestHash !== entry.agentFolderHash) updates.push({
5121
- name,
5122
- source
5123
- });
5124
- } catch (err) {
5125
- errors.push({
5126
- name,
5127
- source,
5128
- error: err instanceof Error ? err.message : "Unknown error"
5129
- });
5130
5168
  }
5131
5169
  console.log();
5132
5170
  if (updates.length === 0) console.log(`${TEXT}✓ All agents are up to date${RESET}`);
@@ -5177,7 +5215,7 @@ async function runUpdate() {
5177
5215
  continue;
5178
5216
  }
5179
5217
  try {
5180
- const latestHash = await fetchAgentFolderHash(entry.source, entry.agentPath, token);
5218
+ const latestHash = await fetchAgentFolderHash(stripHost(entry.source) ?? entry.source, entry.agentPath, token);
5181
5219
  if (latestHash && latestHash !== entry.agentFolderHash) updates.push({
5182
5220
  name: agentName,
5183
5221
  source: entry.source,
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "agentshq",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "The package manager for AI coding agents. Discover, install, and manage agent definitions across 43+ IDEs.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "agentshq": "./bin/cli.mjs",
8
- "add-agent": "./bin/cli.mjs"
7
+ "agentshq": "bin/cli.mjs",
8
+ "add-agent": "bin/cli.mjs"
9
9
  },
10
10
  "files": [
11
11
  "dist",
@@ -22,13 +22,51 @@
22
22
  "type-check": "tsc --noEmit"
23
23
  },
24
24
  "keywords": [
25
- "cli", "agent-definitions", "agents", "ai-agents", "amp", "antigravity", "augment",
26
- "claude-code", "openclaw", "cline", "codebuddy", "codex", "command-code",
27
- "continue", "cortex", "crush", "cursor", "droid", "gemini-cli",
28
- "github-copilot", "goose", "junie", "iflow-cli", "kilo", "kimi-cli",
29
- "kiro-cli", "kode", "mcpjam", "mistral-vibe", "mux", "opencode",
30
- "openhands", "pi", "qoder", "qwen-code", "replit", "roo", "trae",
31
- "trae-cn", "warp", "windsurf", "zencoder", "neovate", "pochi", "adal",
25
+ "cli",
26
+ "agent-definitions",
27
+ "agents",
28
+ "ai-agents",
29
+ "amp",
30
+ "antigravity",
31
+ "augment",
32
+ "claude-code",
33
+ "openclaw",
34
+ "cline",
35
+ "codebuddy",
36
+ "codex",
37
+ "command-code",
38
+ "continue",
39
+ "cortex",
40
+ "crush",
41
+ "cursor",
42
+ "droid",
43
+ "gemini-cli",
44
+ "github-copilot",
45
+ "goose",
46
+ "junie",
47
+ "iflow-cli",
48
+ "kilo",
49
+ "kimi-cli",
50
+ "kiro-cli",
51
+ "kode",
52
+ "mcpjam",
53
+ "mistral-vibe",
54
+ "mux",
55
+ "opencode",
56
+ "openhands",
57
+ "pi",
58
+ "qoder",
59
+ "qwen-code",
60
+ "replit",
61
+ "roo",
62
+ "trae",
63
+ "trae-cn",
64
+ "warp",
65
+ "windsurf",
66
+ "zencoder",
67
+ "neovate",
68
+ "pochi",
69
+ "adal",
32
70
  "universal"
33
71
  ],
34
72
  "repository": {