@tc9011/skills-manager 0.1.0
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/README.md +231 -0
- package/dist/agents.d.ts +19 -0
- package/dist/agents.js +80 -0
- package/dist/agents.js.map +1 -0
- package/dist/auth.d.ts +10 -0
- package/dist/auth.js +70 -0
- package/dist/auth.js.map +1 -0
- package/dist/commands/link.d.ts +3 -0
- package/dist/commands/link.js +109 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/pull.d.ts +4 -0
- package/dist/commands/pull.js +57 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.js +54 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +48 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/git-ops.d.ts +57 -0
- package/dist/git-ops.js +272 -0
- package/dist/git-ops.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/linker.d.ts +23 -0
- package/dist/linker.js +78 -0
- package/dist/linker.js.map +1 -0
- package/dist/lockfile.d.ts +27 -0
- package/dist/lockfile.js +31 -0
- package/dist/lockfile.js.map +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# skills-manager
|
|
2
|
+
|
|
3
|
+
A CLI companion to [vercel-labs/skills](https://github.com/vercel-labs/skills) that backs up your AI agent skills to GitHub and restores them with automatic agent symlink creation.
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
`vercel-labs/skills` installs and manages skills, but it doesn't handle:
|
|
8
|
+
|
|
9
|
+
- **Backup** — pushing your `~/.agents/` directory (skills + lock file) to a remote GitHub repo
|
|
10
|
+
- **Restore** — cloning skills back on a new machine
|
|
11
|
+
- **Agent linking** — reading `.skill-lock.json` and creating symlinks to every agent you use
|
|
12
|
+
|
|
13
|
+
`skills-manager` fills that gap. It backs up the entire `~/.agents/` directory (including `.skill-lock.json` and `skills/`), reads the lock file that `vercel-labs/skills` owns (never modifies it), and creates relative symlinks from each agent's skills directory back to the canonical `~/.agents/skills/` source.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 1. Backup skills to GitHub
|
|
19
|
+
skills-manager push
|
|
20
|
+
|
|
21
|
+
# 2. Restore skills on a new machine
|
|
22
|
+
skills-manager pull --repo owner/my-skills
|
|
23
|
+
|
|
24
|
+
# 3. Link skills to your agents (auto-runs after pull)
|
|
25
|
+
skills-manager link
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
29
|
+
|
|
30
|
+
### `push`
|
|
31
|
+
|
|
32
|
+
Commits and pushes the contents of `~/.agents/` (skills + `.skill-lock.json`) to its configured GitHub remote.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
skills-manager push
|
|
36
|
+
skills-manager push -m "add new debugging skill"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Option | Description |
|
|
40
|
+
|--------|-------------|
|
|
41
|
+
| `-m, --message <msg>` | Custom commit message (default: auto-generated) |
|
|
42
|
+
|
|
43
|
+
**Prerequisites**: The `~/.agents/` directory must be a git repository with a remote configured.
|
|
44
|
+
|
|
45
|
+
### `pull`
|
|
46
|
+
|
|
47
|
+
Clones or pulls the `~/.agents/` directory from GitHub, then automatically runs `link`.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
skills-manager pull --repo tc9011/my-skills
|
|
51
|
+
skills-manager pull # uses existing remote
|
|
52
|
+
skills-manager pull --skip-link # pull only, don't link
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| Option | Description |
|
|
56
|
+
|--------|-------------|
|
|
57
|
+
| `-r, --repo <owner/name>` | GitHub repo to pull from (default: existing remote) |
|
|
58
|
+
| `--skip-link` | Skip automatic agent linking after pull |
|
|
59
|
+
|
|
60
|
+
### `link`
|
|
61
|
+
|
|
62
|
+
Reads `~/.agents/.skill-lock.json` (owned by `vercel-labs/skills`) and creates relative symlinks from each agent's global skills directory to the canonical `~/.agents/skills/`.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
skills-manager link
|
|
66
|
+
skills-manager link --agents cursor opencode claude-code
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| Option | Description |
|
|
70
|
+
|--------|-------------|
|
|
71
|
+
| `-a, --agents <ids...>` | Agent IDs to link (default: `lastSelectedAgents` from lock file) |
|
|
72
|
+
|
|
73
|
+
**Interactive**: Presents a multiselect prompt with all `lastSelectedAgents` pre-selected. You can deselect agents you don't want to link.
|
|
74
|
+
|
|
75
|
+
**Symlink model**:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
~/.config/opencode/skills/my-skill → ../../../.agents/skills/my-skill (relative)
|
|
79
|
+
~/.claude/skills/my-skill → ../../.agents/skills/my-skill (relative)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
Token resolution order:
|
|
85
|
+
|
|
86
|
+
1. `gh auth token` — GitHub CLI (preferred)
|
|
87
|
+
2. `$GITHUB_TOKEN` environment variable
|
|
88
|
+
3. `$GH_TOKEN` environment variable
|
|
89
|
+
|
|
90
|
+
If none found, `push` and `pull` will fail with a clear error message. `link` does not require authentication.
|
|
91
|
+
|
|
92
|
+
## Supported Agents
|
|
93
|
+
|
|
94
|
+
### Universal Agents (share `.agents/skills`)
|
|
95
|
+
|
|
96
|
+
| Agent | ID | Global Path |
|
|
97
|
+
|-------|----|-------------|
|
|
98
|
+
| Amp | `amp` | `~/.config/agents/skills` |
|
|
99
|
+
| Cline | `cline` | `~/.agents/skills` |
|
|
100
|
+
| Codex | `codex` | `$CODEX_HOME/skills` |
|
|
101
|
+
| Cursor | `cursor` | `~/.cursor/skills` |
|
|
102
|
+
| Gemini CLI | `gemini-cli` | `~/.gemini/skills` |
|
|
103
|
+
| GitHub Copilot | `github-copilot` | `~/.copilot/skills` |
|
|
104
|
+
| Kimi Code CLI | `kimi-cli` | `~/.config/agents/skills` |
|
|
105
|
+
| OpenCode | `opencode` | `$XDG_CONFIG_HOME/opencode/skills` |
|
|
106
|
+
| Replit | `replit` | `~/.config/agents/skills` |
|
|
107
|
+
| Universal | `universal` | `~/.config/agents/skills` |
|
|
108
|
+
|
|
109
|
+
### Non-Universal Agents (agent-specific paths)
|
|
110
|
+
|
|
111
|
+
| Agent | ID | Global Path |
|
|
112
|
+
|-------|----|-------------|
|
|
113
|
+
| AdaL | `adal` | `~/.adal/skills` |
|
|
114
|
+
| Antigravity | `antigravity` | `~/.gemini/antigravity/skills` |
|
|
115
|
+
| Augment | `augment` | `~/.augment/skills` |
|
|
116
|
+
| Claude Code | `claude-code` | `$CLAUDE_CONFIG_DIR/skills` |
|
|
117
|
+
| CodeBuddy | `codebuddy` | `~/.codebuddy/skills` |
|
|
118
|
+
| Command Code | `command-code` | `~/.commandcode/skills` |
|
|
119
|
+
| Continue | `continue` | `~/.continue/skills` |
|
|
120
|
+
| Cortex Code | `cortex` | `~/.snowflake/cortex/skills` |
|
|
121
|
+
| Crush | `crush` | `~/.config/crush/skills` |
|
|
122
|
+
| Droid | `droid` | `~/.factory/skills` |
|
|
123
|
+
| Goose | `goose` | `~/.config/goose/skills` |
|
|
124
|
+
| iFlow CLI | `iflow-cli` | `~/.iflow/skills` |
|
|
125
|
+
| Junie | `junie` | `~/.junie/skills` |
|
|
126
|
+
| Kilo Code | `kilo` | `~/.kilocode/skills` |
|
|
127
|
+
| Kiro CLI | `kiro-cli` | `~/.kiro/skills` |
|
|
128
|
+
| Kode | `kode` | `~/.kode/skills` |
|
|
129
|
+
| MCPJam | `mcpjam` | `~/.mcpjam/skills` |
|
|
130
|
+
| Mistral Vibe | `mistral-vibe` | `~/.vibe/skills` |
|
|
131
|
+
| Mux | `mux` | `~/.mux/skills` |
|
|
132
|
+
| Neovate | `neovate` | `~/.neovate/skills` |
|
|
133
|
+
| OpenClaw | `openclaw` | `~/.openclaw/skills` |
|
|
134
|
+
| OpenHands | `openhands` | `~/.openhands/skills` |
|
|
135
|
+
| Pi | `pi` | `~/.pi/agent/skills` |
|
|
136
|
+
| Pochi | `pochi` | `~/.pochi/skills` |
|
|
137
|
+
| Qoder | `qoder` | `~/.qoder/skills` |
|
|
138
|
+
| Qwen Code | `qwen-code` | `~/.qwen/skills` |
|
|
139
|
+
| Replit | `replit` | `~/.config/agents/skills` |
|
|
140
|
+
| Roo Code | `roo` | `~/.roo/skills` |
|
|
141
|
+
| Trae | `trae` | `~/.trae/skills` |
|
|
142
|
+
| Trae CN | `trae-cn` | `~/.trae-cn/skills` |
|
|
143
|
+
| Windsurf | `windsurf` | `~/.codeium/windsurf/skills` |
|
|
144
|
+
| Zencoder | `zencoder` | `~/.zencoder/skills` |
|
|
145
|
+
|
|
146
|
+
**41 agents total** — matching the full [vercel-labs/skills](https://github.com/vercel-labs/skills) agent registry.
|
|
147
|
+
|
|
148
|
+
## Environment Variables
|
|
149
|
+
|
|
150
|
+
| Variable | Used By | Default |
|
|
151
|
+
|----------|---------|---------|
|
|
152
|
+
| `$GITHUB_TOKEN` | `push`, `pull` | — |
|
|
153
|
+
| `$GH_TOKEN` | `push`, `pull` | — |
|
|
154
|
+
| `$XDG_CONFIG_HOME` | `opencode`, `amp`, `kimi-cli`, `replit`, `universal` | `~/.config` |
|
|
155
|
+
| `$CODEX_HOME` | `codex` | `~/.codex` |
|
|
156
|
+
| `$CLAUDE_CONFIG_DIR` | `claude-code` | `~/.claude` |
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
### Prerequisites
|
|
161
|
+
|
|
162
|
+
- Node.js ≥ 20
|
|
163
|
+
- GitHub CLI (`gh`) for authentication (recommended)
|
|
164
|
+
|
|
165
|
+
### Local Debugging
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Run any command directly with tsx (no build step needed)
|
|
169
|
+
npx tsx src/index.ts push
|
|
170
|
+
npx tsx src/index.ts pull --repo owner/my-skills
|
|
171
|
+
npx tsx src/index.ts link
|
|
172
|
+
npx tsx src/index.ts link --agents cursor opencode
|
|
173
|
+
|
|
174
|
+
# Or use the dev script (same thing)
|
|
175
|
+
npm run dev -- push
|
|
176
|
+
npm run dev -- link -- --agents cursor
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
To simulate a real global install:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm link # register skills-manager globally
|
|
183
|
+
skills-manager push # use it like an end user
|
|
184
|
+
npm unlink -g skills-manager # clean up when done
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Scripts
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm install # install dependencies
|
|
191
|
+
npm run dev # run via tsx (development)
|
|
192
|
+
npm test # run tests (vitest)
|
|
193
|
+
npm run test:watch # watch mode
|
|
194
|
+
npm run build # compile TypeScript to dist/
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Tech Stack
|
|
198
|
+
|
|
199
|
+
- **Runtime**: Node.js + TypeScript (ESM)
|
|
200
|
+
- **CLI framework**: [Commander.js](https://github.com/tj/commander.js)
|
|
201
|
+
- **Git operations**: [simple-git](https://github.com/steveukx/git-js)
|
|
202
|
+
- **Interactive prompts**: [@clack/prompts](https://github.com/bombshell-dev/clack)
|
|
203
|
+
- **Testing**: [Vitest](https://vitest.dev/)
|
|
204
|
+
- **Dev runner**: [tsx](https://github.com/privatenumber/tsx)
|
|
205
|
+
|
|
206
|
+
### Project Structure
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
src/
|
|
210
|
+
├── index.ts # CLI entry point
|
|
211
|
+
├── agents.ts # 41-agent registry with path resolution
|
|
212
|
+
├── auth.ts # GitHub token resolution (gh CLI → env vars)
|
|
213
|
+
├── lockfile.ts # Read-only .skill-lock.json parser
|
|
214
|
+
├── linker.ts # Relative symlink creation
|
|
215
|
+
├── git-ops.ts # Git push/pull via simple-git
|
|
216
|
+
└── commands/
|
|
217
|
+
├── push.ts # push command handler
|
|
218
|
+
├── pull.ts # pull command handler (auto-links)
|
|
219
|
+
└── link.ts # link command handler (interactive)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Adding a New Agent
|
|
223
|
+
|
|
224
|
+
1. Add the agent ID to the `AgentId` union type in `src/agents.ts`
|
|
225
|
+
2. Add the agent entry to `agentRegistry` with `displayName`, `projectPath`, `globalPath`, and `universal` flag
|
|
226
|
+
3. If the agent uses an environment variable for path resolution, add it to `getAgentGlobalPath()`
|
|
227
|
+
4. Add a test case in `src/agents.test.ts`
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|
package/dist/agents.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type AgentId = 'amp' | 'antigravity' | 'augment' | 'claude-code' | 'openclaw' | 'cline' | 'codebuddy' | 'codex' | 'command-code' | 'continue' | 'cortex' | 'crush' | 'cursor' | 'droid' | 'gemini-cli' | 'github-copilot' | 'goose' | 'junie' | 'iflow-cli' | 'kilo' | 'kimi-cli' | 'kiro-cli' | 'kode' | 'mcpjam' | 'mistral-vibe' | 'mux' | 'opencode' | 'openhands' | 'pi' | 'qoder' | 'qwen-code' | 'replit' | 'roo' | 'trae' | 'trae-cn' | 'windsurf' | 'zencoder' | 'neovate' | 'pochi' | 'adal' | 'universal';
|
|
2
|
+
export interface AgentPaths {
|
|
3
|
+
displayName: string;
|
|
4
|
+
projectPath: string;
|
|
5
|
+
globalPath: string;
|
|
6
|
+
universal: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const agentRegistry: Record<AgentId, AgentPaths>;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve an agent's global skills path to an absolute filesystem path.
|
|
11
|
+
* Handles ~, $XDG_CONFIG_HOME, $CODEX_HOME, $CLAUDE_CONFIG_DIR.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getAgentGlobalPath(agentId: AgentId): string;
|
|
14
|
+
/** Canonical skills directory — the source of truth. */
|
|
15
|
+
export declare const CANONICAL_SKILLS_DIR: string;
|
|
16
|
+
/** The git-managed agents directory — root of the backup repo. */
|
|
17
|
+
export declare const AGENTS_DIR: string;
|
|
18
|
+
/** Lock file path — READ ONLY, owned by vercel-labs/skills. */
|
|
19
|
+
export declare const SKILL_LOCK_PATH: string;
|
package/dist/agents.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/agents.ts
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export const agentRegistry = {
|
|
5
|
+
// UNIVERSAL GROUP (.agents/skills)
|
|
6
|
+
amp: { displayName: 'Amp', projectPath: '.agents/skills', globalPath: '~/.config/agents/skills', universal: true },
|
|
7
|
+
cline: { displayName: 'Cline', projectPath: '.agents/skills', globalPath: '~/.agents/skills', universal: true },
|
|
8
|
+
codex: { displayName: 'Codex', projectPath: '.agents/skills', globalPath: '$CODEX_HOME/skills', universal: true },
|
|
9
|
+
cursor: { displayName: 'Cursor', projectPath: '.agents/skills', globalPath: '~/.cursor/skills', universal: true },
|
|
10
|
+
'gemini-cli': { displayName: 'Gemini CLI', projectPath: '.agents/skills', globalPath: '~/.gemini/skills', universal: true },
|
|
11
|
+
'github-copilot': { displayName: 'GitHub Copilot', projectPath: '.agents/skills', globalPath: '~/.copilot/skills', universal: true },
|
|
12
|
+
'kimi-cli': { displayName: 'Kimi Code CLI', projectPath: '.agents/skills', globalPath: '~/.config/agents/skills', universal: true },
|
|
13
|
+
opencode: { displayName: 'OpenCode', projectPath: '.agents/skills', globalPath: '$XDG_CONFIG_HOME/opencode/skills', universal: true },
|
|
14
|
+
replit: { displayName: 'Replit', projectPath: '.agents/skills', globalPath: '~/.config/agents/skills', universal: true },
|
|
15
|
+
universal: { displayName: 'Universal', projectPath: '.agents/skills', globalPath: '~/.config/agents/skills', universal: true },
|
|
16
|
+
// NON-UNIVERSAL (agent-specific paths)
|
|
17
|
+
antigravity: { displayName: 'Antigravity', projectPath: '.agent/skills', globalPath: '~/.gemini/antigravity/skills', universal: false },
|
|
18
|
+
augment: { displayName: 'Augment', projectPath: '.augment/skills', globalPath: '~/.augment/skills', universal: false },
|
|
19
|
+
'claude-code': { displayName: 'Claude Code', projectPath: '.claude/skills', globalPath: '$CLAUDE_CONFIG_DIR/skills', universal: false },
|
|
20
|
+
openclaw: { displayName: 'OpenClaw', projectPath: 'skills', globalPath: '~/.openclaw/skills', universal: false },
|
|
21
|
+
codebuddy: { displayName: 'CodeBuddy', projectPath: '.codebuddy/skills', globalPath: '~/.codebuddy/skills', universal: false },
|
|
22
|
+
'command-code': { displayName: 'Command Code', projectPath: '.commandcode/skills', globalPath: '~/.commandcode/skills', universal: false },
|
|
23
|
+
continue: { displayName: 'Continue', projectPath: '.continue/skills', globalPath: '~/.continue/skills', universal: false },
|
|
24
|
+
cortex: { displayName: 'Cortex Code', projectPath: '.cortex/skills', globalPath: '~/.snowflake/cortex/skills', universal: false },
|
|
25
|
+
crush: { displayName: 'Crush', projectPath: '.crush/skills', globalPath: '~/.config/crush/skills', universal: false },
|
|
26
|
+
droid: { displayName: 'Droid', projectPath: '.factory/skills', globalPath: '~/.factory/skills', universal: false },
|
|
27
|
+
goose: { displayName: 'Goose', projectPath: '.goose/skills', globalPath: '~/.config/goose/skills', universal: false },
|
|
28
|
+
junie: { displayName: 'Junie', projectPath: '.junie/skills', globalPath: '~/.junie/skills', universal: false },
|
|
29
|
+
'iflow-cli': { displayName: 'iFlow CLI', projectPath: '.iflow/skills', globalPath: '~/.iflow/skills', universal: false },
|
|
30
|
+
kilo: { displayName: 'Kilo Code', projectPath: '.kilocode/skills', globalPath: '~/.kilocode/skills', universal: false },
|
|
31
|
+
'kiro-cli': { displayName: 'Kiro CLI', projectPath: '.kiro/skills', globalPath: '~/.kiro/skills', universal: false },
|
|
32
|
+
kode: { displayName: 'Kode', projectPath: '.kode/skills', globalPath: '~/.kode/skills', universal: false },
|
|
33
|
+
mcpjam: { displayName: 'MCPJam', projectPath: '.mcpjam/skills', globalPath: '~/.mcpjam/skills', universal: false },
|
|
34
|
+
'mistral-vibe': { displayName: 'Mistral Vibe', projectPath: '.vibe/skills', globalPath: '~/.vibe/skills', universal: false },
|
|
35
|
+
mux: { displayName: 'Mux', projectPath: '.mux/skills', globalPath: '~/.mux/skills', universal: false },
|
|
36
|
+
openhands: { displayName: 'OpenHands', projectPath: '.openhands/skills', globalPath: '~/.openhands/skills', universal: false },
|
|
37
|
+
pi: { displayName: 'Pi', projectPath: '.pi/skills', globalPath: '~/.pi/agent/skills', universal: false },
|
|
38
|
+
qoder: { displayName: 'Qoder', projectPath: '.qoder/skills', globalPath: '~/.qoder/skills', universal: false },
|
|
39
|
+
'qwen-code': { displayName: 'Qwen Code', projectPath: '.qwen/skills', globalPath: '~/.qwen/skills', universal: false },
|
|
40
|
+
roo: { displayName: 'Roo Code', projectPath: '.roo/skills', globalPath: '~/.roo/skills', universal: false },
|
|
41
|
+
trae: { displayName: 'Trae', projectPath: '.trae/skills', globalPath: '~/.trae/skills', universal: false },
|
|
42
|
+
'trae-cn': { displayName: 'Trae CN', projectPath: '.trae/skills', globalPath: '~/.trae-cn/skills', universal: false },
|
|
43
|
+
windsurf: { displayName: 'Windsurf', projectPath: '.windsurf/skills', globalPath: '~/.codeium/windsurf/skills', universal: false },
|
|
44
|
+
zencoder: { displayName: 'Zencoder', projectPath: '.zencoder/skills', globalPath: '~/.zencoder/skills', universal: false },
|
|
45
|
+
neovate: { displayName: 'Neovate', projectPath: '.neovate/skills', globalPath: '~/.neovate/skills', universal: false },
|
|
46
|
+
pochi: { displayName: 'Pochi', projectPath: '.pochi/skills', globalPath: '~/.pochi/skills', universal: false },
|
|
47
|
+
adal: { displayName: 'AdaL', projectPath: '.adal/skills', globalPath: '~/.adal/skills', universal: false },
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Resolve an agent's global skills path to an absolute filesystem path.
|
|
51
|
+
* Handles ~, $XDG_CONFIG_HOME, $CODEX_HOME, $CLAUDE_CONFIG_DIR.
|
|
52
|
+
*/
|
|
53
|
+
export function getAgentGlobalPath(agentId) {
|
|
54
|
+
const home = homedir();
|
|
55
|
+
let p = agentRegistry[agentId].globalPath;
|
|
56
|
+
// Resolve env-var-based paths first
|
|
57
|
+
if (p.startsWith('$XDG_CONFIG_HOME')) {
|
|
58
|
+
const xdg = process.env.XDG_CONFIG_HOME ?? join(home, '.config');
|
|
59
|
+
p = p.replace('$XDG_CONFIG_HOME', xdg);
|
|
60
|
+
}
|
|
61
|
+
else if (p.startsWith('$CODEX_HOME')) {
|
|
62
|
+
const codex = process.env.CODEX_HOME ?? join(home, '.codex');
|
|
63
|
+
p = p.replace('$CODEX_HOME', codex);
|
|
64
|
+
}
|
|
65
|
+
else if (p.startsWith('$CLAUDE_CONFIG_DIR')) {
|
|
66
|
+
const claude = process.env.CLAUDE_CONFIG_DIR ?? join(home, '.claude');
|
|
67
|
+
p = p.replace('$CLAUDE_CONFIG_DIR', claude);
|
|
68
|
+
}
|
|
69
|
+
else if (p.startsWith('~')) {
|
|
70
|
+
p = p.replace('~', home);
|
|
71
|
+
}
|
|
72
|
+
return p;
|
|
73
|
+
}
|
|
74
|
+
/** Canonical skills directory — the source of truth. */
|
|
75
|
+
export const CANONICAL_SKILLS_DIR = join(homedir(), '.agents', 'skills');
|
|
76
|
+
/** The git-managed agents directory — root of the backup repo. */
|
|
77
|
+
export const AGENTS_DIR = join(homedir(), '.agents');
|
|
78
|
+
/** Lock file path — READ ONLY, owned by vercel-labs/skills. */
|
|
79
|
+
export const SKILL_LOCK_PATH = join(homedir(), '.agents', '.skill-lock.json');
|
|
80
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get GitHub token. Priority: gh auth token > GITHUB_TOKEN > GH_TOKEN.
|
|
3
|
+
* Returns null if none available.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getGitHubToken(): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure a GitHub token is available. If not, interactively guide the user
|
|
8
|
+
* through authentication. Returns token or throws CliError.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureGitHubToken(): Promise<string>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// src/auth.ts
|
|
2
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
3
|
+
import * as p from '@clack/prompts';
|
|
4
|
+
import { CliError } from './errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Get GitHub token. Priority: gh auth token > GITHUB_TOKEN > GH_TOKEN.
|
|
7
|
+
* Returns null if none available.
|
|
8
|
+
*/
|
|
9
|
+
export function getGitHubToken() {
|
|
10
|
+
// Try gh CLI first
|
|
11
|
+
try {
|
|
12
|
+
const token = execSync('gh auth token', {
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
15
|
+
}).trim();
|
|
16
|
+
if (token)
|
|
17
|
+
return token;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// gh not installed or not authenticated
|
|
21
|
+
}
|
|
22
|
+
// Fallback to env vars
|
|
23
|
+
if (process.env.GITHUB_TOKEN)
|
|
24
|
+
return process.env.GITHUB_TOKEN;
|
|
25
|
+
if (process.env.GH_TOKEN)
|
|
26
|
+
return process.env.GH_TOKEN;
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensure a GitHub token is available. If not, interactively guide the user
|
|
31
|
+
* through authentication. Returns token or throws CliError.
|
|
32
|
+
*/
|
|
33
|
+
export async function ensureGitHubToken() {
|
|
34
|
+
const existing = getGitHubToken();
|
|
35
|
+
if (existing)
|
|
36
|
+
return existing;
|
|
37
|
+
const method = await p.select({
|
|
38
|
+
message: 'No GitHub authentication found. How would you like to authenticate?',
|
|
39
|
+
options: [
|
|
40
|
+
{ value: 'gh', label: 'Run gh auth login', hint: 'recommended — opens GitHub CLI login flow' },
|
|
41
|
+
{ value: 'env', label: 'Set GITHUB_TOKEN manually', hint: 'export GITHUB_TOKEN=ghp_...' },
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
if (p.isCancel(method)) {
|
|
45
|
+
p.cancel('Authentication cancelled.');
|
|
46
|
+
throw new CliError('Authentication cancelled.');
|
|
47
|
+
}
|
|
48
|
+
if (method === 'gh') {
|
|
49
|
+
p.log.step('Starting gh auth login...');
|
|
50
|
+
const result = spawnSync('gh', ['auth', 'login'], {
|
|
51
|
+
stdio: 'inherit',
|
|
52
|
+
});
|
|
53
|
+
if (result.status !== 0) {
|
|
54
|
+
p.cancel('gh auth login failed. Please try again.');
|
|
55
|
+
throw new CliError('gh auth login failed.');
|
|
56
|
+
}
|
|
57
|
+
const token = getGitHubToken();
|
|
58
|
+
if (!token) {
|
|
59
|
+
p.cancel('Still no token after gh auth login. Please try again.');
|
|
60
|
+
throw new CliError('No token after gh auth login.');
|
|
61
|
+
}
|
|
62
|
+
return token;
|
|
63
|
+
}
|
|
64
|
+
// method === 'env'
|
|
65
|
+
p.note('Run one of the following, then re-run your command:\n\n' +
|
|
66
|
+
' export GITHUB_TOKEN=ghp_your_token_here\n' +
|
|
67
|
+
' export GH_TOKEN=ghp_your_token_here', 'Set environment variable');
|
|
68
|
+
throw new CliError('Please set GITHUB_TOKEN and try again.');
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,mBAAmB;IACnB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,EAAE;YACtC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC9D,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAEtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC;QAC5B,OAAO,EAAE,qEAAqE;QAC9E,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,2CAA2C,EAAE;YAC9F,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,IAAI,EAAE,6BAA6B,EAAE;SAC1F;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,CAAC,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACtC,MAAM,IAAI,QAAQ,CAAC,2BAA2B,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;YAChD,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,CAAC,CAAC,MAAM,CAAC,yCAAyC,CAAC,CAAC;YACpD,MAAM,IAAI,QAAQ,CAAC,uBAAuB,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,CAAC,CAAC,MAAM,CAAC,uDAAuD,CAAC,CAAC;YAClE,MAAM,IAAI,QAAQ,CAAC,+BAA+B,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mBAAmB;IACnB,CAAC,CAAC,IAAI,CACJ,yDAAyD;QACzD,6CAA6C;QAC7C,uCAAuC,EACvC,0BAA0B,CAC3B,CAAC;IACF,MAAM,IAAI,QAAQ,CAAC,wCAAwC,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { CANONICAL_SKILLS_DIR, SKILL_LOCK_PATH, agentRegistry, getAgentGlobalPath } from '../agents.js';
|
|
3
|
+
import { CliError } from '../errors.js';
|
|
4
|
+
import { readConfig, writeConfig } from '../config.js';
|
|
5
|
+
import { getLastSelectedAgents } from '../lockfile.js';
|
|
6
|
+
import { createSkillSymlinks, listCanonicalSkills } from '../linker.js';
|
|
7
|
+
import * as p from '@clack/prompts';
|
|
8
|
+
export async function linkCommand(options) {
|
|
9
|
+
p.intro('skills-manager link');
|
|
10
|
+
// 1. Read lock file for lastSelectedAgents
|
|
11
|
+
let agents;
|
|
12
|
+
if (options.agents?.length) {
|
|
13
|
+
const validIds = new Set(Object.keys(agentRegistry));
|
|
14
|
+
const invalid = options.agents.filter(id => !validIds.has(id));
|
|
15
|
+
if (invalid.length > 0) {
|
|
16
|
+
p.cancel(`Unknown agent ID(s): ${invalid.join(', ')}. Run with no --agents to see available IDs.`);
|
|
17
|
+
throw new CliError(`Unknown agent ID(s): ${invalid.join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
agents = options.agents;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
agents = await getLastSelectedAgents(SKILL_LOCK_PATH);
|
|
23
|
+
if (agents.length === 0) {
|
|
24
|
+
p.cancel('No lastSelectedAgents found in .skill-lock.json. Use --agents to specify.');
|
|
25
|
+
throw new CliError('No lastSelectedAgents found in .skill-lock.json.');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 2. Interactive confirmation
|
|
29
|
+
const agentChoices = agents.map(id => {
|
|
30
|
+
const globalPath = getAgentGlobalPath(id);
|
|
31
|
+
const dirExists = existsSync(globalPath);
|
|
32
|
+
return {
|
|
33
|
+
value: id,
|
|
34
|
+
label: `${agentRegistry[id].displayName} (${id})`,
|
|
35
|
+
hint: dirExists ? globalPath : `${globalPath} — directory will be created`,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
const selected = await p.multiselect({
|
|
39
|
+
message: 'Select agents to link skills to:',
|
|
40
|
+
options: agentChoices,
|
|
41
|
+
initialValues: computeInitialValues(agents, agentChoices),
|
|
42
|
+
required: false,
|
|
43
|
+
});
|
|
44
|
+
if (p.isCancel(selected) || !selected.length) {
|
|
45
|
+
p.cancel('No agents selected.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// 3. Get skill list
|
|
49
|
+
const skills = await listCanonicalSkills(CANONICAL_SKILLS_DIR);
|
|
50
|
+
if (skills.length === 0) {
|
|
51
|
+
p.cancel(`No skills found in ${CANONICAL_SKILLS_DIR}.`);
|
|
52
|
+
throw new CliError(`No skills found in ${CANONICAL_SKILLS_DIR}.`);
|
|
53
|
+
}
|
|
54
|
+
// 4. Create symlinks for each agent
|
|
55
|
+
const linkedAgents = [];
|
|
56
|
+
const skippedAgents = [];
|
|
57
|
+
const validSelected = new Set(Object.keys(agentRegistry));
|
|
58
|
+
const selectedAgents = selected.filter((id) => validSelected.has(id));
|
|
59
|
+
for (const agentId of selectedAgents) {
|
|
60
|
+
const globalPath = getAgentGlobalPath(agentId);
|
|
61
|
+
const spinner = p.spinner();
|
|
62
|
+
spinner.start(`Linking ${agentRegistry[agentId].displayName}...`);
|
|
63
|
+
try {
|
|
64
|
+
const results = await createSkillSymlinks(CANONICAL_SKILLS_DIR, globalPath, skills);
|
|
65
|
+
const created = results.filter(r => r.status === 'created').length;
|
|
66
|
+
const recreated = results.filter(r => r.status === 'recreated').length;
|
|
67
|
+
const existed = results.filter(r => r.status === 'exists').length;
|
|
68
|
+
const skipped = results.filter(r => r.status === 'skipped').length;
|
|
69
|
+
const parts = [`${created} linked`];
|
|
70
|
+
if (recreated > 0)
|
|
71
|
+
parts.push(`${recreated} recreated`);
|
|
72
|
+
parts.push(`${existed} existing`, `${skipped} skipped`);
|
|
73
|
+
spinner.stop(`${agentRegistry[agentId].displayName}: ${parts.join(', ')}`);
|
|
74
|
+
linkedAgents.push(agentId);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
spinner.stop(`${agentRegistry[agentId].displayName}: failed`);
|
|
78
|
+
skippedAgents.push({ id: agentId, reason: String(err) });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// 5. Save selection for next time
|
|
82
|
+
if (linkedAgents.length > 0) {
|
|
83
|
+
writeConfig({ lastLinkedAgents: selectedAgents });
|
|
84
|
+
}
|
|
85
|
+
// 6. Summary
|
|
86
|
+
p.note([
|
|
87
|
+
linkedAgents.length > 0 ? `✓ Linked: ${linkedAgents.join(', ')}` : '',
|
|
88
|
+
skippedAgents.length > 0 ? `✗ Skipped: ${skippedAgents.map(s => `${s.id} (${s.reason})`).join(', ')}` : '',
|
|
89
|
+
].filter(Boolean).join('\n'), 'Summary');
|
|
90
|
+
p.outro('Done!');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Determine which agents should be pre-selected in the multiselect.
|
|
94
|
+
* Priority: saved lastLinkedAgents (if any match current list) > existsSync fallback.
|
|
95
|
+
*/
|
|
96
|
+
function computeInitialValues(agents, choices) {
|
|
97
|
+
const config = readConfig();
|
|
98
|
+
const saved = config.lastLinkedAgents;
|
|
99
|
+
if (saved && saved.length > 0) {
|
|
100
|
+
const agentSet = new Set(agents);
|
|
101
|
+
const matching = saved.filter(id => agentSet.has(id));
|
|
102
|
+
if (matching.length > 0) {
|
|
103
|
+
return matching;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Fallback: pre-select agents whose directories exist locally
|
|
107
|
+
return choices.filter(c => existsSync(getAgentGlobalPath(c.value))).map(c => c.value);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AGENTS_DIR } from '../agents.js';
|
|
2
|
+
import { ensureGitHubToken } from '../auth.js';
|
|
3
|
+
import { CliError } from '../errors.js';
|
|
4
|
+
import { pullSkills, buildRemoteUrl, getRepoRemoteUrl, ensureGitRepo, ensureRemote, } from '../git-ops.js';
|
|
5
|
+
import { linkCommand } from './link.js';
|
|
6
|
+
import * as p from '@clack/prompts';
|
|
7
|
+
export async function pullCommand(options) {
|
|
8
|
+
p.intro('skills-manager pull');
|
|
9
|
+
const token = await ensureGitHubToken();
|
|
10
|
+
// Determine remote URL
|
|
11
|
+
let remoteUrl;
|
|
12
|
+
if (options.repo) {
|
|
13
|
+
remoteUrl = buildRemoteUrl(options.repo);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
const existing = await getRepoRemoteUrl(AGENTS_DIR);
|
|
17
|
+
if (existing) {
|
|
18
|
+
remoteUrl = existing;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// No --repo flag and no existing remote — prompt interactively
|
|
22
|
+
await ensureGitRepo(AGENTS_DIR);
|
|
23
|
+
const repo = await p.text({
|
|
24
|
+
message: 'Enter GitHub repo to pull from (owner/name):',
|
|
25
|
+
placeholder: 'e.g. tc9011/my-skills',
|
|
26
|
+
});
|
|
27
|
+
if (p.isCancel(repo)) {
|
|
28
|
+
p.cancel('Pull cancelled.');
|
|
29
|
+
throw new CliError('Pull cancelled by user.');
|
|
30
|
+
}
|
|
31
|
+
const result = await ensureRemote(AGENTS_DIR, repo);
|
|
32
|
+
remoteUrl = result.remoteUrl;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Pull
|
|
36
|
+
const spinner = p.spinner();
|
|
37
|
+
spinner.start('Pulling skills from GitHub...');
|
|
38
|
+
try {
|
|
39
|
+
const result = await pullSkills(AGENTS_DIR, remoteUrl, token);
|
|
40
|
+
spinner.stop(result.cloned
|
|
41
|
+
? 'Skills cloned successfully!'
|
|
42
|
+
: 'Skills updated from remote.');
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
spinner.stop('Pull failed.');
|
|
46
|
+
p.cancel(String(err));
|
|
47
|
+
throw new CliError(String(err));
|
|
48
|
+
}
|
|
49
|
+
// Auto-run link unless skipped
|
|
50
|
+
if (!options.skipLink) {
|
|
51
|
+
await linkCommand({});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
p.outro('Pull complete. Run `skills-manager link` to create agent symlinks.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EACL,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA8C;IAC9E,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAE/B,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAExC,uBAAuB;IACvB,IAAI,SAAiB,CAAC;IACtB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS,GAAG,QAAQ,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,+DAA+D;YAC/D,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;YAEhC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC;gBACxB,OAAO,EAAE,8CAA8C;gBACvD,WAAW,EAAE,uBAAuB;aACrC,CAAC,CAAC;YAEH,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrB,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;gBAC5B,MAAM,IAAI,QAAQ,CAAC,yBAAyB,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACpD,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO;IACP,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CACV,MAAM,CAAC,MAAM;YACX,CAAC,CAAC,6BAA6B;YAC/B,CAAC,CAAC,6BAA6B,CAClC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtB,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,+BAA+B;IAC/B,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,CAAC,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;IAChF,CAAC;AACH,CAAC"}
|