agentshq 0.1.0 → 0.1.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.
- package/dist/cli.mjs +76 -38
- package/package.json +48 -10
package/dist/cli.mjs
CHANGED
|
@@ -22,36 +22,57 @@ import { createHash } from "crypto";
|
|
|
22
22
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
23
23
|
const AGENTS_DIR$1 = ".agents";
|
|
24
24
|
const AGENTS_SUBDIR = "agents";
|
|
25
|
-
/** Base URL for the agents website
|
|
25
|
+
/** Base URL for the agents website (display links). Override with AGENTS_BASE_URL env var. */
|
|
26
26
|
const BASE_URL = process.env.AGENTS_BASE_URL || "https://agentshq.sh";
|
|
27
|
+
/** Base URL for API requests. Override with AGENTS_API_URL env var. */
|
|
28
|
+
const API_URL = process.env.AGENTS_API_URL || "https://api.agentshq.sh";
|
|
27
29
|
/** Default repo for agent definitions */
|
|
28
30
|
const DEFAULT_REPO = "ulpi-io/agents";
|
|
29
31
|
//#endregion
|
|
30
32
|
//#region src/source-parser.ts
|
|
31
33
|
/**
|
|
32
|
-
* Extract owner/repo (
|
|
34
|
+
* Extract host/owner/repo (e.g., "github.com/ulpi-io/agents") from a parsed source
|
|
33
35
|
* for lockfile tracking and telemetry.
|
|
34
36
|
* Returns null for local paths or unparseable sources.
|
|
35
|
-
*
|
|
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.
|
|
36
42
|
*/
|
|
37
43
|
function getOwnerRepo(parsed) {
|
|
38
44
|
if (parsed.type === "local") return null;
|
|
39
|
-
const sshMatch = parsed.url.match(/^git@[^:]
|
|
45
|
+
const sshMatch = parsed.url.match(/^git@([^:]+):(.+)$/);
|
|
40
46
|
if (sshMatch) {
|
|
41
|
-
|
|
47
|
+
const host = sshMatch[1];
|
|
48
|
+
let path = sshMatch[2];
|
|
42
49
|
path = path.replace(/\.git$/, "");
|
|
43
|
-
if (path.includes("/")) return path
|
|
50
|
+
if (path.includes("/")) return `${host}/${path}`;
|
|
44
51
|
return null;
|
|
45
52
|
}
|
|
46
53
|
if (!parsed.url.startsWith("http://") && !parsed.url.startsWith("https://")) return null;
|
|
47
54
|
try {
|
|
48
|
-
|
|
55
|
+
const url = new URL(parsed.url);
|
|
56
|
+
const host = url.hostname;
|
|
57
|
+
let path = url.pathname.slice(1);
|
|
49
58
|
path = path.replace(/\.git$/, "");
|
|
50
|
-
if (path.includes("/")) return path
|
|
59
|
+
if (path.includes("/")) return `${host}/${path}`;
|
|
51
60
|
} catch {}
|
|
52
61
|
return null;
|
|
53
62
|
}
|
|
54
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
|
+
/**
|
|
55
76
|
* Extract owner and repo from an owner/repo string.
|
|
56
77
|
* Returns null if the format is invalid.
|
|
57
78
|
*/
|
|
@@ -629,9 +650,9 @@ function detectFormat(filePath) {
|
|
|
629
650
|
function parseFromFlatMd(content, filePath) {
|
|
630
651
|
try {
|
|
631
652
|
const { data, content: body } = (0, import_gray_matter.default)(content);
|
|
632
|
-
const name = typeof data.name === "string" && data.name.length > 0 ? data.name :
|
|
653
|
+
const name = typeof data.name === "string" && data.name.length > 0 ? data.name : void 0;
|
|
633
654
|
const description = typeof data.description === "string" && data.description.length > 0 ? data.description : void 0;
|
|
634
|
-
if (!name
|
|
655
|
+
if (!name) return null;
|
|
635
656
|
return {
|
|
636
657
|
name,
|
|
637
658
|
description: description ?? "",
|
|
@@ -999,26 +1020,36 @@ async function discoverAgents(basePath, subpath, options) {
|
|
|
999
1020
|
join(searchPath, "agents/.system"),
|
|
1000
1021
|
join(searchPath, ".agent/agents"),
|
|
1001
1022
|
join(searchPath, ".agents/agents"),
|
|
1023
|
+
join(searchPath, ".augment/agents"),
|
|
1002
1024
|
join(searchPath, ".claude/agents"),
|
|
1003
1025
|
join(searchPath, ".cline/agents"),
|
|
1004
1026
|
join(searchPath, ".codebuddy/agents"),
|
|
1005
1027
|
join(searchPath, ".codex/agents"),
|
|
1006
1028
|
join(searchPath, ".commandcode/agents"),
|
|
1007
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"),
|
|
1008
1034
|
join(searchPath, ".github/agents"),
|
|
1009
1035
|
join(searchPath, ".goose/agents"),
|
|
1010
1036
|
join(searchPath, ".iflow/agents"),
|
|
1011
1037
|
join(searchPath, ".junie/agents"),
|
|
1012
1038
|
join(searchPath, ".kilocode/agents"),
|
|
1013
1039
|
join(searchPath, ".kiro/agents"),
|
|
1040
|
+
join(searchPath, ".kode/agents"),
|
|
1041
|
+
join(searchPath, ".mcpjam/agents"),
|
|
1014
1042
|
join(searchPath, ".mux/agents"),
|
|
1015
1043
|
join(searchPath, ".neovate/agents"),
|
|
1016
1044
|
join(searchPath, ".opencode/agents"),
|
|
1017
1045
|
join(searchPath, ".openhands/agents"),
|
|
1018
1046
|
join(searchPath, ".pi/agents"),
|
|
1047
|
+
join(searchPath, ".pochi/agents"),
|
|
1019
1048
|
join(searchPath, ".qoder/agents"),
|
|
1049
|
+
join(searchPath, ".qwen/agents"),
|
|
1020
1050
|
join(searchPath, ".roo/agents"),
|
|
1021
1051
|
join(searchPath, ".trae/agents"),
|
|
1052
|
+
join(searchPath, ".vibe/agents"),
|
|
1022
1053
|
join(searchPath, ".windsurf/agents"),
|
|
1023
1054
|
join(searchPath, ".zencoder/agents")
|
|
1024
1055
|
];
|
|
@@ -2632,8 +2663,8 @@ async function listInstalledAgents(options = {}) {
|
|
|
2632
2663
|
}
|
|
2633
2664
|
//#endregion
|
|
2634
2665
|
//#region src/telemetry.ts
|
|
2635
|
-
const TELEMETRY_URL = `${
|
|
2636
|
-
const AUDIT_URL = `${
|
|
2666
|
+
const TELEMETRY_URL = `${API_URL}/t`;
|
|
2667
|
+
const AUDIT_URL = `${API_URL}/audit`;
|
|
2637
2668
|
let cliVersion = null;
|
|
2638
2669
|
function isCI() {
|
|
2639
2670
|
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.BUILDKITE || process.env.JENKINS_URL || process.env.TEAMCITY_VERSION);
|
|
@@ -2914,7 +2945,7 @@ var WellKnownProvider = class {
|
|
|
2914
2945
|
const wellKnownProvider = new WellKnownProvider();
|
|
2915
2946
|
//#endregion
|
|
2916
2947
|
//#region package.json
|
|
2917
|
-
var version$1 = "0.1.
|
|
2948
|
+
var version$1 = "0.1.3";
|
|
2918
2949
|
//#endregion
|
|
2919
2950
|
//#region src/add.ts
|
|
2920
2951
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
@@ -3131,8 +3162,9 @@ async function handleWellKnownAgents(source, url, options, spinner) {
|
|
|
3131
3162
|
options: agentDefs.map((s) => ({
|
|
3132
3163
|
value: s,
|
|
3133
3164
|
label: s.installName,
|
|
3134
|
-
hint: s.description
|
|
3165
|
+
hint: s.description
|
|
3135
3166
|
})),
|
|
3167
|
+
initialValues: agentDefs,
|
|
3136
3168
|
required: true
|
|
3137
3169
|
});
|
|
3138
3170
|
if (pD(selected)) {
|
|
@@ -3262,7 +3294,7 @@ async function handleWellKnownAgents(source, url, options, spinner) {
|
|
|
3262
3294
|
if (await isSourcePrivate(sourceIdentifier) !== true) track({
|
|
3263
3295
|
event: "install",
|
|
3264
3296
|
source: sourceIdentifier,
|
|
3265
|
-
agents:
|
|
3297
|
+
agents: selectedAgents.map((s) => s.installName).join(","),
|
|
3266
3298
|
...installGlobally && { global: "1" },
|
|
3267
3299
|
agentFiles: JSON.stringify(agentFiles),
|
|
3268
3300
|
sourceType: "well-known"
|
|
@@ -3477,7 +3509,7 @@ async function runAdd(args, options = {}) {
|
|
|
3477
3509
|
grouped[groupName].push({
|
|
3478
3510
|
value: s,
|
|
3479
3511
|
label: getAgentDisplayName(s),
|
|
3480
|
-
hint: s.description
|
|
3512
|
+
hint: s.description
|
|
3481
3513
|
});
|
|
3482
3514
|
}
|
|
3483
3515
|
selected = await be({
|
|
@@ -3490,8 +3522,9 @@ async function runAdd(args, options = {}) {
|
|
|
3490
3522
|
options: sortedAgents.map((s) => ({
|
|
3491
3523
|
value: s,
|
|
3492
3524
|
label: getAgentDisplayName(s),
|
|
3493
|
-
hint: s.description
|
|
3525
|
+
hint: s.description
|
|
3494
3526
|
})),
|
|
3527
|
+
initialValues: sortedAgents,
|
|
3495
3528
|
required: true
|
|
3496
3529
|
});
|
|
3497
3530
|
if (pD(selected)) {
|
|
@@ -3502,7 +3535,8 @@ async function runAdd(args, options = {}) {
|
|
|
3502
3535
|
selectedAgents = selected;
|
|
3503
3536
|
}
|
|
3504
3537
|
const ownerRepoForAudit = getOwnerRepo(parsed);
|
|
3505
|
-
const
|
|
3538
|
+
const bareOwnerRepo = ownerRepoForAudit ? stripHost(ownerRepoForAudit) : null;
|
|
3539
|
+
const ownerRepoParsed = bareOwnerRepo ? parseOwnerRepo(bareOwnerRepo) : null;
|
|
3506
3540
|
const repoIsPrivate = ownerRepoParsed ? await isRepoPrivate(ownerRepoParsed.owner, ownerRepoParsed.repo) : null;
|
|
3507
3541
|
const auditPromise = ownerRepoForAudit && repoIsPrivate === false ? fetchAuditData(ownerRepoForAudit, selectedAgents.map((s) => getAgentDisplayName(s))) : Promise.resolve(null);
|
|
3508
3542
|
let targetIdes;
|
|
@@ -3667,11 +3701,12 @@ async function runAdd(args, options = {}) {
|
|
|
3667
3701
|
agentFiles[agentDef.name] = relativePath;
|
|
3668
3702
|
}
|
|
3669
3703
|
const normalizedSource = getOwnerRepo(parsed);
|
|
3704
|
+
const bareNormalizedSource = normalizedSource ? stripHost(normalizedSource) : null;
|
|
3670
3705
|
const lockSource = parsed.url.startsWith("git@") ? parsed.url : normalizedSource;
|
|
3671
3706
|
if (normalizedSource && repoIsPrivate !== true) track({
|
|
3672
3707
|
event: "install",
|
|
3673
3708
|
source: normalizedSource,
|
|
3674
|
-
agents:
|
|
3709
|
+
agents: selectedAgents.map((s) => getAgentDisplayName(s)).join(","),
|
|
3675
3710
|
...installGlobally && { global: "1" },
|
|
3676
3711
|
agentFiles: JSON.stringify(agentFiles)
|
|
3677
3712
|
});
|
|
@@ -3682,8 +3717,8 @@ async function runAdd(args, options = {}) {
|
|
|
3682
3717
|
if (successfulAgentNames.has(agentDisplayName)) try {
|
|
3683
3718
|
let agentFolderHash = "";
|
|
3684
3719
|
const agentPathValue = agentFiles[agentDef.name];
|
|
3685
|
-
if (parsed.type === "github" && agentPathValue) {
|
|
3686
|
-
const hash = await fetchAgentFolderHash(
|
|
3720
|
+
if (parsed.type === "github" && agentPathValue && bareNormalizedSource) {
|
|
3721
|
+
const hash = await fetchAgentFolderHash(bareNormalizedSource, agentPathValue, getGitHubToken());
|
|
3687
3722
|
if (hash) agentFolderHash = hash;
|
|
3688
3723
|
}
|
|
3689
3724
|
const installs = {};
|
|
@@ -3878,7 +3913,7 @@ const BOLD$2 = "\x1B[1m";
|
|
|
3878
3913
|
const DIM$2 = "\x1B[38;5;102m";
|
|
3879
3914
|
const TEXT$1 = "\x1B[38;5;145m";
|
|
3880
3915
|
const CYAN$1 = "\x1B[36m";
|
|
3881
|
-
const SEARCH_API_BASE =
|
|
3916
|
+
const SEARCH_API_BASE = API_URL;
|
|
3882
3917
|
function formatInstalls(count) {
|
|
3883
3918
|
if (!count || count <= 0) return "";
|
|
3884
3919
|
if (count >= 1e6) return `${(count / 1e6).toFixed(1).replace(/\.0$/, "")}M installs`;
|
|
@@ -5105,26 +5140,29 @@ async function runCheck(args = []) {
|
|
|
5105
5140
|
console.log(`${DIM}Checking ${totalAgents} agent(s) for updates...${RESET}`);
|
|
5106
5141
|
const updates = [];
|
|
5107
5142
|
const errors = [];
|
|
5108
|
-
for (const [source, agents] of agentsBySource)
|
|
5109
|
-
const
|
|
5110
|
-
|
|
5143
|
+
for (const [source, agents] of agentsBySource) {
|
|
5144
|
+
const bareSource = stripHost(source) ?? source;
|
|
5145
|
+
for (const { name, entry } of agents) try {
|
|
5146
|
+
const latestHash = await fetchAgentFolderHash(bareSource, entry.agentPath, token);
|
|
5147
|
+
if (!latestHash) {
|
|
5148
|
+
errors.push({
|
|
5149
|
+
name,
|
|
5150
|
+
source,
|
|
5151
|
+
error: "Could not fetch from GitHub"
|
|
5152
|
+
});
|
|
5153
|
+
continue;
|
|
5154
|
+
}
|
|
5155
|
+
if (latestHash !== entry.agentFolderHash) updates.push({
|
|
5156
|
+
name,
|
|
5157
|
+
source
|
|
5158
|
+
});
|
|
5159
|
+
} catch (err) {
|
|
5111
5160
|
errors.push({
|
|
5112
5161
|
name,
|
|
5113
5162
|
source,
|
|
5114
|
-
error:
|
|
5163
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
5115
5164
|
});
|
|
5116
|
-
continue;
|
|
5117
5165
|
}
|
|
5118
|
-
if (latestHash !== entry.agentFolderHash) updates.push({
|
|
5119
|
-
name,
|
|
5120
|
-
source
|
|
5121
|
-
});
|
|
5122
|
-
} catch (err) {
|
|
5123
|
-
errors.push({
|
|
5124
|
-
name,
|
|
5125
|
-
source,
|
|
5126
|
-
error: err instanceof Error ? err.message : "Unknown error"
|
|
5127
|
-
});
|
|
5128
5166
|
}
|
|
5129
5167
|
console.log();
|
|
5130
5168
|
if (updates.length === 0) console.log(`${TEXT}✓ All agents are up to date${RESET}`);
|
|
@@ -5175,7 +5213,7 @@ async function runUpdate() {
|
|
|
5175
5213
|
continue;
|
|
5176
5214
|
}
|
|
5177
5215
|
try {
|
|
5178
|
-
const latestHash = await fetchAgentFolderHash(entry.source, entry.agentPath, token);
|
|
5216
|
+
const latestHash = await fetchAgentFolderHash(stripHost(entry.source) ?? entry.source, entry.agentPath, token);
|
|
5179
5217
|
if (latestHash && latestHash !== entry.agentFolderHash) updates.push({
|
|
5180
5218
|
name: agentName,
|
|
5181
5219
|
source: entry.source,
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentshq",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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": "
|
|
8
|
-
"add-agent": "
|
|
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",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
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": {
|