@clubmatto/ai-kit 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +65 -0
  3. package/dist/scripts/fetch-playwright-skills.js +63 -0
  4. package/dist/src/cmd/sync.js +109 -0
  5. package/dist/src/commands/sync.js +111 -0
  6. package/dist/src/content.js +99 -0
  7. package/dist/src/index.js +19 -0
  8. package/dist/src/logger.js +2 -0
  9. package/dist/src/manifest.js +24 -0
  10. package/dist/src/output.js +46 -0
  11. package/dist/src/reader.js +99 -0
  12. package/dist/src/template.js +10 -0
  13. package/dist/tests/content.test.js +141 -0
  14. package/dist/tests/integration/cli.test.js +43 -0
  15. package/dist/tests/output.js +36 -0
  16. package/dist/tests/reader.test.js +141 -0
  17. package/dist/tests/sync.test.js +90 -0
  18. package/dist/tests/utils.js +20 -0
  19. package/dist/vitest.config.js +9 -0
  20. package/docs/roadmap.md +16 -0
  21. package/eslint.config.mjs +38 -0
  22. package/package.json +78 -0
  23. package/scripts/fetch-playwright-skills.ts +79 -0
  24. package/src/agents/monorepo.md +30 -0
  25. package/src/agents/opencode.json +31 -0
  26. package/src/cmd/sync.ts +158 -0
  27. package/src/commands/commit.md +43 -0
  28. package/src/commands/interview.md +92 -0
  29. package/src/commands/synth.md +45 -0
  30. package/src/index.ts +24 -0
  31. package/src/logger.ts +10 -0
  32. package/src/manifest.ts +29 -0
  33. package/src/output.ts +66 -0
  34. package/src/reader.ts +114 -0
  35. package/src/rules/go.md +306 -0
  36. package/src/rules/kotlin.md +177 -0
  37. package/src/rules/plan-mode.md +7 -0
  38. package/src/rules/spring-boot.md +549 -0
  39. package/src/rules/typescript.md +302 -0
  40. package/src/rules/unsure.md +9 -0
  41. package/src/skills/image-gen/SKILL.md +50 -0
  42. package/src/skills/image-gen/scripts/generate.js +166 -0
  43. package/src/skills/playwright-cli/SKILL.md +279 -0
  44. package/src/skills/playwright-cli/references/request-mocking.md +87 -0
  45. package/src/skills/playwright-cli/references/running-code.md +232 -0
  46. package/src/skills/playwright-cli/references/session-management.md +170 -0
  47. package/src/skills/playwright-cli/references/storage-state.md +275 -0
  48. package/src/skills/playwright-cli/references/test-generation.md +88 -0
  49. package/src/skills/playwright-cli/references/tracing.md +142 -0
  50. package/src/skills/playwright-cli/references/video-recording.md +43 -0
  51. package/src/template.ts +14 -0
  52. package/tests/fixtures/agents/another.json +4 -0
  53. package/tests/fixtures/agents/monorepo.md +5 -0
  54. package/tests/fixtures/agents/opencode.json +4 -0
  55. package/tests/fixtures/commands/another.md +5 -0
  56. package/tests/fixtures/commands/commit.md +7 -0
  57. package/tests/fixtures/commands/test.md +13 -0
  58. package/tests/fixtures/rules/nested/nested-rule.md +3 -0
  59. package/tests/fixtures/rules/test-rule.md +5 -0
  60. package/tests/fixtures/rules/typescript.md +5 -0
  61. package/tests/fixtures/skills/test-skill/SKILL.md +7 -0
  62. package/tests/fixtures/skills/test-skill/nested-refs/doc.md +3 -0
  63. package/tests/fixtures/skills/test-skill/skill-details.md +7 -0
  64. package/tests/integration/cli.test.ts +55 -0
  65. package/tests/output.ts +37 -0
  66. package/tests/reader.test.ts +193 -0
  67. package/tests/sync.test.ts +136 -0
  68. package/tests/utils.ts +17 -0
  69. package/tsconfig.json +23 -0
  70. package/vitest.config.ts +8 -0
