@mhmdreza-rafiei/agentry 0.2.1 → 0.2.2

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 comprehensive-skills contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 comprehensive-skills contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,198 +1,249 @@
1
- <div align="center">
2
-
3
- # Agentry
4
-
5
- **Install agents, skills, rules, scripts, and profiles onto coding agents — from any Git repo.**
6
-
7
- Supports **Cursor**, **Claude Code**, **Codex**, **OpenCode**, and [70+ more](#supported-agents).
8
-
9
- [![npm](https://img.shields.io/npm/v/@mhmdreza-rafiei/agentry?style=flat&color=38bdf8)](https://www.npmjs.com/package/@mhmdreza-rafiei/agentry)
10
- [![node](https://img.shields.io/badge/node-%3E%3D22.20-38bdf8?style=flat)](#install)
11
- [![license](https://img.shields.io/badge/license-MIT-38bdf8?style=flat)](LICENSE)
12
- [![stars](https://img.shields.io/github/stars/mhmdreza-rafiei/agentry?style=social)](https://github.com/mhmdreza-rafiei/agentry)
13
-
14
- </div>
15
-
16
- ## Install
17
-
18
- ```bash
19
- npm install -g @mhmdreza-rafiei/agentry
20
- # or
21
- npx @mhmdreza-rafiei/agentry@latest --help
22
- ```
23
-
24
- ## Quick start
25
-
26
- ```bash
27
- # Browse + install skills from a repo
28
- agentry add skills mhmdreza-rafiei/agent-tools
29
-
30
- # Install one skill to Cursor
31
- agentry add skills mhmdreza-rafiei/agent-tools enhance-prompt -a cursor
32
-
33
- # See what is installed
34
- agentry list
35
- agentry list skills
36
- ```
37
-
38
- ## Commands
39
-
40
- | Command | Description |
41
- | --- | --- |
42
- | `agentry add <kind> <source> [selector]` | Discover and install artifacts |
43
- | `agentry add profile <name> [source]` | Apply a local `profile/<name>.yaml` bundle |
44
- | `agentry list` | List installed artifacts |
45
- | `agentry list <kind>` | List installed artifacts of one kind |
46
- | `agentry list <source> [kind] [selector]` | List what a repo/path contains |
47
- | `agentry remove <kind> [source] [selector]` | Remove installs (files + lock) |
48
- | `agentry update [kind] [source] [selector]` | Re-install from source or lockfile |
49
- | `agentry init <kind> [name] [category]` | Scaffold a new artifact |
50
- | `agentry update` | Update the Agentry CLI itself |
51
- | `agentry uninstall` | Uninstall the Agentry CLI |
52
-
53
- `<kind>` is `skill | rule | agent | profile | script` (plurals accepted).
54
-
55
- ### Source formats
56
-
57
- ```bash
58
- # GitHub shorthand
59
- agentry add skills mhmdreza-rafiei/agent-tools
60
-
61
- # Full GitHub URL
62
- agentry add skills https://github.com/mhmdreza-rafiei/agent-tools
63
-
64
- # Tree URL (subdir + ref)
65
- agentry add skills https://github.com/mhmdreza-rafiei/agent-tools/tree/main/skills
66
-
67
- # Local path
68
- agentry add skills ./my-skills
69
-
70
- # Any git URL
71
- agentry add skills git@github.com:mhmdreza-rafiei/agent-tools.git
72
- ```
73
-
74
- ### Options
75
-
76
- | Option | Description |
77
- | --- | --- |
78
- | `-g, --global` | Install into `~` (all projects) |
79
- | `--project` | Install into the current folder (default) |
80
- | `--dir <path>` | Install into a specific folder |
81
- | `-a, --agent <name>` | Target provider(s); repeatable; `*` = all |
82
- | `-l, --list` | Preview only — write nothing |
83
- | `--copy` | Copy instead of symlink for non-universal agents |
84
- | `--all` | Install everything to all agents, no prompts |
85
- | `-y, --yes` | Skip prompts |
86
- | `--description <text>` | `init`: frontmatter description |
87
- | `--alwaysApply` | `init` rule: `alwaysApply: true` |
88
- | `--reference` / `--no-reference` | `init` skill: include `references/TEMPLATE.md` |
89
- | `--skills` / `--agents` / `--rules` / `--scripts` `[src]` | `init` profile: include kinds (optional source) |
90
-
91
- ## Examples
92
-
93
- ```bash
94
- # List everything in a catalog repo
95
- agentry list mhmdreza-rafiei/agent-tools
96
- agentry list mhmdreza-rafiei/agent-tools skills
97
- agentry list mhmdreza-rafiei/agent-tools skills enhance-prompt
98
-
99
- # Install
100
- agentry add skills mhmdreza-rafiei/agent-tools
101
- agentry add skills mhmdreza-rafiei/agent-tools enhance-prompt -a cursor -a claude-code
102
- agentry add rules mhmdreza-rafiei/agent-tools ask-dont-guess
103
- agentry add agents mhmdreza-rafiei/agent-tools frontend-developer
104
-
105
- # Inventory
106
- agentry list
107
- agentry list skills
108
-
109
- # Update / remove by selector or by install source
110
- agentry update skills mhmdreza-rafiei/agent-tools
111
- agentry remove skills enhance-prompt
112
- agentry remove skills mhmdreza-rafiei/agent-tools
113
-
114
- # Scaffold
115
- agentry init skill enhance-prompt prompt --reference
116
- agentry init rule ask-dont-guess --alwaysApply --description "Ask before guessing"
117
- agentry init profile frontend --skills mhmdreza-rafiei/agent-tools -a cursor
118
- ```
119
-
120
- Example catalog used throughout this README: [`mhmdreza-rafiei/agent-tools`](https://github.com/mhmdreza-rafiei/agent-tools).
121
-
122
- ## How it works
123
-
124
- 1. Resolve a source (local path or shallow git clone).
125
- 2. Discover artifacts under `<kind>s/` **and** root markers (`SKILL.md`, `.mdc`).
126
- 3. Let you pick what to install (searchable list + `All`).
127
- 4. Install once to `.agents/skills/<id>` for universal providers; symlink (or `--copy`) for others.
128
- 5. Track installs in `.agentry/lock.json` for remove/update.
129
-
130
- If a clone fails and a prior cache exists, Agentry asks whether to load from cache (`~/.cache/agentry/repos`).
131
-
132
- ## Artifact layouts
133
-
134
- Author installable tools in a source repo like this:
135
-
136
- ### Skills
137
-
138
- ```text
139
- skills/
140
- enhance-prompt/
141
- SKILL.md
142
- references/
143
- TEMPLATE.md
144
- prompt/
145
- rewrite/
146
- SKILL.md
147
- ```
148
-
149
- ### Agents / rules
150
-
151
- ```text
152
- agents/
153
- frontend-developer.mdc
154
- rules/
155
- ask-dont-guess.mdc
156
- ```
157
-
158
- ### Scripts / profiles
159
-
160
- ```text
161
- scripts/
162
- deploy/
163
- README.md
164
- profiles/
165
- frontend.yaml
166
- ```
167
-
168
- Local install profiles (consumed by `agentry add profile`) live at `profile/<name>.yaml`.
169
-
170
- ## Supported agents
171
-
172
- Agentry targets **70+** providers. Universal providers share `.agents/skills/`; others get a symlink or copy.
173
-
174
- | Agent | Skills path |
175
- | --- | --- |
176
- | Cursor | `.agents/skills` |
177
- | Codex | `.agents/skills` |
178
- | OpenCode | `.agents/skills` |
179
- | Gemini CLI | `.agents/skills` |
180
- | Claude Code | `.claude/skills` |
181
- | Windsurf | `.windsurf/skills` |
182
- | … | see `src/registry/agents.ts` |
183
-
184
- ## Development
185
-
186
- ```bash
187
- npm install
188
- npm run typecheck
189
- npm test
190
- npm run build
191
- node dist/cli.mjs --help
192
- ```
193
-
194
- Requires **Node ≥ 22.20**.
195
-
196
- ## License
197
-
198
- [MIT](LICENSE)
1
+ <div align="center">
2
+
3
+ # Agentry
4
+
5
+ **Install agents, skills, rules, scripts, and profiles onto coding agents — from any Git repo.**
6
+
7
+ Supports **Cursor**, **Claude Code**, **Codex**, **OpenCode**, and [70+ more](#supported-agents).
8
+
9
+ [![npm](https://img.shields.io/npm/v/@mhmdreza-rafiei/agentry?style=flat&color=38bdf8)](https://www.npmjs.com/package/@mhmdreza-rafiei/agentry)
10
+ [![node](https://img.shields.io/badge/node-%3E%3D22.20-38bdf8?style=flat)](#install)
11
+ [![license](https://img.shields.io/badge/license-MIT-38bdf8?style=flat)](LICENSE)
12
+ [![stars](https://img.shields.io/github/stars/mhmdreza-rafiei/agentry?style=social)](https://github.com/mhmdreza-rafiei/agentry)
13
+
14
+ </div>
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install -g @mhmdreza-rafiei/agentry
20
+ # or
21
+ npx @mhmdreza-rafiei/agentry@latest --help
22
+ ```
23
+
24
+ ## Quick start
25
+
26
+ ```bash
27
+ # Browse + install skills from a repo
28
+ agentry add skills mhmdreza-rafiei/agent-tools
29
+
30
+ # Install one skill to Cursor
31
+ agentry add skills mhmdreza-rafiei/agent-tools enhance-prompt -a cursor
32
+
33
+ # See what is installed
34
+ agentry list
35
+ agentry list skills
36
+ ```
37
+
38
+ ## What it looks like
39
+
40
+ ```text
41
+ █████╗ ██████╗ ███████╗███╗ ██╗████████╗██████╗ ██╗ ██╗
42
+ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔══██╗╚██╗ ██╔╝
43
+ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██████╔╝ ╚████╔╝
44
+ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██╔══██╗ ╚██╔╝
45
+ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ██║ ██║ ██║
46
+ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
47
+ Install agents, skills, rules & profiles
48
+
49
+ ◇ Cloning mhmdreza-rafiei/agent-tools
50
+ ◇ Found 12 skills
51
+
52
+ ◆ Select skills to install
53
+ │ Search: enhance
54
+ │ ◼ All
55
+ │ ◼ prompt/enhance-prompt
56
+ │ ◻ quick-start
57
+ │
58
+ ◇ Which agents do you want to install to?
59
+ │ Universal (.agents/skills) · Cursor, Codex, …
60
+ │ ◼ Claude Code
61
+
62
+ ◆ Installation scope
63
+ │
64
+ │ ● Project
65
+ │ Install in the current directory (committed with your project)
66
+ │ → /path/to/your-project
67
+ │ lock /path/to/your-project/.agentry/lock.json
68
+ │
69
+ │ ○ Global
70
+ │ Install in your home directory (available across all projects)
71
+ │ → /home/you
72
+ │ lock /home/you/.agentry/lock.json
73
+ └ ↑/↓ select · enter confirm
74
+
75
+ ◆ Install summary
76
+ │ Scope project
77
+ │ Targets 4 agents · 3 universal · 1 additional
78
+ │ Cursor, Codex, OpenCode, Claude Code
79
+ │
80
+ │ Artifacts 1 selected
81
+ │ • skill/prompt/enhance-prompt
82
+ │ Rewrite prompts for clarity and fidelity
83
+ │
84
+ └ Review before use — artifacts run with full agent permissions.
85
+
86
+ ◇ Installed skill/prompt/enhance-prompt
87
+ ```
88
+
89
+ ## Commands
90
+
91
+ | Command | Description |
92
+ | --- | --- |
93
+ | `agentry add <kind> <source> [selector]` | Discover and install artifacts |
94
+ | `agentry add profile <name> [source]` | Apply a local `profile/<name>.yaml` bundle |
95
+ | `agentry list` | List installed artifacts |
96
+ | `agentry list <kind>` | List installed artifacts of one kind |
97
+ | `agentry list <source> [kind] [selector]` | List what a repo/path contains |
98
+ | `agentry remove <kind> [source] [selector]` | Remove installs (files + lock) |
99
+ | `agentry update [kind] [source] [selector]` | Re-install from source or lockfile |
100
+ | `agentry init <kind> [name] [category]` | Scaffold a new artifact |
101
+ | `agentry update` | Update the Agentry CLI itself |
102
+ | `agentry uninstall` | Uninstall the Agentry CLI |
103
+
104
+ `<kind>` is `skill | rule | agent | profile | script` (plurals accepted).
105
+
106
+ ### Source formats
107
+
108
+ ```bash
109
+ # GitHub shorthand
110
+ agentry add skills mhmdreza-rafiei/agent-tools
111
+
112
+ # Full GitHub URL
113
+ agentry add skills https://github.com/mhmdreza-rafiei/agent-tools
114
+
115
+ # Tree URL (subdir + ref)
116
+ agentry add skills https://github.com/mhmdreza-rafiei/agent-tools/tree/main/skills
117
+
118
+ # Local path
119
+ agentry add skills ./my-skills
120
+
121
+ # Any git URL
122
+ agentry add skills git@github.com:mhmdreza-rafiei/agent-tools.git
123
+ ```
124
+
125
+ ### Options
126
+
127
+ | Option | Description |
128
+ | --- | --- |
129
+ | `-g, --global` | Install into `~` (all projects) |
130
+ | `-p, --project` | Install into the current folder |
131
+ | `-d, --dir <path>` | Install into a specific folder |
132
+ | `-a, --agent <name>` | Target provider(s); repeatable; `*` = all |
133
+ | `-l, --list` | Preview only — write nothing |
134
+ | `--copy` | Copy instead of symlink for non-universal agents |
135
+ | `--all` | Install everything to all agents, no prompts |
136
+ | `-y, --yes` | Skip prompts (scope defaults to project) |
137
+ | `--description <text>` | `init`: frontmatter description |
138
+ | `--alwaysApply` | `init` rule: `alwaysApply: true` |
139
+ | `--reference` / `--no-reference` | `init` skill: include `references/TEMPLATE.md` |
140
+ | `--skills` / `--agents` / `--rules` / `--scripts` `[src]` | `init` profile: include kinds (optional source) |
141
+
142
+ ## Examples
143
+
144
+ ```bash
145
+ # List everything in a catalog repo
146
+ agentry list mhmdreza-rafiei/agent-tools
147
+ agentry list mhmdreza-rafiei/agent-tools skills
148
+ agentry list mhmdreza-rafiei/agent-tools skills enhance-prompt
149
+
150
+ # Install
151
+ agentry add skills mhmdreza-rafiei/agent-tools
152
+ agentry add skills mhmdreza-rafiei/agent-tools enhance-prompt -a cursor -a claude-code
153
+ agentry add rules mhmdreza-rafiei/agent-tools ask-dont-guess
154
+ agentry add agents mhmdreza-rafiei/agent-tools frontend-developer
155
+
156
+ # Inventory
157
+ agentry list
158
+ agentry list skills
159
+
160
+ # Update / remove by selector or by install source
161
+ agentry update skills mhmdreza-rafiei/agent-tools
162
+ agentry remove skills enhance-prompt
163
+ agentry remove skills mhmdreza-rafiei/agent-tools
164
+
165
+ # Scaffold
166
+ agentry init skill enhance-prompt prompt --reference
167
+ agentry init rule ask-dont-guess --alwaysApply --description "Ask before guessing"
168
+ agentry init profile frontend --skills mhmdreza-rafiei/agent-tools -a cursor
169
+ ```
170
+
171
+ Example catalog used throughout this README: [`mhmdreza-rafiei/agent-tools`](https://github.com/mhmdreza-rafiei/agent-tools).
172
+
173
+ ## How it works
174
+
175
+ 1. Resolve a source (local path or shallow git clone).
176
+ 2. Discover artifacts under `<kind>s/` **and** root markers (`SKILL.md`, `.mdc`).
177
+ 3. Let you pick what to install (searchable list + `All`).
178
+ 4. Install once to `.agents/skills/<id>` for universal providers; symlink (or `--copy`) for others.
179
+ 5. Track installs in `.agentry/lock.json` for remove/update.
180
+
181
+ If a clone fails and a prior cache exists, Agentry asks whether to load from cache (`~/.cache/agentry/repos`).
182
+
183
+ ## Artifact layouts
184
+
185
+ Author installable tools in a source repo like this:
186
+
187
+ ### Skills
188
+
189
+ ```text
190
+ skills/
191
+ enhance-prompt/
192
+ SKILL.md
193
+ references/
194
+ TEMPLATE.md
195
+ prompt/
196
+ rewrite/
197
+ SKILL.md
198
+ ```
199
+
200
+ ### Agents / rules
201
+
202
+ ```text
203
+ agents/
204
+ frontend-developer.mdc
205
+ rules/
206
+ ask-dont-guess.mdc
207
+ ```
208
+
209
+ ### Scripts / profiles
210
+
211
+ ```text
212
+ scripts/
213
+ deploy/
214
+ README.md
215
+ profiles/
216
+ frontend.yaml
217
+ ```
218
+
219
+ Local install profiles (consumed by `agentry add profile`) live at `profile/<name>.yaml`.
220
+
221
+ ## Supported agents
222
+
223
+ Agentry targets **70+** providers. Universal providers share `.agents/skills/`; others get a symlink or copy.
224
+
225
+ | Agent | Skills path |
226
+ | --- | --- |
227
+ | Cursor | `.agents/skills` |
228
+ | Codex | `.agents/skills` |
229
+ | OpenCode | `.agents/skills` |
230
+ | Gemini CLI | `.agents/skills` |
231
+ | Claude Code | `.claude/skills` |
232
+ | Windsurf | `.windsurf/skills` |
233
+ | … | see `src/registry/agents.ts` |
234
+
235
+ ## Development
236
+
237
+ ```bash
238
+ npm install
239
+ npm run typecheck
240
+ npm test
241
+ npm run build
242
+ node dist/cli.mjs --help
243
+ ```
244
+
245
+ Requires **Node ≥ 22.20**.
246
+
247
+ ## License
248
+
249
+ [MIT](LICENSE)
@@ -122,13 +122,13 @@ function printHelp() {
122
122
  "",
123
123
  h("Options"),
124
124
  ` ${flag("-g, --global")} ${dim("Install into ~ (all projects)")}`,
125
- ` ${flag("--project")} ${dim("Install into the current folder (default)")}`,
126
- ` ${flag("--dir")} ${dim("<p>")} ${dim("Install into a specific folder")}`,
125
+ ` ${flag("-p, --project")} ${dim("Install into the current folder")}`,
126
+ ` ${flag("-d, --dir")} ${dim("<p>")} ${dim("Install into a specific folder")}`,
127
127
  ` ${flag("-a, --agent")} ${dim("<n>")} ${dim("Target provider(s); repeatable; '*' = all")}`,
128
128
  ` ${flag("-l, --list")} ${dim("Preview only — write nothing")}`,
129
129
  ` ${flag("--copy")} ${dim("Copy files instead of symlinking")}`,
130
130
  ` ${flag("--all")} ${dim("Install everything to all agents, no prompts")}`,
131
- ` ${flag("-y, --yes")} ${dim("Don't prompt")}`,
131
+ ` ${flag("-y, --yes")} ${dim("Don't prompt (scope defaults to project)")}`,
132
132
  ` ${flag("--description")} ${dim("<t>")} ${dim("init: frontmatter description")}`,
133
133
  ` ${flag("--alwaysApply")} ${dim("init rule: alwaysApply: true")}`,
134
134
  ` ${flag("--reference")} ${dim("init skill: add references/TEMPLATE.md")}`,
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { animateLogo, badge, delay, printHelp, sky, theme } from "./_chunks/theme2.mjs";
3
- import { execFileSync, execSync } from "node:child_process";
3
+ import { execFileSync } from "node:child_process";
4
4
  import https from "node:https";
5
5
  import { createHash } from "node:crypto";
6
- import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
6
+ import { copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
7
7
  import { homedir, tmpdir } from "node:os";
8
8
  import { dirname, join, resolve, sep } from "node:path";
9
9
  import { xdgCache, xdgConfig } from "xdg-basedir";
@@ -16,7 +16,7 @@ import { determineAgent } from "@vercel/detect-agent";
16
16
  import { stripVTControlCharacters } from "node:util";
17
17
  import { Writable } from "node:stream";
18
18
  var name = "@mhmdreza-rafiei/agentry";
19
- var version = "0.2.0";
19
+ var version = "0.2.2";
20
20
  const ARTIFACT_KINDS = [
21
21
  "skill",
22
22
  "rule",
@@ -34,15 +34,21 @@ function isLocalPath(source) {
34
34
  return false;
35
35
  }
36
36
  }
37
+ const SAFE_REF$1 = /^[a-zA-Z0-9][\w./-]*$/;
37
38
  function parseGithubTreeUrl(url) {
38
39
  const m = url.match(/^https?:\/\/github\.com\/([\w.-]+\/[\w.-]+?)\/tree\/([^/]+)\/(.+)$/);
39
40
  if (!m) return null;
41
+ const ref = m[2];
42
+ if (!SAFE_REF$1.test(ref)) throw new Error(`Invalid git ref in source URL: "${ref}"`);
40
43
  return {
41
44
  ownerRepo: m[1],
42
- ref: m[2],
45
+ ref,
43
46
  subpath: m[3].replace(/\/+$/, "")
44
47
  };
45
48
  }
49
+ function redactUrl(url) {
50
+ return url.replace(/:\/\/([^/@]+)@/g, "://***@");
51
+ }
46
52
  function parseSource(source) {
47
53
  if (!source || typeof source !== "string") throw new Error("Empty source.");
48
54
  const raw = source;
@@ -140,7 +146,9 @@ function saveToCache(parsed, clonedRoot) {
140
146
  cpSync(clonedRoot, dest, { recursive: true });
141
147
  } catch {}
142
148
  }
149
+ const SAFE_REF = /^[a-zA-Z0-9][\w./-]*$/;
143
150
  function cloneTo(url, dest, ref) {
151
+ if (ref && !SAFE_REF.test(ref)) throw new Error(`Invalid git ref: "${ref}"`);
144
152
  execFileSync("git", [
145
153
  "clone",
146
154
  "--quiet",
@@ -158,28 +166,39 @@ function cloneTo(url, dest, ref) {
158
166
  "pipe"
159
167
  ] });
160
168
  }
169
+ function assertInsideRoot(root, candidate) {
170
+ const base = resolve(root);
171
+ const resolved = resolve(candidate);
172
+ const prefix = base.endsWith(sep) ? base : base + sep;
173
+ const a = resolved.toLowerCase();
174
+ const b = base.toLowerCase();
175
+ const p = prefix.toLowerCase();
176
+ if (a !== b && !a.startsWith(p)) throw new Error(`Path escapes source root: "${candidate}"`);
177
+ return resolved;
178
+ }
161
179
  function withSubpath(root, subpath, cleanupRoot) {
180
+ const cleanup = () => rmSync(cleanupRoot, {
181
+ recursive: true,
182
+ force: true
183
+ });
162
184
  if (!subpath) return {
163
185
  root,
164
- cleanup: () => rmSync(cleanupRoot, {
165
- recursive: true,
166
- force: true
167
- })
186
+ cleanup
168
187
  };
169
- const sub = join(root, subpath);
188
+ let sub;
189
+ try {
190
+ sub = assertInsideRoot(root, join(root, subpath));
191
+ } catch (e) {
192
+ cleanup();
193
+ throw e;
194
+ }
170
195
  if (!existsSync(sub)) {
171
- rmSync(cleanupRoot, {
172
- recursive: true,
173
- force: true
174
- });
196
+ cleanup();
175
197
  throw new Error(`Subpath "${subpath}" not found.`);
176
198
  }
177
199
  return {
178
200
  root: sub,
179
- cleanup: () => rmSync(cleanupRoot, {
180
- recursive: true,
181
- force: true
182
- })
201
+ cleanup
183
202
  };
184
203
  }
185
204
  async function resolveSource(source, opts = {}) {
@@ -193,6 +212,7 @@ async function resolveSource(source, opts = {}) {
193
212
  }
194
213
  const url = parsed.url;
195
214
  if (!url) throw new Error(`Cannot resolve source "${parsed.raw}".`);
215
+ const safeUrl = redactUrl(url);
196
216
  const tmp = mkdtempSync(join(tmpdir(), "agentry-src-"));
197
217
  try {
198
218
  cloneTo(url, tmp, parsed.ref);
@@ -206,7 +226,7 @@ async function resolveSource(source, opts = {}) {
206
226
  const cacheOk = existsSync(cached) && existsSync(join(cached, ".git"));
207
227
  if (cacheOk && opts.confirmCache) {
208
228
  if (await opts.confirmCache({
209
- url,
229
+ url: safeUrl,
210
230
  cacheDir: cached,
211
231
  error: detail
212
232
  })) {
@@ -218,7 +238,7 @@ async function resolveSource(source, opts = {}) {
218
238
  };
219
239
  }
220
240
  }
221
- throw new Error(`git clone failed for ${url}\n${detail}${cacheOk ? "\n(A local cache exists — re-run interactively to load it, or pass -y to auto-use cache.)" : ""}`);
241
+ throw new Error(`git clone failed for ${safeUrl}\n${detail}${cacheOk ? "\n(A local cache exists — re-run interactively to load it, or pass -y to auto-use cache.)" : ""}`);
222
242
  }
223
243
  saveToCache(parsed, tmp);
224
244
  return withSubpath(tmp, parsed.subpath, tmp);
@@ -563,6 +583,38 @@ function getNonUniversalAgents() {
563
583
  return listAgents().filter((a) => a.skillsDir !== ".agents/skills");
564
584
  }
565
585
  const home = homedir();
586
+ function copyTreeDereferenced(src, dest, seen = /* @__PURE__ */ new Set()) {
587
+ const st = lstatSync(src);
588
+ if (st.isSymbolicLink()) {
589
+ let real;
590
+ try {
591
+ real = realpathSync(src);
592
+ } catch {
593
+ return;
594
+ }
595
+ if (seen.has(real)) return;
596
+ seen.add(real);
597
+ copyTreeDereferenced(real, dest, seen);
598
+ return;
599
+ }
600
+ if (st.isDirectory()) {
601
+ let real;
602
+ try {
603
+ real = realpathSync(src);
604
+ } catch {
605
+ real = resolve(src);
606
+ }
607
+ if (seen.has(real)) return;
608
+ seen.add(real);
609
+ mkdirSync(dest, { recursive: true });
610
+ for (const name of readdirSync(src)) copyTreeDereferenced(join(src, name), join(dest, name), seen);
611
+ return;
612
+ }
613
+ if (st.isFile()) {
614
+ mkdirSync(dirname(dest), { recursive: true });
615
+ copyFileSync(src, dest);
616
+ }
617
+ }
566
618
  function lockBase(opts) {
567
619
  return opts.scope === "global" ? home : opts.dir || process.cwd();
568
620
  }
@@ -690,7 +742,7 @@ function installOne(artifact, opts, agentList, source) {
690
742
  force: true
691
743
  });
692
744
  mkdirSync(join(canonical, ".."), { recursive: true });
693
- cpSync(artifact.dir, canonical, { recursive: true });
745
+ copyTreeDereferenced(artifact.dir, canonical);
694
746
  for (const a of list) if (a.skillsDir === ".agents/skills") dests.push({
695
747
  agent: a.name,
696
748
  dir: canonical
@@ -703,7 +755,7 @@ function installOne(artifact, opts, agentList, source) {
703
755
  });
704
756
  mkdirSync(join(dir, ".."), { recursive: true });
705
757
  if (opts.copy) {
706
- cpSync(canonical, dir, { recursive: true });
758
+ copyTreeDereferenced(canonical, dir);
707
759
  dests.push({
708
760
  agent: a.name,
709
761
  dir
@@ -716,7 +768,7 @@ function installOne(artifact, opts, agentList, source) {
716
768
  symlinked: true
717
769
  });
718
770
  } catch {
719
- cpSync(canonical, dir, { recursive: true });
771
+ copyTreeDereferenced(canonical, dir);
720
772
  dests.push({
721
773
  agent: a.name,
722
774
  dir
@@ -730,7 +782,7 @@ function installOne(artifact, opts, agentList, source) {
730
782
  force: true
731
783
  });
732
784
  mkdirSync(join(dir, ".."), { recursive: true });
733
- cpSync(artifact.dir, dir, { recursive: true });
785
+ copyTreeDereferenced(artifact.dir, dir);
734
786
  dests.push({
735
787
  agent: a.name,
736
788
  dir
@@ -1417,6 +1469,98 @@ function agentsPrompt(action) {
1417
1469
  if (action === "update") return "Which agents do you want to update for?";
1418
1470
  return "Which agents do you want to install to?";
1419
1471
  }
1472
+ function scopePrompt(action) {
1473
+ if (action === "remove") return "Removal scope";
1474
+ if (action === "update") return "Update scope";
1475
+ return "Installation scope";
1476
+ }
1477
+ async function selectInstallScope(message, paths) {
1478
+ if (isQuiet()) return "project";
1479
+ return new Promise((resolve) => {
1480
+ if (!process.stdin.isTTY) {
1481
+ resolve("project");
1482
+ return;
1483
+ }
1484
+ const rl = readline.createInterface({
1485
+ input: process.stdin,
1486
+ output: process.stdout
1487
+ });
1488
+ process.stdin.setRawMode(true);
1489
+ readline.emitKeypressEvents(process.stdin, rl);
1490
+ let value = "project";
1491
+ let lastH = 0;
1492
+ const joinRel = (base, rel) => {
1493
+ const sep = base.includes("\\") ? "\\" : "/";
1494
+ return `${base.replace(/[\\/]+$/, "")}${sep}${rel.replace(/\//g, sep)}`;
1495
+ };
1496
+ const optionBlock = (key, selected, done) => {
1497
+ const active = done ? done === key : selected;
1498
+ const bullet = active ? sky(c.bold("●")) : c.dim("○");
1499
+ const title = key === "project" ? "Project" : "Global";
1500
+ const hint = key === "project" ? "Install in the current directory (committed with your project)" : "Install in your home directory (available across all projects)";
1501
+ const path = key === "project" ? paths.projectDir : paths.homeDir;
1502
+ const lock = key === "project" ? joinRel(paths.projectDir, ".agentry/lock.json") : joinRel(paths.homeDir, ".agentry/lock.json");
1503
+ const lines = [];
1504
+ if (done === "cancel") lines.push(`${c.dim("│")} ${c.strikethrough(c.dim(title))}`);
1505
+ else {
1506
+ lines.push(`${c.dim("│")} ${bullet} ${active ? c.bold(title) : title}`);
1507
+ lines.push(`${c.dim("│")} ${c.dim(hint)}`);
1508
+ lines.push(`${c.dim("│")} ${sky("→")} ${c.dim(path)}`);
1509
+ lines.push(`${c.dim("│")} ${c.dim(`lock ${lock}`)}`);
1510
+ }
1511
+ return lines;
1512
+ };
1513
+ const paint = (done) => {
1514
+ const lines = [];
1515
+ if (done === "cancel") {
1516
+ lines.push(`${sky("■")} ${c.bold(message)}`);
1517
+ lines.push(`${c.dim("│")} ${c.strikethrough(c.dim("Cancelled"))}`);
1518
+ } else if (done === "project" || done === "global") {
1519
+ lines.push(`${sky("◇")} ${c.bold(message)}`);
1520
+ lines.push(...optionBlock(done, true, done).slice(0, 2));
1521
+ lines.push(`${c.dim("│")} ${sky("→")} ${c.dim(done === "project" ? paths.projectDir : paths.homeDir)}`);
1522
+ } else {
1523
+ lines.push(`${sky("◆")} ${c.bold(message)}`);
1524
+ lines.push(`${c.dim("│")}`);
1525
+ lines.push(...optionBlock("project", value === "project"));
1526
+ lines.push(`${c.dim("│")}`);
1527
+ lines.push(...optionBlock("global", value === "global"));
1528
+ lines.push(`${c.dim("└")} ${c.dim("↑/↓ select · enter confirm")}`);
1529
+ }
1530
+ if (lastH > 0) for (let i = 0; i < lastH; i++) process.stdout.write("\x1B[1A\x1B[2K");
1531
+ process.stdout.write(lines.join("\n") + "\n");
1532
+ lastH = lines.length;
1533
+ };
1534
+ const cleanup = () => {
1535
+ process.stdin.removeListener("keypress", onKey);
1536
+ process.stdin.setRawMode(false);
1537
+ rl.close();
1538
+ };
1539
+ const onKey = (_s, key) => {
1540
+ if (!key) return;
1541
+ if (key.name === "up" || key.name === "down" || key.name === "tab") {
1542
+ value = value === "project" ? "global" : "project";
1543
+ paint();
1544
+ return;
1545
+ }
1546
+ if (key.name === "return") {
1547
+ paint(value);
1548
+ cleanup();
1549
+ blank();
1550
+ resolve(value);
1551
+ return;
1552
+ }
1553
+ if (key.name === "escape" || key.ctrl && key.name === "c") {
1554
+ paint("cancel");
1555
+ cleanup();
1556
+ resolve(null);
1557
+ }
1558
+ };
1559
+ process.stdin.on("keypress", onKey);
1560
+ blank();
1561
+ paint();
1562
+ });
1563
+ }
1420
1564
  function isQuiet() {
1421
1565
  return isCI() || !process.stdout.isTTY;
1422
1566
  }
@@ -1814,7 +1958,10 @@ async function cmdAdd(kind, source, selector, opts) {
1814
1958
  blank();
1815
1959
  }
1816
1960
  const agentList = await resolveAgentList(opts, "install");
1817
- if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${agentList.length} agent${agentList.length === 1 ? "" : "s"} selected`, "install summary");
1961
+ const askScope = !opts.scopeExplicit && !opts.yes && !isQuiet();
1962
+ if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${agentList.length} agent${agentList.length === 1 ? "" : "s"} selected`, askScope ? "installation scope" : "install summary");
1963
+ if (!await ensureInstallScope(opts, "install")) return;
1964
+ if (askScope) await sectionTransition("scope set", "install summary");
1818
1965
  installAll(chosen, opts, agentList, source);
1819
1966
  } finally {
1820
1967
  cleanup();
@@ -1833,6 +1980,7 @@ async function cmdAddProfile(name, source, opts) {
1833
1980
  const repo = source || (profile.artifacts.skills[0]?.source ?? profile.artifacts.rules[0]?.source);
1834
1981
  if (!repo) throw new Error(`No source given and ${file} lists none. Try: agentry add profile ${name} author/repo`);
1835
1982
  const agentList = await resolveAgentList(opts, "install");
1983
+ if (!await ensureInstallScope(opts, "install")) return;
1836
1984
  const { root, cleanup } = await resolveSourceWithUi(repo, opts);
1837
1985
  try {
1838
1986
  const artifacts = [];
@@ -1878,6 +2026,23 @@ async function resolveAgentList(opts, action = "install") {
1878
2026
  if (isCancelLike(selected)) throw new Error("Cancelled.");
1879
2027
  return selected;
1880
2028
  }
2029
+ async function ensureInstallScope(opts, action) {
2030
+ if (opts.scopeExplicit) return true;
2031
+ if (opts.yes || isQuiet()) return true;
2032
+ const { homedir } = await import("node:os");
2033
+ if (!isQuiet()) await sectionTransition(`${action === "install" ? "agents" : action} ready`, scopePrompt(action).toLowerCase());
2034
+ const picked = await selectInstallScope(scopePrompt(action), {
2035
+ projectDir: opts.dir || process.cwd(),
2036
+ homeDir: homedir()
2037
+ });
2038
+ if (picked == null || isCancelLike(picked)) {
2039
+ outro("Cancelled.");
2040
+ return false;
2041
+ }
2042
+ opts.scope = picked;
2043
+ opts.scopeExplicit = true;
2044
+ return true;
2045
+ }
1881
2046
  function installAll(artifacts, opts, agentList, source) {
1882
2047
  if (!artifacts.length) {
1883
2048
  warn("Nothing matched - nothing installed.");
@@ -1904,8 +2069,22 @@ function resolveSourceOrSelector(arg1, arg2, opts) {
1904
2069
  if (!arg1) return {};
1905
2070
  if (isExplicitSource(arg1)) return { source: arg1 };
1906
2071
  if (isOwnerRepoShape(arg1)) {
1907
- const lock = readLock(toInstallOpts(opts));
1908
- if (Object.values(lock.items).some((e) => e.source && sourcesEqual(e.source, arg1))) return { source: arg1 };
2072
+ const bases = [{
2073
+ scope: "project",
2074
+ dir: opts.dir,
2075
+ agents: opts.agents,
2076
+ copy: opts.copy,
2077
+ dryRun: opts.dryRun
2078
+ }, {
2079
+ scope: "global",
2080
+ agents: opts.agents,
2081
+ copy: opts.copy,
2082
+ dryRun: opts.dryRun
2083
+ }];
2084
+ for (const base of bases) {
2085
+ const lock = readLock(base);
2086
+ if (Object.values(lock.items).some((e) => e.source && sourcesEqual(e.source, arg1))) return { source: arg1 };
2087
+ }
1909
2088
  }
1910
2089
  return { selector: arg1 };
1911
2090
  }
@@ -1918,6 +2097,7 @@ async function cmdRemove(kind, arg1, arg2, opts) {
1918
2097
  }, 420);
1919
2098
  if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition("prepare remove", "choose agents to remove from");
1920
2099
  const agentList = await resolveAgentList(opts, "remove");
2100
+ if (!await ensureInstallScope(opts, "remove")) return;
1921
2101
  const installOpts = toInstallOpts(opts);
1922
2102
  const scope = [
1923
2103
  kind,
@@ -2051,7 +2231,6 @@ function printArtifactList(artifacts, meta) {
2051
2231
  async function cmdUpdateAssets(kind, arg1, arg2, opts) {
2052
2232
  intro();
2053
2233
  const { source, selector } = resolveSourceOrSelector(arg1, arg2, opts);
2054
- const installOpts = toInstallOpts(opts);
2055
2234
  if (source) {
2056
2235
  await spinner("Parsing source…", () => parseSource(source), (p) => {
2057
2236
  const where = p.url || p.local || source;
@@ -2076,6 +2255,7 @@ async function cmdUpdateAssets(kind, arg1, arg2, opts) {
2076
2255
  await sectionTransition(`${chosen.length} ${kind}${chosen.length === 1 ? "" : "s"} selected`, "choose target agents");
2077
2256
  } else if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${chosen.length} ${kind}${chosen.length === 1 ? "" : "s"} ready`, "choose target agents");
2078
2257
  const agentList = await resolveAgentList(opts, "update");
2258
+ if (!await ensureInstallScope(opts, "update")) return;
2079
2259
  if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${agentList.length} agent${agentList.length === 1 ? "" : "s"} selected`, "update summary");
2080
2260
  installAll(chosen, opts, agentList, source);
2081
2261
  } finally {
@@ -2083,7 +2263,8 @@ async function cmdUpdateAssets(kind, arg1, arg2, opts) {
2083
2263
  }
2084
2264
  return;
2085
2265
  }
2086
- let installed = listInstalled(installOpts).filter((it) => kind === "all" || it.id.startsWith(kind + "/"));
2266
+ if (!await ensureInstallScope(opts, "update")) return;
2267
+ let installed = listInstalled(toInstallOpts(opts)).filter((it) => kind === "all" || it.id.startsWith(kind + "/"));
2087
2268
  if (selector) {
2088
2269
  const rel = `${kind}/${selector}`;
2089
2270
  installed = installed.filter((it) => it.id === rel || it.id.startsWith(rel + "/") || it.id.endsWith("/" + selector));
@@ -2308,6 +2489,7 @@ function takeOptValue(argv, i) {
2308
2489
  function parseArgs(argv) {
2309
2490
  const opts = {
2310
2491
  scope: "project",
2492
+ scopeExplicit: false,
2311
2493
  agents: [],
2312
2494
  copy: false,
2313
2495
  dryRun: false,
@@ -2321,15 +2503,19 @@ function parseArgs(argv) {
2321
2503
  const a = argv[i];
2322
2504
  if (a === "-g" || a === "--global") {
2323
2505
  opts.scope = "global";
2506
+ opts.scopeExplicit = true;
2324
2507
  flags.global = true;
2325
- } else if (a === "--project") {
2508
+ } else if (a === "-p" || a === "--project") {
2326
2509
  opts.scope = "project";
2510
+ opts.scopeExplicit = true;
2327
2511
  flags.project = true;
2328
2512
  } else if (a === "-y" || a === "--yes") {
2329
2513
  opts.yes = true;
2330
2514
  flags.yes = true;
2331
- } else if (a === "--dir") {
2515
+ } else if (a === "-d" || a === "--dir") {
2332
2516
  opts.dir = argv[++i];
2517
+ opts.scope = "project";
2518
+ opts.scopeExplicit = true;
2333
2519
  flags.dir = opts.dir;
2334
2520
  } else if (a === "-a" || a === "--agent") {
2335
2521
  opts.agents.push(argv[++i]);
@@ -2420,7 +2606,11 @@ async function runUpdateSelf() {
2420
2606
  function runNpmInstall(spec) {
2421
2607
  spinner(`Updating agentry CLI`, () => {
2422
2608
  try {
2423
- execSync(`npm install -g ${spec}`, { stdio: "inherit" });
2609
+ execFileSync("npm", [
2610
+ "install",
2611
+ "-g",
2612
+ spec
2613
+ ], { stdio: "inherit" });
2424
2614
  } catch {
2425
2615
  err("Update failed. Once published, run: npm install -g " + spec);
2426
2616
  process.exit(1);
@@ -2430,7 +2620,11 @@ function runNpmInstall(spec) {
2430
2620
  function runUninstall() {
2431
2621
  spinner("Uninstalling agentry CLI", () => {
2432
2622
  try {
2433
- execSync(`npm uninstall -g ${name}`, { stdio: "inherit" });
2623
+ execFileSync("npm", [
2624
+ "uninstall",
2625
+ "-g",
2626
+ name
2627
+ ], { stdio: "inherit" });
2434
2628
  } catch {
2435
2629
  err("Uninstall failed. Try: npm uninstall -g " + name);
2436
2630
  process.exit(1);
package/package.json CHANGED
@@ -1,53 +1,61 @@
1
- {
2
- "name": "@mhmdreza-rafiei/agentry",
3
- "version": "0.2.1",
4
- "description": "One CLI to install agents, skills, rules, and profiles onto AI coding agents — portable AI/agent tooling.",
5
- "type": "module",
6
- "bin": {
7
- "agentry": "./dist/cli.mjs"
8
- },
9
- "files": [
10
- "dist",
11
- "README.md",
12
- "LICENSE"
13
- ],
14
- "scripts": {
15
- "dev": "tsx src/cli.ts",
16
- "build": "obuild",
17
- "test": "vitest run",
18
- "test:watch": "vitest",
19
- "typecheck": "tsc --noEmit"
20
- },
21
- "engines": {
22
- "node": ">=22.20.0"
23
- },
24
- "keywords": [
25
- "ai",
26
- "agents",
27
- "skills",
28
- "rules",
29
- "profiles",
30
- "cli",
31
- "cursor",
32
- "claude-code",
33
- "codex",
34
- "agentic",
35
- "scaffold"
36
- ],
37
- "license": "MIT",
38
- "dependencies": {
39
- "@clack/prompts": "^0.7.0",
40
- "@vercel/detect-agent": "^1.2.1",
41
- "picocolors": "^1.1.1",
42
- "xdg-basedir": "^5.1.0",
43
- "yaml": "^2.8.3",
44
- "zod": "^3.23.0"
45
- },
46
- "devDependencies": {
47
- "@types/node": "^22.10.0",
48
- "obuild": "^0.4.22",
49
- "tsx": "^4.19.0",
50
- "typescript": "^5.9.3",
51
- "vitest": "^2.1.0"
52
- }
53
- }
1
+ {
2
+ "name": "@mhmdreza-rafiei/agentry",
3
+ "version": "0.2.2",
4
+ "description": "One CLI to install agents, skills, rules, and profiles onto AI coding agents — portable AI/agent tooling.",
5
+ "type": "module",
6
+ "bin": {
7
+ "agentry": "dist/cli.mjs"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "dev": "tsx src/cli.ts",
16
+ "build": "obuild",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "typecheck": "tsc --noEmit"
20
+ },
21
+ "engines": {
22
+ "node": ">=22.20.0"
23
+ },
24
+ "keywords": [
25
+ "ai",
26
+ "agents",
27
+ "skills",
28
+ "rules",
29
+ "profiles",
30
+ "cli",
31
+ "cursor",
32
+ "claude-code",
33
+ "codex",
34
+ "agentic",
35
+ "scaffold"
36
+ ],
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/mhmdreza-rafiei/agentry.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/mhmdreza-rafiei/agentry/issues"
44
+ },
45
+ "homepage": "https://github.com/mhmdreza-rafiei/agentry#readme",
46
+ "dependencies": {
47
+ "@clack/prompts": "^0.7.0",
48
+ "@vercel/detect-agent": "^1.2.1",
49
+ "picocolors": "^1.1.1",
50
+ "xdg-basedir": "^5.1.0",
51
+ "yaml": "^2.8.3",
52
+ "zod": "^3.23.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^22.10.0",
56
+ "obuild": "^0.4.22",
57
+ "tsx": "^4.19.0",
58
+ "typescript": "^5.9.3",
59
+ "vitest": "^4.1.10"
60
+ }
61
+ }