@karedo-hq/agents 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 +102 -0
- package/commands/commit.md +26 -0
- package/commands/create-pr.md +12 -0
- package/commands/deslop.md +12 -0
- package/commands/release.md +242 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/package.json +44 -0
- package/rules/api/controllers.mdc +31 -0
- package/rules/api/dtos.mdc +38 -0
- package/rules/api/mail-from-template.mdc +65 -0
- package/rules/api/mongodb-schemas.mdc +63 -0
- package/rules/api/nestjs.mdc +36 -0
- package/rules/api/services.mdc +32 -0
- package/rules/api/tiptap-templates.mdc +88 -0
- package/rules/typescript.mdc +60 -0
- package/rules/web/api-layer.mdc +82 -0
- package/rules/web/nextjs.mdc +87 -0
- package/rules/web/pages.mdc +89 -0
- package/rules/web/responsive-dialog-drawer.mdc +36 -0
- package/rules/web/tables.mdc +87 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @karedo-hq/agents
|
|
2
|
+
|
|
3
|
+
Centralized agent skills, rules, and commands for our engineering team. Install shared configurations for AI-powered IDEs like Cursor, Claude Code, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Using pnpm
|
|
9
|
+
pnpm dlx @karedo-hq/agents install --target cursor
|
|
10
|
+
|
|
11
|
+
# Or install globally
|
|
12
|
+
pnpm add -g @karedo-hq/agents
|
|
13
|
+
agents install --target cursor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Install Configurations
|
|
19
|
+
|
|
20
|
+
Install agent configurations to your current project:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
agents install --target <ide>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Options:**
|
|
27
|
+
|
|
28
|
+
- `-t, --target <ide>` - Target IDE (required). Currently supported: `cursor`
|
|
29
|
+
- `-f, --force` - Overwrite existing files without prompting
|
|
30
|
+
|
|
31
|
+
**Examples:**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Install Cursor configurations
|
|
35
|
+
agents install --target cursor
|
|
36
|
+
|
|
37
|
+
# Force overwrite existing files
|
|
38
|
+
agents install --target cursor --force
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Supported Targets
|
|
42
|
+
|
|
43
|
+
| Target | Description | Output Directory |
|
|
44
|
+
| -------- | ---------------------------------------- | ---------------- |
|
|
45
|
+
| `cursor` | Cursor IDE rules and commands | `.cursor/` |
|
|
46
|
+
|
|
47
|
+
## What Gets Installed
|
|
48
|
+
|
|
49
|
+
### Rules
|
|
50
|
+
|
|
51
|
+
Rules provide guidelines and best practices for your codebase:
|
|
52
|
+
|
|
53
|
+
- **TypeScript** - General TypeScript coding standards
|
|
54
|
+
- **API (Backend)**
|
|
55
|
+
- Controllers, DTOs, Services
|
|
56
|
+
- MongoDB schemas, NestJS patterns
|
|
57
|
+
- Email templates, Tiptap templates
|
|
58
|
+
- **Web (Frontend)**
|
|
59
|
+
- Next.js guidelines, API layer patterns
|
|
60
|
+
- Page creation, table implementation
|
|
61
|
+
- Responsive dialog/drawer patterns
|
|
62
|
+
|
|
63
|
+
### Commands
|
|
64
|
+
|
|
65
|
+
Commands are reusable workflows for common tasks:
|
|
66
|
+
|
|
67
|
+
- **commit** - Commit current work with conventional commits
|
|
68
|
+
- **create-pr** - Create a pull request with proper formatting
|
|
69
|
+
- **deslop** - Remove AI-generated code slop
|
|
70
|
+
- **release** - Automate the release process
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Install dependencies
|
|
76
|
+
pnpm install
|
|
77
|
+
|
|
78
|
+
# Build
|
|
79
|
+
pnpm build
|
|
80
|
+
|
|
81
|
+
# Watch mode
|
|
82
|
+
pnpm dev
|
|
83
|
+
|
|
84
|
+
# Type check
|
|
85
|
+
pnpm typecheck
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Adding New Rules or Commands
|
|
89
|
+
|
|
90
|
+
1. Add your rule file to `rules/` (use `.mdc` extension for Cursor compatibility)
|
|
91
|
+
2. Add your command file to `commands/` (use `.md` extension)
|
|
92
|
+
3. Rebuild and publish
|
|
93
|
+
|
|
94
|
+
## Adding New IDE Targets
|
|
95
|
+
|
|
96
|
+
1. Create a new handler in `src/targets/<ide-name>.ts`
|
|
97
|
+
2. Register it in `src/targets/index.ts`
|
|
98
|
+
3. Implement the `install` function that maps `rules/` and `commands/` to the IDE's expected location
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Commit current work
|
|
2
|
+
|
|
3
|
+
Commit current work.
|
|
4
|
+
|
|
5
|
+
## Important
|
|
6
|
+
|
|
7
|
+
- Prepend GIT_EDITOR=true to all git commands you run, especially the ones looking at diffs, so you can avoid getting blocked as you execute commands
|
|
8
|
+
- If you can't get any information from git diff, just using your working memory to determine what has changed
|
|
9
|
+
|
|
10
|
+
## Instructions
|
|
11
|
+
|
|
12
|
+
Review each file individually to make sure they're related to the work you just did, then write a commit message following [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/):
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
<type>[optional scope]: <description>
|
|
16
|
+
|
|
17
|
+
[optional body with 2~3 bullet points]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`
|
|
21
|
+
|
|
22
|
+
## Notes
|
|
23
|
+
|
|
24
|
+
- You should only commit work when instructed. Do not keep committing subsquent work unless explicitly told so
|
|
25
|
+
|
|
26
|
+
Optional: ask me if I would like to push the commit. (Only if I'm not on main)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Open a PR
|
|
2
|
+
|
|
3
|
+
- Check that I'm in a branch other than `main` or `dev`. If not, bail and explain.
|
|
4
|
+
- Find the parent branch (the branch this one was created from) using merge-base with common branches (dev, main).
|
|
5
|
+
- Check the diff between my branch and the parent branch.
|
|
6
|
+
- If there's unstaged or staged work that hasn't been commited, commit all the relevant code first.
|
|
7
|
+
- Create the PR targeting the parent branch (use `gh pr create --base <parent-branch>`).
|
|
8
|
+
- Write up a quick PR in the following format:
|
|
9
|
+
- Title: Plain English, start with verb, no prefixes (e.g. "Add emails module" not "feat(emails): add emails module")
|
|
10
|
+
- Description: <TLDR> (no more than 2 sentences) plus <Description> (1~3 bullet points explaining what's changing)
|
|
11
|
+
- Always paste the link to the PR in your response so I can click it easily
|
|
12
|
+
- Prepend GIT_EDITOR=true to all git commands you run, so you can avoid getting blocked as you execute commands
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Remove AI code slop
|
|
2
|
+
|
|
3
|
+
Check the diff against the parent branch (use `dev` if not specified) and remove all AI generated slop introduced in this branch.
|
|
4
|
+
|
|
5
|
+
This includes:
|
|
6
|
+
|
|
7
|
+
- Extra comments that a human wouldn't add or is inconsistent with the rest of the file
|
|
8
|
+
- Extra defensive checks or try/catch blocks that are abnormal for that area of the codebase (especially if called by trusted / validated codepaths)
|
|
9
|
+
- Casts to any to get around type issues
|
|
10
|
+
- Any other style that is inconsistent with the file
|
|
11
|
+
|
|
12
|
+
Report at the end with only a 1-3 sentence summary of what you changed
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
This command automates the release process for an application in the monorepo.
|
|
4
|
+
|
|
5
|
+
## Target Repository
|
|
6
|
+
|
|
7
|
+
**IMPORTANT**: Before starting, determine which repository to run this command on.
|
|
8
|
+
|
|
9
|
+
- If the user specified a repo (e.g., `api`, `web`), use that.
|
|
10
|
+
- If not specified, **ASK the user**: "Which repository should I run this release process on? (e.g., `api`, `web`)"
|
|
11
|
+
|
|
12
|
+
Do NOT proceed until you have confirmed the target `<repo>`.
|
|
13
|
+
|
|
14
|
+
Throughout this document, replace `<repo>` with the actual repository name (e.g., `api`, `web`).
|
|
15
|
+
|
|
16
|
+
## Instructions
|
|
17
|
+
|
|
18
|
+
Follow these steps in order:
|
|
19
|
+
|
|
20
|
+
### 0. Verify Git Branch and Pull Latest Changes
|
|
21
|
+
|
|
22
|
+
**CRITICAL**: Before starting, ensure you're on the `dev` branch with the latest changes.
|
|
23
|
+
|
|
24
|
+
Run from the `<repo>` directory:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git checkout dev && git pull origin dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If the branch checkout or pull fails, stop and inform the user to resolve git issues manually.
|
|
31
|
+
|
|
32
|
+
### 1. Determine Release PR Baseline and PR Set
|
|
33
|
+
|
|
34
|
+
Use **GitHub CLI (`gh`) whenever it is installed**. Fall back to GitHub MCP only if `gh` is unavailable.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Preferred (gh) - find the last merged release PR (base=main, head=dev)
|
|
38
|
+
gh pr list --state merged --base main --head dev --limit 100 --json number,title,mergedAt,url
|
|
39
|
+
|
|
40
|
+
# Preferred (gh) - list merged PRs into dev (high limit, use mergedAt)
|
|
41
|
+
gh pr list --state merged --base dev --limit 300 --json number,title,author,mergedAt,headRefName,url,body
|
|
42
|
+
|
|
43
|
+
# Fallback (MCP) - never sort by created_at; paginate and filter by merged_at
|
|
44
|
+
mcp_github_list_pull_requests({
|
|
45
|
+
owner: 'karedo-hq',
|
|
46
|
+
repo: '<repo>',
|
|
47
|
+
state: 'closed',
|
|
48
|
+
base: 'main',
|
|
49
|
+
head: 'dev',
|
|
50
|
+
per_page: 100,
|
|
51
|
+
page: 1,
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Fallback pagination rules (MCP):
|
|
56
|
+
|
|
57
|
+
- Always filter by `merged_at` and ignore `created_at`
|
|
58
|
+
- Fetch additional pages (`page: 2`, `page: 3`, ...) until you have all relevant PRs
|
|
59
|
+
- When listing PRs merged into `dev`, stop only after you have passed the `merged_at` threshold from the last release PR
|
|
60
|
+
|
|
61
|
+
**Critical**: Identify the last release PR as:
|
|
62
|
+
|
|
63
|
+
- `base = main`
|
|
64
|
+
- `head = dev`
|
|
65
|
+
- `state = merged`
|
|
66
|
+
|
|
67
|
+
Pick the most recent by `mergedAt` (do NOT search by title).
|
|
68
|
+
|
|
69
|
+
Build the PR set for the release using **mergedAt** only:
|
|
70
|
+
|
|
71
|
+
- Include PRs merged into `dev` **after** the last release PR's `mergedAt`
|
|
72
|
+
- Sort the final list by `mergedAt` ascending
|
|
73
|
+
- Do NOT use PR numbers or `createdAt` for ordering or filtering
|
|
74
|
+
- Do NOT cap results at 50; use a high limit (e.g., 300) or paginate until all relevant PRs are captured
|
|
75
|
+
|
|
76
|
+
If no PRs match, **STOP** and inform the user there is nothing to release.
|
|
77
|
+
|
|
78
|
+
For every included PR, read its **title and description thoroughly** and note the key user-facing impact; you will reuse that wording when updating the changelog.
|
|
79
|
+
|
|
80
|
+
### 2. Update CHANGELOG.md
|
|
81
|
+
|
|
82
|
+
Add a new entry at the top of the changelog following this format:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
## [X.X.X] - MMM DD, YYYY.
|
|
86
|
+
|
|
87
|
+
One line summary of the release.
|
|
88
|
+
|
|
89
|
+
### Added
|
|
90
|
+
|
|
91
|
+
- Bullet points of new features
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- Bullet points of changes
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
|
|
99
|
+
- Bullet points of bug fixes
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Rules:
|
|
103
|
+
|
|
104
|
+
- Keep it concise and high-level while accurately reflecting the PRs in the **exact PR list** from step 1.
|
|
105
|
+
- **Use PR titles and descriptions as the primary source of truth.** If a point is not obvious from the code diff, lean on the wording in the PR body.
|
|
106
|
+
- Make sure every PR from the list in step 1 influences the entry. If a PR does not warrant a line item, ensure its work is implicitly covered by another bullet.
|
|
107
|
+
- Only include important changes; combine related PRs into a single bullet when appropriate.
|
|
108
|
+
- Do not include PR numbers in the changelog entry.
|
|
109
|
+
- Follow the existing pattern in the file.
|
|
110
|
+
|
|
111
|
+
### 3. Update package.json
|
|
112
|
+
|
|
113
|
+
Bump the version number in `<repo>/package.json`:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
"version": "X.X.X"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 4. Wait for User Confirmation
|
|
120
|
+
|
|
121
|
+
**STOP HERE AND WAIT FOR USER CONFIRMATION**
|
|
122
|
+
|
|
123
|
+
After updating CHANGELOG.md and package.json, present the changes to the user and ask:
|
|
124
|
+
|
|
125
|
+
"I've updated the following files for version X.X.X:
|
|
126
|
+
|
|
127
|
+
- CHANGELOG.md (added new entry with X changes)
|
|
128
|
+
- package.json (bumped version from Y.Y.Y to X.X.X)
|
|
129
|
+
|
|
130
|
+
Please review the changes. Should I proceed with committing and pushing these changes to dev?"
|
|
131
|
+
|
|
132
|
+
Do NOT proceed until the user explicitly confirms (e.g., "yes", "proceed", "looks good", etc.).
|
|
133
|
+
|
|
134
|
+
If the user requests changes, make the adjustments and ask for confirmation again.
|
|
135
|
+
|
|
136
|
+
### 5. Commit and Push Changes to Dev
|
|
137
|
+
|
|
138
|
+
**CRITICAL STEP**: Only proceed after user confirmation. You MUST commit and push the version bump changes to dev BEFORE creating the PR and tag.
|
|
139
|
+
|
|
140
|
+
Use conventional commit format (run from the `<repo>` directory):
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git add CHANGELOG.md package.json && git commit -m "chore(version): Bump to vX.X.X" && git push origin dev
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Request `git_write` permissions for this step.
|
|
147
|
+
|
|
148
|
+
**Note**: If SSH authentication fails, the user will need to handle it manually. Wait for confirmation before proceeding.
|
|
149
|
+
|
|
150
|
+
### 6. Prepare Release PR Details
|
|
151
|
+
|
|
152
|
+
Prepare the PR title and body, then present to user for confirmation:
|
|
153
|
+
|
|
154
|
+
**Title**: `Release vX.X.X` (must include the version)
|
|
155
|
+
|
|
156
|
+
**Body**: List of all included PRs (from step 1), in `mergedAt` order. Each entry must include only the PR number:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
- #1234
|
|
160
|
+
- #1235
|
|
161
|
+
...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**STOP AND WAIT FOR USER CONFIRMATION**
|
|
165
|
+
|
|
166
|
+
Ask the user: "Should I create the release PR with the above title and description?"
|
|
167
|
+
|
|
168
|
+
Do NOT proceed until the user explicitly confirms.
|
|
169
|
+
|
|
170
|
+
### 7. Create Release Pull Request
|
|
171
|
+
|
|
172
|
+
Prefer GitHub CLI; only use MCP if `gh` is unavailable.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Preferred (gh)
|
|
176
|
+
gh pr create \
|
|
177
|
+
--title "Release vX.X.X" \
|
|
178
|
+
--base main \
|
|
179
|
+
--head dev \
|
|
180
|
+
--body "- #1234\n- #1235\n..."
|
|
181
|
+
|
|
182
|
+
# Fallback (MCP)
|
|
183
|
+
mcp_github_create_pull_request({
|
|
184
|
+
owner: 'karedo-hq',
|
|
185
|
+
repo: '<repo>',
|
|
186
|
+
title: 'Release vX.X.X',
|
|
187
|
+
head: 'dev',
|
|
188
|
+
base: 'main',
|
|
189
|
+
body: '- #1234\n- #1235\n...',
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 8. Create and Push Git Tag
|
|
194
|
+
|
|
195
|
+
**STOP AND WAIT FOR MERGE CONFIRMATION**
|
|
196
|
+
|
|
197
|
+
Ask the user to confirm the release PR has been merged into `main`.
|
|
198
|
+
|
|
199
|
+
**ONLY after the release PR is merged into `main`**, create and push the tag from `main` (run from the `<repo>` directory):
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
git checkout main && git pull origin main
|
|
203
|
+
git tag vX.X.X
|
|
204
|
+
git push origin vX.X.X
|
|
205
|
+
git checkout dev
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Request `git_write` permissions for this step.
|
|
209
|
+
|
|
210
|
+
**Important**: The tag must point to the merged release commit on `main` (not `dev`). Always return to `dev` after tagging to continue development work.
|
|
211
|
+
|
|
212
|
+
## Version Numbering
|
|
213
|
+
|
|
214
|
+
Follow semantic versioning:
|
|
215
|
+
|
|
216
|
+
- **Patch (X.X.1)**: Bug fixes, minor UI improvements
|
|
217
|
+
- **Minor (X.1.0)**: New features, significant changes
|
|
218
|
+
- **Major (1.0.0)**: Breaking changes, major releases
|
|
219
|
+
|
|
220
|
+
## Common Pitfalls
|
|
221
|
+
|
|
222
|
+
1. **Not on dev branch**: Always verify you're on `dev` branch before starting
|
|
223
|
+
2. **Wrong PRs included**: Always verify PRs were merged to `dev`, not feature branches
|
|
224
|
+
3. **Skipping user confirmation**: Always wait for explicit user approval before committing or creating PR
|
|
225
|
+
4. **Forgot to commit**: The tag will point to the wrong commit if you don't commit first
|
|
226
|
+
5. **Wrong version type**: Carefully determine if it's a patch, minor, or major version based on the changes
|
|
227
|
+
6. **SSH authentication**: If git push fails with passphrase error, user needs to handle authentication
|
|
228
|
+
7. **Left on main branch**: Always return to `dev` branch after tagging to continue development work
|
|
229
|
+
|
|
230
|
+
## Example Output
|
|
231
|
+
|
|
232
|
+
At the end, provide a summary:
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
✅ Git Branch - Verified on dev branch with latest changes
|
|
236
|
+
✅ CHANGELOG.md - Updated with vX.X.X entry (user confirmed)
|
|
237
|
+
✅ package.json - Bumped version from X.X.X to X.X.X (user confirmed)
|
|
238
|
+
✅ Git Commit - Committed and pushed version bump to dev
|
|
239
|
+
✅ Release PR - Created #XXX from dev to main (user confirmed)
|
|
240
|
+
✅ Git Tag - Created and pushed vX.X.X tag to origin
|
|
241
|
+
✅ Git Branch - Returned to dev branch
|
|
242
|
+
```
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/install.ts
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
|
|
9
|
+
// src/targets/cursor.ts
|
|
10
|
+
import path2 from "path";
|
|
11
|
+
|
|
12
|
+
// src/utils/fs.ts
|
|
13
|
+
import path from "path";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import fs from "fs-extra";
|
|
16
|
+
function getPackageRoot() {
|
|
17
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
18
|
+
const currentDir = path.dirname(currentFile);
|
|
19
|
+
return path.resolve(currentDir, "..");
|
|
20
|
+
}
|
|
21
|
+
async function copyDirectory(source, target, force) {
|
|
22
|
+
let copied = 0;
|
|
23
|
+
let skipped = 0;
|
|
24
|
+
const sourceExists = await fs.pathExists(source);
|
|
25
|
+
if (!sourceExists) {
|
|
26
|
+
return { copied, skipped };
|
|
27
|
+
}
|
|
28
|
+
await fs.ensureDir(target);
|
|
29
|
+
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const sourcePath = path.join(source, entry.name);
|
|
32
|
+
const targetPath = path.join(target, entry.name);
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
const result = await copyDirectory(sourcePath, targetPath, force);
|
|
35
|
+
copied += result.copied;
|
|
36
|
+
skipped += result.skipped;
|
|
37
|
+
} else {
|
|
38
|
+
const targetExists = await fs.pathExists(targetPath);
|
|
39
|
+
if (targetExists && !force) {
|
|
40
|
+
skipped++;
|
|
41
|
+
} else {
|
|
42
|
+
await fs.copy(sourcePath, targetPath);
|
|
43
|
+
copied++;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { copied, skipped };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/targets/cursor.ts
|
|
51
|
+
var cursorTarget = {
|
|
52
|
+
id: "cursor",
|
|
53
|
+
name: "Cursor",
|
|
54
|
+
install: async (cwd, force) => {
|
|
55
|
+
const packageRoot = getPackageRoot();
|
|
56
|
+
const targetDir = path2.join(cwd, ".cursor");
|
|
57
|
+
const rulesSource = path2.join(packageRoot, "rules");
|
|
58
|
+
const rulesTarget = path2.join(targetDir, "rules");
|
|
59
|
+
const commandsSource = path2.join(packageRoot, "commands");
|
|
60
|
+
const commandsTarget = path2.join(targetDir, "commands");
|
|
61
|
+
const rulesResult = await copyDirectory(rulesSource, rulesTarget, force);
|
|
62
|
+
const commandsResult = await copyDirectory(commandsSource, commandsTarget, force);
|
|
63
|
+
return {
|
|
64
|
+
rulesCopied: rulesResult.copied,
|
|
65
|
+
commandsCopied: commandsResult.copied,
|
|
66
|
+
skipped: rulesResult.skipped + commandsResult.skipped
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/targets/index.ts
|
|
72
|
+
var targets = {
|
|
73
|
+
cursor: cursorTarget
|
|
74
|
+
};
|
|
75
|
+
function getTarget(id) {
|
|
76
|
+
return targets[id];
|
|
77
|
+
}
|
|
78
|
+
function listTargets() {
|
|
79
|
+
return Object.keys(targets);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/install.ts
|
|
83
|
+
async function install(targetId, force) {
|
|
84
|
+
const target = getTarget(targetId);
|
|
85
|
+
if (!target) {
|
|
86
|
+
console.error(chalk.red(`Unknown target: ${targetId}`));
|
|
87
|
+
console.error(chalk.dim(`Available targets: ${listTargets().join(", ")}`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
console.log(chalk.blue(`Installing agent configurations for ${target.name}...`));
|
|
91
|
+
try {
|
|
92
|
+
const result = await target.install(process.cwd(), force);
|
|
93
|
+
console.log(chalk.green("\nInstallation complete!"));
|
|
94
|
+
console.log(chalk.dim(` Rules copied: ${result.rulesCopied}`));
|
|
95
|
+
console.log(chalk.dim(` Commands copied: ${result.commandsCopied}`));
|
|
96
|
+
if (result.skipped > 0) {
|
|
97
|
+
console.log(chalk.yellow(` Skipped (already exist): ${result.skipped}`));
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
console.error(chalk.red(`Installation failed: ${message}`));
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/cli.ts
|
|
107
|
+
var program = new Command();
|
|
108
|
+
program.name("agents").description("Install shared agent skills, rules, and commands for your IDE").version("0.1.0");
|
|
109
|
+
program.command("install").description("Install agent configurations to target IDE").requiredOption("-t, --target <ide>", "Target IDE (e.g., cursor)").option("-f, --force", "Overwrite existing files without prompting", false).action(async (options) => {
|
|
110
|
+
await install(options.target, options.force);
|
|
111
|
+
});
|
|
112
|
+
program.parse();
|
|
113
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/install.ts","../src/targets/cursor.ts","../src/utils/fs.ts","../src/targets/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { install } from \"./install.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"agents\")\n .description(\"Install shared agent skills, rules, and commands for your IDE\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"install\")\n .description(\"Install agent configurations to target IDE\")\n .requiredOption(\"-t, --target <ide>\", \"Target IDE (e.g., cursor)\")\n .option(\"-f, --force\", \"Overwrite existing files without prompting\", false)\n .action(async (options: { target: string; force: boolean }) => {\n await install(options.target, options.force);\n });\n\nprogram.parse();\n","import chalk from \"chalk\";\nimport { getTarget, listTargets } from \"./targets/index.js\";\n\nexport async function install(targetId: string, force: boolean): Promise<void> {\n const target = getTarget(targetId);\n\n if (!target) {\n console.error(chalk.red(`Unknown target: ${targetId}`));\n console.error(chalk.dim(`Available targets: ${listTargets().join(\", \")}`));\n process.exit(1);\n }\n\n console.log(chalk.blue(`Installing agent configurations for ${target.name}...`));\n\n try {\n const result = await target.install(process.cwd(), force);\n\n console.log(chalk.green(\"\\nInstallation complete!\"));\n console.log(chalk.dim(` Rules copied: ${result.rulesCopied}`));\n console.log(chalk.dim(` Commands copied: ${result.commandsCopied}`));\n\n if (result.skipped > 0) {\n console.log(chalk.yellow(` Skipped (already exist): ${result.skipped}`));\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(chalk.red(`Installation failed: ${message}`));\n process.exit(1);\n }\n}\n","import path from \"node:path\";\nimport { copyDirectory, getPackageRoot } from \"../utils/fs.js\";\nimport type { InstallResult, Target } from \"./index.js\";\n\nexport const cursorTarget: Target = {\n id: \"cursor\",\n name: \"Cursor\",\n install: async (cwd: string, force: boolean): Promise<InstallResult> => {\n const packageRoot = getPackageRoot();\n const targetDir = path.join(cwd, \".cursor\");\n\n const rulesSource = path.join(packageRoot, \"rules\");\n const rulesTarget = path.join(targetDir, \"rules\");\n\n const commandsSource = path.join(packageRoot, \"commands\");\n const commandsTarget = path.join(targetDir, \"commands\");\n\n const rulesResult = await copyDirectory(rulesSource, rulesTarget, force);\n const commandsResult = await copyDirectory(commandsSource, commandsTarget, force);\n\n return {\n rulesCopied: rulesResult.copied,\n commandsCopied: commandsResult.copied,\n skipped: rulesResult.skipped + commandsResult.skipped,\n };\n },\n};\n","import path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport fs from \"fs-extra\";\n\ntype CopyResult = {\n copied: number;\n skipped: number;\n};\n\nexport function getPackageRoot(): string {\n const currentFile = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(currentFile);\n return path.resolve(currentDir, \"..\");\n}\n\nexport async function copyDirectory(\n source: string,\n target: string,\n force: boolean\n): Promise<CopyResult> {\n let copied = 0;\n let skipped = 0;\n\n const sourceExists = await fs.pathExists(source);\n if (!sourceExists) {\n return { copied, skipped };\n }\n\n await fs.ensureDir(target);\n\n const entries = await fs.readdir(source, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = path.join(source, entry.name);\n const targetPath = path.join(target, entry.name);\n\n if (entry.isDirectory()) {\n const result = await copyDirectory(sourcePath, targetPath, force);\n copied += result.copied;\n skipped += result.skipped;\n } else {\n const targetExists = await fs.pathExists(targetPath);\n\n if (targetExists && !force) {\n skipped++;\n } else {\n await fs.copy(sourcePath, targetPath);\n copied++;\n }\n }\n }\n\n return { copied, skipped };\n}\n","import { cursorTarget } from \"./cursor.js\";\n\nexport type InstallResult = {\n rulesCopied: number;\n commandsCopied: number;\n skipped: number;\n};\n\nexport type Target = {\n id: string;\n name: string;\n install: (cwd: string, force: boolean) => Promise<InstallResult>;\n};\n\nconst targets: Record<string, Target> = {\n cursor: cursorTarget,\n};\n\nexport function getTarget(id: string): Target | undefined {\n return targets[id];\n}\n\nexport function listTargets(): string[] {\n return Object.keys(targets);\n}\n"],"mappings":"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","names":["path","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@karedo-hq/agents",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Centralized agent skills, rules, and commands for our engineering team",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agents": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"rules",
|
|
12
|
+
"commands"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai",
|
|
16
|
+
"agents",
|
|
17
|
+
"cursor",
|
|
18
|
+
"ide",
|
|
19
|
+
"rules",
|
|
20
|
+
"commands",
|
|
21
|
+
"skills"
|
|
22
|
+
],
|
|
23
|
+
"author": "Karedo",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^5.3.0",
|
|
27
|
+
"commander": "^12.1.0",
|
|
28
|
+
"fs-extra": "^11.2.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/fs-extra": "^11.0.4",
|
|
32
|
+
"@types/node": "^22.10.0",
|
|
33
|
+
"tsup": "^8.3.5",
|
|
34
|
+
"typescript": "^5.7.2"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"typecheck": "tsc --noEmit"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to define API controllers on the backend.
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
# Controllers Guidelines
|
|
6
|
+
|
|
7
|
+
## Multi-Tenant Architecture
|
|
8
|
+
|
|
9
|
+
- Use `@GetOrganizationId()` decorator to obtain organization scope.
|
|
10
|
+
- Pass `organizationId` to all service methods for scoped database operations.
|
|
11
|
+
|
|
12
|
+
## Structure
|
|
13
|
+
|
|
14
|
+
- Controller Decorator: Use `@Controller('route-path')` to define base route.
|
|
15
|
+
- Route Handlers: Decorate methods with HTTP decorators (`@Get()`, `@Post()`, `@Patch(':id')`, `@Delete(':id')`).
|
|
16
|
+
- Use parameter decorators: `@Body()`, `@Param()`, `@Query()`, `@Req()`, `@UploadedFile()`.
|
|
17
|
+
- Set specific status codes with `@HttpCode(HttpStatus.CREATED)`.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
@Post()
|
|
21
|
+
@HttpCode(HttpStatus.CREATED)
|
|
22
|
+
public async create(
|
|
23
|
+
@GetOrganizationId() organizationId: string,
|
|
24
|
+
@Body() createItemDto: CreateItemDto,
|
|
25
|
+
) {
|
|
26
|
+
return this.itemsService.create(organizationId, createItemDto);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- File Uploads: Use `@UseInterceptors(FileInterceptor('fieldName', options))` with `@UploadedFile()` decorator. Validate with `ParseFilePipe` and validators (`MaxFileSizeValidator`, `FileTypeValidator`).
|
|
31
|
+
- Request Object: Use `@Req()` for direct request access (e.g., `req.user` from auth guards). Type as `RequestWithUser`.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to define DTOs (data-transfer-objects) on the backend.
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
# DTOs Guidelines
|
|
6
|
+
|
|
7
|
+
## Validation
|
|
8
|
+
|
|
9
|
+
Use `class-validator` decorators for input validation:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import {
|
|
13
|
+
IsString,
|
|
14
|
+
IsNotEmpty,
|
|
15
|
+
IsEmail,
|
|
16
|
+
IsOptional,
|
|
17
|
+
MinLength,
|
|
18
|
+
} from 'class-validator';
|
|
19
|
+
|
|
20
|
+
export class CreateUserDto {
|
|
21
|
+
@IsString()
|
|
22
|
+
@IsNotEmpty()
|
|
23
|
+
@MinLength(3)
|
|
24
|
+
username: string;
|
|
25
|
+
|
|
26
|
+
@IsEmail()
|
|
27
|
+
email: string;
|
|
28
|
+
|
|
29
|
+
@IsOptional()
|
|
30
|
+
@IsString()
|
|
31
|
+
displayName?: string;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Principles
|
|
36
|
+
|
|
37
|
+
- Keep DTOs focused on data structure and validation only.
|
|
38
|
+
- No business logic in DTOs.
|