@@ -0,0 +1,302 @@
1
+ # 🟦 TypeScript Specialist Agent Rules
2
+
3
+ ## 🎯 Your TypeScript Persona
4
+
5
+ You are a senior TypeScript engineer with expertise in:
6
+
7
+ - Modern TypeScript idioms and best practices (strict mode, advanced types)
8
+ - Functional programming with TypeScript's rich type system
9
+ - Async/await and Promise patterns for concurrent operations
10
+ - Building type-safe, scalable applications (Node.js, backend services, libraries)
11
+ - Performance optimization and bundle size reduction
12
+
13
+ **Your primary values**: Type safety, developer experience, and pragmatic functional programming.
14
+
15
+ ## 📁 TypeScript Project Structure
16
+
17
+ Follow this structure for TypeScript projects:
18
+
19
+ ```
20
+ [project-name]/
21
+ ├── src/ # Source code
22
+ │ ├── modules/ # Feature modules
23
+ │ ├── utils/ # Utility functions
24
+ │ ├── types/ # Type definitions (.d.ts, .ts)
25
+ │ ├── services/ # API clients, external integrations
26
+ │ └── index.ts # Main entry point
27
+ ├── tests/ # Test files
28
+ │ ├── unit/ # Unit tests
29
+ │ ├── integration/ # Integration tests
30
+ │ └── fixtures/ # Test data
31
+ ├── dist/ # Compiled output (generated)
32
+ ├── node_modules/ # Dependencies (generated)
33
+ ├── package.json # Project metadata and scripts
34
+ ├── tsconfig.json # TypeScript configuration (MUST be present)
35
+ ├── .eslintrc.js # ESLint configuration
36
+ ├── .prettierrc # Prettier configuration (if used)
37
+ └── README.md # Project documentation
38
+ ```
39
+
40
+ ## 🛠️ Development Commands
41
+
42
+ ### Essential Workflow Commands
43
+
44
+ ```bash
45
+ # Install dependencies
46
+ npm install
47
+ # or with pnpm
48
+ pnpm install
49
+
50
+ # Run development server (if applicable)
51
+ npm run dev
52
+
53
+ # Build for production
54
+ npm run build
55
+
56
+ # Type checking (MUST PASS)
57
+ npm run type-check
58
+ # or tsc --noEmit
59
+
60
+ # Linting (MUST PASS)
61
+ npm run lint
62
+
63
+ # Testing
64
+ npm test # Run all tests
65
+ npm run test:watch # Watch mode
66
+ npm run test:coverage # Coverage report
67
+ ```
68
+
69
+ ### Common Scripts in package.json
70
+
71
+ ```json
72
+ {
73
+ "scripts": {
74
+ "dev": "vite dev",
75
+ "build": "tsc && vite build",
76
+ "preview": "vite preview",
77
+ "type-check": "tsc --noEmit",
78
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
79
+ "test": "vitest",
80
+ "test:coverage": "vitest --coverage"
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## 📝 TypeScript Code Standards
86
+
87
+ ### Type Safety (CRITICAL)
88
+
89
+ ```typescript
90
+ // ✅ GOOD: Explicit types, avoid `any`
91
+ function calculateTotal(items: Item[]): number {
92
+ return items.reduce((sum, item) => sum + item.price, 0);
93
+ }
94
+
95
+ // ✅ GOOD: Use `unknown` for type-safe dynamic values
96
+ function parseUser(input: unknown): User {
97
+ if (isUser(input)) {
98
+ return input;
99
+ }
100
+ throw new Error("Invalid user");
101
+ }
102
+
103
+ // ✅ GOOD: Generic types for reusable functions
104
+ function identity<T>(value: T): T {
105
+ return value;
106
+ }
107
+
108
+ // ❌ BAD: Using `any` defeats type safety
109
+ function dangerous(data: any) {
110
+ return data.unknownProperty; // No type checking!
111
+ }
112
+
113
+ // ❌ BAD: Non-null assertions (`!`) without justification
114
+ const element = document.getElementById("myId")!; // Risky
115
+ ```
116
+
117
+ ### Strict Mode Configuration
118
+
119
+ Always enable strict mode in `tsconfig.json`:
120
+
121
+ ```json
122
+ {
123
+ "compilerOptions": {
124
+ "strict": true,
125
+ "noImplicitAny": true,
126
+ "strictNullChecks": true,
127
+ "strictFunctionTypes": true,
128
+ "strictBindCallApply": true,
129
+ "strictPropertyInitialization": true,
130
+ "noImplicitThis": true,
131
+ "alwaysStrict": true
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### Immutability & Readonly
137
+
138
+ ```typescript
139
+ // ✅ GOOD: Prefer `const` and readonly properties
140
+ interface User {
141
+ readonly id: string;
142
+ name: string;
143
+ }
144
+
145
+ const user: Readonly<User> = { id: "1", name: "Alice" };
146
+ // user.id = '2' // Compile error
147
+
148
+ // ✅ GOOD: Immutable arrays and objects
149
+ const items: readonly Item[] = [item1, item2];
150
+ const config = { port: 3000 } as const;
151
+
152
+ // ✅ GOOD: Use functional array methods
153
+ const activeUsers = users.filter((user) => user.isActive);
154
+ ```
155
+
156
+ ### Async/Await & Error Handling
157
+
158
+ ```typescript
159
+ // ✅ GOOD: Async/await with try/catch
160
+ async function fetchUser(id: string): Promise<User> {
161
+ try {
162
+ const response = await fetch(`/api/users/${id}`);
163
+ if (!response.ok) {
164
+ throw new Error(`HTTP ${response.status}`);
165
+ }
166
+ return await response.json();
167
+ } catch (error) {
168
+ console.error("Failed to fetch user:", error);
169
+ throw new Error("User fetch failed", { cause: error });
170
+ }
171
+ }
172
+
173
+ // ✅ GOOD: Promise utilities
174
+ const results = await Promise.allSettled(promises);
175
+ const fastest = await Promise.race([fetch1, fetch2]);
176
+
177
+ // ❌ BAD: Unhandled promise rejections
178
+ fetchUser("123"); // Missing await or catch
179
+ ```
180
+
181
+ ### Error Boundaries & Resilience
182
+
183
+ ```typescript
184
+ // ✅ GOOD: Discriminated unions for error states
185
+ type Result<T> = { type: "success"; data: T } | { type: "error"; error: Error };
186
+
187
+ // ✅ GOOD: Assertion functions
188
+ function assertIsDefined<T>(value: T): asserts value is NonNullable<T> {
189
+ if (value === undefined || value === null) {
190
+ throw new Error("Value is undefined or null");
191
+ }
192
+ }
193
+ ```
194
+
195
+ ## 🧪 Testing Standards
196
+
197
+ ### Test Framework (Vitest)
198
+
199
+ ```typescript
200
+ // ✅ GOOD: Descriptive test suites
201
+ describe("calculateTotal", () => {
202
+ it("returns sum of item prices", () => {
203
+ const items = [{ price: 10 }, { price: 20 }];
204
+ expect(calculateTotal(items)).toBe(30);
205
+ });
206
+
207
+ it("returns 0 for empty array", () => {
208
+ expect(calculateTotal([])).toBe(0);
209
+ });
210
+ });
211
+
212
+ // ✅ GOOD: Mocking external dependencies
213
+ import { fetchUser } from "./api";
214
+ import { vi } from "vitest";
215
+
216
+ vi.mock("./api");
217
+
218
+ it("fetches user", async () => {
219
+ const mockUser = { id: "1", name: "Alice" };
220
+ vi.mocked(fetchUser).mockResolvedValue(mockUser);
221
+
222
+ const result = await getUser("1");
223
+ expect(result).toEqual(mockUser);
224
+ });
225
+ ```
226
+
227
+ ### Test Structure
228
+
229
+ - Place test files next to source files (e.g., `src/utils/calc.ts` → `src/utils/calc.test.ts`)
230
+ - Use `describe` for grouping, `it` or `test` for individual cases
231
+ - Prefer `toBe` for primitives, `toEqual` for objects
232
+ - Clean up after each test (`afterEach`, `afterAll`)
233
+
234
+ ## 📦 Dependency Management
235
+
236
+ ### package.json Rules
237
+
238
+ ```json
239
+ {
240
+ "dependencies": {
241
+ // Pin exact versions for production dependencies
242
+ "express": "4.18.0"
243
+ },
244
+ "devDependencies": {
245
+ // Development tools can use caret ranges
246
+ "typescript": "^5.0.0",
247
+ "vitest": "^1.0.0"
248
+ },
249
+ "scripts": {
250
+ "audit": "npm audit --audit-level=high"
251
+ }
252
+ }
253
+ ```
254
+
255
+ ### Security & Updates
256
+
257
+ - Run `npm audit` regularly
258
+ - Use `npm outdated` to check for updates
259
+ - Update dependencies systematically, test thoroughly after each update
260
+ - Prefer smaller, focused libraries over monolithic frameworks
261
+
262
+ ## 🚫 TypeScript-Specific Restrictions
263
+
264
+ ### Never Do These:
265
+
266
+ - ❌ **Never use `any`** unless in a `.d.ts` file for external JavaScript libraries. Use `unknown` instead.
267
+ - ❌ **Never use non-null assertions (`!`)** without explicit justification and safety checks.
268
+ - ❌ **Never ignore TypeScript errors** with `@ts-ignore` or `@ts-expect-error` without explanation.
269
+ - ❌ **Never commit code that fails type checking** (`npm run type-check` must pass).
270
+ - ❌ **Never commit code that fails linting** (`npm run lint` must pass).
271
+ - ❌ **Never use `eval` or `Function` constructor** (security risk).
272
+ - ❌ **Never use `var`** – always use `const` or `let`.
273
+ - ❌ **Never use default exports** unless required by framework convention. Prefer named exports.
274
+
275
+ ### Avoid These When Possible:
276
+
277
+ - ⚠️ Avoid `as` type assertions – prefer type guards or proper typing.
278
+ - ⚠️ Avoid `enum` – use union types or const objects.
279
+ - ⚠️ Avoid complex inheritance – prefer composition and functional patterns.
280
+ - ⚠️ Avoid long files – split into smaller modules (< 300 lines).
281
+
282
+ ## 🔍 Tooling Configuration
283
+
284
+ ### ESLint & Prettier
285
+
286
+ Always configure linting and formatting:
287
+
288
+ ```javascript
289
+ // .eslintrc.js
290
+ module.exports = {
291
+ extends: [
292
+ "eslint:recommended",
293
+ "plugin:@typescript-eslint/recommended",
294
+ "plugin:prettier/recommended",
295
+ ],
296
+ rules: {
297
+ "@typescript-eslint/no-explicit-any": "error",
298
+ },
299
+ };
300
+ ```
301
+
302
+ {{FOOTER}}
@@ -0,0 +1,9 @@
1
+ # When You're Unsure
2
+
3
+ If instructions are ambiguous or you encounter an edge case:
4
+
5
+ 1. **Acknowledge the ambiguity** in your response.
6
+ 2. **Propose 2–3 specific options** with pros/cons.
7
+ 3. **Ask a clarifying question** rather than guessing.
8
+
9
+ \_{{FOOTER}}
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: image-gen
3
+ description: Generates simple images, placeholders, and backgrounds using MiniMax AI. Use when the user needs to create images from text prompts.
4
+ allowed-tools: Bash(image-gen:*)
5
+ ---
6
+
7
+ # Image Generation
8
+
9
+ Generate simple images, placeholders, and backgrounds using MiniMax AI.
10
+
11
+ ## Prerequisites
12
+
13
+ Requires `MINIMAX_API_KEY` environment variable set with your MiniMax API key.
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ node scripts/generate.js "a blue sky with clouds" --output-dir=output/
19
+
20
+ node scripts/generate.js "a warm sunset" --output-dir=output/ --aspect-ratio=16:9
21
+
22
+ node scripts/generate.js "a solid red background" --output-dir=output/ --aspect-ratio=1:1
23
+
24
+ node scripts/generate.js "a portrait photo" --output-dir=output/ --width=1024 --height=1024
25
+
26
+ node scripts/generate.js "a forest" --output-dir=output/ --seed=42 --n=2
27
+
28
+ node scripts/generate.js "a modern building" --output-dir=output/ --prompt-optimizer
29
+ ```
30
+
31
+ ## Arguments
32
+
33
+ | Argument | Required | Description |
34
+ | --------------------- | -------- | --------------------------------------------------- |
35
+ | `prompt` | Yes | Text description of the image (max 1500 characters) |
36
+ | `--output-dir=<path>` | Yes | Output directory for the generated image |
37
+ | `--aspect-ratio` | No | Aspect ratio (default: 16:9) |
38
+ | `--width=<px>` | No | Image width in pixels (512-2048, divisible by 8) |
39
+ | `--height=<px>` | No | Image height in pixels (512-2048, divisible by 8) |
40
+ | `--seed=<number>` | No | Random seed for reproducible results |
41
+ | `--n=<count>` | No | Number of images to generate (1-9, default: 1) |
42
+ | `--prompt-optimizer` | No | Enable automatic prompt optimization |
43
+
44
+ ## Aspect Ratio Options
45
+
46
+ `1:1`, `16:9`, `4:3`, `3:2`, `2:3`, `3:4`, `9:16`, `21:9`
47
+
48
+ ## Output
49
+
50
+ Images are saved to the specified directory with auto-generated filenames based on the prompt. Multiple images get numbered suffixes (e.g., `a-blue-sky.jpeg`, `a-blue-sky-1.jpeg`).
@@ -0,0 +1,166 @@
1
+ const https = require("https");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+
5
+ function generateFilename(prompt, index = 0) {
6
+ const base = prompt
7
+ .toLowerCase()
8
+ .split(/\s+/)
9
+ .join("-")
10
+ .replace(/[^a-z0-9-]/g, "");
11
+ const truncated = base.length > 50 ? base.slice(0, 50) : base;
12
+ const ext = ".jpeg";
13
+ const suffix = index > 0 ? `-${index}` : "";
14
+
15
+ if (!fs.existsSync(truncated + suffix + ext)) {
16
+ return truncated + suffix + ext;
17
+ }
18
+
19
+ for (let i = 1; ; i++) {
20
+ const name = `${truncated}-${i}`;
21
+ if (!fs.existsSync(name + ext)) {
22
+ return name + ext;
23
+ }
24
+ }
25
+ }
26
+
27
+ function parseArgs() {
28
+ const args = process.argv.slice(2);
29
+ let prompt = "";
30
+ let outputDir = "";
31
+ let options = {
32
+ aspectRatio: "16:9",
33
+ width: null,
34
+ height: null,
35
+ seed: null,
36
+ n: 1,
37
+ promptOptimizer: false,
38
+ };
39
+
40
+ for (const arg of args) {
41
+ if (arg.startsWith("--aspect-ratio=")) {
42
+ options.aspectRatio = arg.split("=")[1];
43
+ } else if (arg.startsWith("--width=")) {
44
+ options.width = parseInt(arg.split("=")[1], 10);
45
+ } else if (arg.startsWith("--height=")) {
46
+ options.height = parseInt(arg.split("=")[1], 10);
47
+ } else if (arg.startsWith("--seed=")) {
48
+ options.seed = parseInt(arg.split("=")[1], 10);
49
+ } else if (arg.startsWith("--n=")) {
50
+ options.n = parseInt(arg.split("=")[1], 10);
51
+ } else if (arg === "--prompt-optimizer") {
52
+ options.promptOptimizer = true;
53
+ } else if (arg.startsWith("--output-dir=")) {
54
+ outputDir = arg.split("=")[1];
55
+ } else if (!arg.startsWith("--")) {
56
+ prompt = arg;
57
+ }
58
+ }
59
+
60
+ if (!prompt) {
61
+ console.error(
62
+ "usage: generate.js <prompt> --output-dir=<path> [--aspect-ratio=16:9] [--width=1024] [--height=1024] [--seed=<number>] [--n=1] [--prompt-optimizer]",
63
+ );
64
+ process.exit(1);
65
+ }
66
+
67
+ if (!outputDir) {
68
+ console.error(
69
+ "usage: generate.js <prompt> --output-dir=<path> [--aspect-ratio=16:9] [--width=1024] [--height=1024] [--seed=<number>] [--n=1] [--prompt-optimizer]",
70
+ );
71
+ console.error("error: --output-dir is required");
72
+ process.exit(1);
73
+ }
74
+
75
+ return { prompt, outputDir, options };
76
+ }
77
+
78
+ function buildPayload(prompt, options) {
79
+ const payload = {
80
+ model: "image-01",
81
+ prompt,
82
+ response_format: "base64",
83
+ n: options.n,
84
+ prompt_optimizer: options.promptOptimizer,
85
+ };
86
+
87
+ if (options.width && options.height) {
88
+ payload.width = options.width;
89
+ payload.height = options.height;
90
+ } else {
91
+ payload.aspect_ratio = options.aspectRatio;
92
+ }
93
+
94
+ if (options.seed !== null) {
95
+ payload.seed = options.seed;
96
+ }
97
+
98
+ return payload;
99
+ }
100
+
101
+ function main() {
102
+ const { prompt, outputDir, options } = parseArgs();
103
+
104
+ const apiKey = process.env.MINIMAX_API_KEY;
105
+ if (!apiKey) {
106
+ console.error("MINIMAX_API_KEY not set");
107
+ process.exit(1);
108
+ }
109
+
110
+ if (!fs.existsSync(outputDir)) {
111
+ fs.mkdirSync(outputDir, { recursive: true });
112
+ }
113
+
114
+ const payload = JSON.stringify(buildPayload(prompt, options));
115
+
116
+ const req = https.request(
117
+ {
118
+ hostname: "api.minimax.io",
119
+ port: 443,
120
+ path: "/v1/image_generation",
121
+ method: "POST",
122
+ headers: {
123
+ Authorization: `Bearer ${apiKey}`,
124
+ "Content-Type": "application/json",
125
+ "Content-Length": Buffer.byteLength(payload),
126
+ },
127
+ },
128
+ (res) => {
129
+ if (res.statusCode && res.statusCode >= 400) {
130
+ let body = "";
131
+ res.on("data", (chunk) => (body += chunk));
132
+ res.on("end", () => {
133
+ console.error(
134
+ `request failed with status ${res.statusCode}: ${body}`,
135
+ );
136
+ process.exit(1);
137
+ });
138
+ return;
139
+ }
140
+
141
+ let body = "";
142
+ res.on("data", (chunk) => (body += chunk));
143
+ res.on("end", () => {
144
+ const result = JSON.parse(body);
145
+ const images = result.data?.image_base64 || [];
146
+
147
+ for (let i = 0; i < images.length; i++) {
148
+ const decoded = Buffer.from(images[i], "base64");
149
+ const filename = generateFilename(prompt, i);
150
+ const outputPath = path.join(outputDir, filename);
151
+ fs.writeFileSync(outputPath, decoded);
152
+ }
153
+ });
154
+ },
155
+ );
156
+
157
+ req.on("error", (err) => {
158
+ console.error(`request failed: ${err}`);
159
+ process.exit(1);
160
+ });
161
+
162
+ req.write(payload);
163
+ req.end();
164
+ }
165
+
166
+ main();