@channeulparks/woorido-skills 1.0.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 ADDED
@@ -0,0 +1,69 @@
1
+ # woorido-skills
2
+
3
+ WooriDo AI Coding Rules for Claude, Gemini, Antigravity and other AI coding assistants.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npx woorido-skills install
9
+ ```
10
+
11
+ This will install:
12
+ - `.claude/skills/woorido/SKILL.md` - Unified coding rules
13
+ - `.agent/workflows/*.md` - Antigravity slash commands
14
+
15
+ ## Usage
16
+
17
+ ### Antigravity (Primary)
18
+
19
+ ```bash
20
+ /component Button # Create WDS React component
21
+ /api-hook challenge # Create React Query hook
22
+ /form CreateChallenge # Create react-hook-form + zod form
23
+ /page ChallengeDetail # Create page component
24
+ /test Button # Create Vitest tests
25
+ /spring-api Challenge # Create Spring Boot API
26
+ /mybatis Challenge # Create MyBatis mapper
27
+ /django-view Search # Create Django DRF viewset
28
+ ```
29
+
30
+ ### VS Code Gemini
31
+
32
+ Reference the skill file in your prompt:
33
+ ```
34
+ @.claude/skills/woorido/SKILL.md 참고해서 Button 컴포넌트 만들어줘
35
+ ```
36
+
37
+ ### Claude Code
38
+
39
+ Skills are automatically loaded from `.claude/skills/`.
40
+
41
+ ## Tech Stack
42
+
43
+ ### Frontend
44
+ - React 18 + Vite + TypeScript
45
+ - WDS (WooriDo Design System) - CSS Modules + CSS Variables
46
+ - React Query (server state) + Zustand (client state)
47
+ - react-hook-form + zod
48
+ - Radix UI
49
+
50
+ ### Backend
51
+ - Spring Boot 3.2 + Java 21 + MyBatis + Oracle
52
+ - Django 5.0 + DRF + Elasticsearch
53
+
54
+ ## Available Workflows
55
+
56
+ | Command | Description |
57
+ |---------|-------------|
58
+ | `/component` | WDS-based React component |
59
+ | `/api-hook` | React Query hook |
60
+ | `/form` | Form with validation |
61
+ | `/page` | Page component |
62
+ | `/test` | Vitest tests |
63
+ | `/spring-api` | Spring Boot REST API |
64
+ | `/mybatis` | MyBatis mapper + XML |
65
+ | `/django-view` | Django REST viewset |
66
+
67
+ ## License
68
+
69
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * WooriDo Skills CLI
5
+ *
6
+ * Usage:
7
+ * npx woorido-skills install
8
+ * npx woorido-skills install --dry-run
9
+ * npx woorido-skills list
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
16
+ const TARGET_DIR = process.cwd();
17
+
18
+ // ANSI colors
19
+ const colors = {
20
+ green: (text) => `\x1b[32m${text}\x1b[0m`,
21
+ yellow: (text) => `\x1b[33m${text}\x1b[0m`,
22
+ blue: (text) => `\x1b[34m${text}\x1b[0m`,
23
+ red: (text) => `\x1b[31m${text}\x1b[0m`,
24
+ dim: (text) => `\x1b[2m${text}\x1b[0m`,
25
+ };
26
+
27
+ /**
28
+ * Copy files recursively
29
+ */
30
+ function copyRecursive(src, dest, dryRun = false) {
31
+ const files = [];
32
+
33
+ function walk(srcPath, destPath) {
34
+ const entries = fs.readdirSync(srcPath, { withFileTypes: true });
35
+
36
+ for (const entry of entries) {
37
+ const srcFile = path.join(srcPath, entry.name);
38
+ const destFile = path.join(destPath, entry.name);
39
+
40
+ if (entry.isDirectory()) {
41
+ if (!dryRun && !fs.existsSync(destFile)) {
42
+ fs.mkdirSync(destFile, { recursive: true });
43
+ }
44
+ walk(srcFile, destFile);
45
+ } else {
46
+ files.push({
47
+ src: srcFile,
48
+ dest: destFile,
49
+ relativeDest: path.relative(TARGET_DIR, destFile),
50
+ });
51
+
52
+ if (!dryRun) {
53
+ const destDir = path.dirname(destFile);
54
+ if (!fs.existsSync(destDir)) {
55
+ fs.mkdirSync(destDir, { recursive: true });
56
+ }
57
+ fs.copyFileSync(srcFile, destFile);
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ walk(src, dest);
64
+ return files;
65
+ }
66
+
67
+ /**
68
+ * Install command
69
+ */
70
+ function install(options = {}) {
71
+ const { dryRun = false } = options;
72
+
73
+ console.log();
74
+ console.log(colors.blue('🚀 WooriDo Skills Installer'));
75
+ console.log();
76
+
77
+ if (dryRun) {
78
+ console.log(colors.yellow('📋 Dry run mode - no files will be created'));
79
+ console.log();
80
+ }
81
+
82
+ const files = copyRecursive(TEMPLATES_DIR, TARGET_DIR, dryRun);
83
+
84
+ console.log(colors.dim('Installing files:'));
85
+ console.log();
86
+
87
+ for (const file of files) {
88
+ console.log(` ${colors.green('✔')} ${file.relativeDest}`);
89
+ }
90
+
91
+ console.log();
92
+ console.log(colors.green(`✨ Done! ${files.length} files installed.`));
93
+ console.log();
94
+ console.log(colors.dim('Installed:'));
95
+ console.log(colors.dim(' - .claude/skills/woorido/SKILL.md (unified coding rules)'));
96
+ console.log(colors.dim(' - .agent/workflows/*.md (Antigravity commands)'));
97
+ console.log();
98
+ console.log(colors.blue('Usage:'));
99
+ console.log(' Antigravity: /component Button, /api-hook challenge, etc.');
100
+ console.log(' VS Code Gemini: @.claude/skills/woorido/SKILL.md');
101
+ console.log();
102
+ }
103
+
104
+ /**
105
+ * List command
106
+ */
107
+ function list() {
108
+ console.log();
109
+ console.log(colors.blue('📦 WooriDo Skills'));
110
+ console.log();
111
+
112
+ console.log(colors.dim('Unified SKILL.md:'));
113
+ console.log(' .claude/skills/woorido/SKILL.md');
114
+ console.log();
115
+
116
+ console.log(colors.dim('Antigravity Workflows:'));
117
+ const workflows = [
118
+ '/component - Create WDS React component',
119
+ '/api-hook - Create React Query hook',
120
+ '/form - Create react-hook-form + zod form',
121
+ '/page - Create page component',
122
+ '/test - Create Vitest tests',
123
+ '/spring-api - Create Spring Boot API',
124
+ '/mybatis - Create MyBatis mapper',
125
+ '/django-view - Create Django DRF viewset',
126
+ ];
127
+
128
+ for (const wf of workflows) {
129
+ console.log(` ${wf}`);
130
+ }
131
+ console.log();
132
+ }
133
+
134
+ /**
135
+ * Help command
136
+ */
137
+ function help() {
138
+ console.log();
139
+ console.log(colors.blue('WooriDo Skills CLI'));
140
+ console.log();
141
+ console.log('Commands:');
142
+ console.log(' install Install skills to current directory');
143
+ console.log(' install --dry-run Show files without installing');
144
+ console.log(' list List available skills and workflows');
145
+ console.log(' help Show this help message');
146
+ console.log();
147
+ console.log('Examples:');
148
+ console.log(' npx woorido-skills install');
149
+ console.log(' npx woorido-skills list');
150
+ console.log();
151
+ }
152
+
153
+ // Parse arguments
154
+ const args = process.argv.slice(2);
155
+ const command = args[0];
156
+ const flags = args.slice(1);
157
+
158
+ const options = {
159
+ dryRun: flags.includes('--dry-run'),
160
+ };
161
+
162
+ // Execute command
163
+ switch (command) {
164
+ case 'install':
165
+ install(options);
166
+ break;
167
+ case 'list':
168
+ list();
169
+ break;
170
+ case 'help':
171
+ case '--help':
172
+ case '-h':
173
+ help();
174
+ break;
175
+ default:
176
+ if (command) {
177
+ console.log(colors.red(`Unknown command: ${command}`));
178
+ }
179
+ help();
180
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@channeulparks/woorido-skills",
3
+ "version": "1.0.0",
4
+ "description": "WooriDo AI Coding Rules for Claude, Gemini, Antigravity and other AI coding assistants",
5
+ "main": "bin/cli.js",
6
+ "bin": {
7
+ "woorido-skills": "./bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "templates"
12
+ ],
13
+ "scripts": {
14
+ "test": "node bin/cli.js install --dry-run"
15
+ },
16
+ "keywords": [
17
+ "ai",
18
+ "coding",
19
+ "rules",
20
+ "claude",
21
+ "gemini",
22
+ "antigravity",
23
+ "woorido",
24
+ "skills",
25
+ "react",
26
+ "spring-boot",
27
+ "django"
28
+ ],
29
+ "author": "WooriDo Team",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/ParkChanNul/woorido-skills"
34
+ }
35
+ }
@@ -0,0 +1,134 @@
1
+ ---
2
+ description: Create a React Query hook for API calls
3
+ ---
4
+
5
+ # /api-hook [ResourceName]
6
+
7
+ <!-- React Query 기반 API 훅 생성 -->
8
+
9
+ ## Usage
10
+ ```
11
+ /api-hook challenge
12
+ /api-hook user --mutations
13
+ /api-hook ledger --infinite
14
+ ```
15
+
16
+ ## Steps
17
+
18
+ // turbo
19
+ 1. Create `src/hooks/use[ResourceName].ts`:
20
+
21
+ ```tsx
22
+ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
23
+ import { api } from '@/lib/api';
24
+ import type { [ResourceName] } from '@/types';
25
+
26
+ // Query Keys
27
+ export const [resourceName]Keys = {
28
+ all: ['[resourceName]s'] as const,
29
+ lists: () => [...[resourceName]Keys.all, 'list'] as const,
30
+ list: (filters: Record<string, unknown>) => [...[resourceName]Keys.lists(), filters] as const,
31
+ details: () => [...[resourceName]Keys.all, 'detail'] as const,
32
+ detail: (id: string) => [...[resourceName]Keys.details(), id] as const,
33
+ };
34
+
35
+ // GET single
36
+ export function use[ResourceName](id: string) {
37
+ return useQuery({
38
+ queryKey: [resourceName]Keys.detail(id),
39
+ queryFn: () => api.get<[ResourceName]>(`/[resourceName]s/${id}`),
40
+ enabled: !!id,
41
+ });
42
+ }
43
+
44
+ // GET list
45
+ export function use[ResourceName]List(filters?: Record<string, unknown>) {
46
+ return useQuery({
47
+ queryKey: [resourceName]Keys.list(filters ?? {}),
48
+ queryFn: () => api.get<[ResourceName][]>('/[resourceName]s', { params: filters }),
49
+ });
50
+ }
51
+ ```
52
+
53
+ ## Mutations (--mutations flag)
54
+
55
+ <!-- 생성/수정/삭제 뮤테이션 추가 -->
56
+
57
+ ```tsx
58
+ // CREATE
59
+ export function useCreate[ResourceName]() {
60
+ const queryClient = useQueryClient();
61
+
62
+ return useMutation({
63
+ mutationFn: (data: Create[ResourceName]Request) =>
64
+ api.post<[ResourceName]>('/[resourceName]s', data),
65
+ onSuccess: () => {
66
+ queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
67
+ },
68
+ });
69
+ }
70
+
71
+ // UPDATE
72
+ export function useUpdate[ResourceName]() {
73
+ const queryClient = useQueryClient();
74
+
75
+ return useMutation({
76
+ mutationFn: ({ id, data }: { id: string; data: Update[ResourceName]Request }) =>
77
+ api.put<[ResourceName]>(`/[resourceName]s/${id}`, data),
78
+ onSuccess: (_, { id }) => {
79
+ queryClient.invalidateQueries({ queryKey: [resourceName]Keys.detail(id) });
80
+ queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
81
+ },
82
+ });
83
+ }
84
+
85
+ // DELETE
86
+ export function useDelete[ResourceName]() {
87
+ const queryClient = useQueryClient();
88
+
89
+ return useMutation({
90
+ mutationFn: (id: string) => api.delete(`/[resourceName]s/${id}`),
91
+ onSuccess: () => {
92
+ queryClient.invalidateQueries({ queryKey: [resourceName]Keys.lists() });
93
+ },
94
+ });
95
+ }
96
+ ```
97
+
98
+ ## Infinite Query (--infinite flag)
99
+
100
+ <!-- 무한 스크롤 목록 조회 -->
101
+
102
+ ```tsx
103
+ import { useInfiniteQuery } from '@tanstack/react-query';
104
+
105
+ export function use[ResourceName]Infinite(filters?: Record<string, unknown>) {
106
+ return useInfiniteQuery({
107
+ queryKey: [...[resourceName]Keys.lists(), 'infinite', filters],
108
+ queryFn: ({ pageParam = 0 }) =>
109
+ api.get<PaginatedResponse<[ResourceName]>>('/[resourceName]s', {
110
+ params: { ...filters, page: pageParam, size: 20 }
111
+ }),
112
+ getNextPageParam: (lastPage) =>
113
+ lastPage.hasNext ? lastPage.page + 1 : undefined,
114
+ initialPageParam: 0,
115
+ });
116
+ }
117
+ ```
118
+
119
+ ## API Client Reference
120
+
121
+ ```tsx
122
+ // lib/api.ts
123
+ import axios from 'axios';
124
+
125
+ export const api = axios.create({
126
+ baseURL: import.meta.env.VITE_API_URL,
127
+ headers: { 'Content-Type': 'application/json' },
128
+ });
129
+
130
+ api.interceptors.response.use(
131
+ (res) => res.data,
132
+ (error) => Promise.reject(error.response?.data ?? error)
133
+ );
134
+ ```
@@ -0,0 +1,117 @@
1
+ ---
2
+ description: Create a WDS-based React component with CSS Modules
3
+ ---
4
+
5
+ # /component [ComponentName]
6
+
7
+ <!-- WDS 디자인 시스템 기반 React 컴포넌트 생성 -->
8
+
9
+ ## Usage
10
+ ```
11
+ /component Button
12
+ /component Modal --radix
13
+ /component UserCard --domain
14
+ ```
15
+
16
+ ## Steps
17
+
18
+ // turbo
19
+ 1. Create folder `src/components/[ComponentName]/`
20
+
21
+ // turbo
22
+ 2. Create `[ComponentName].tsx` with this template:
23
+
24
+ ```tsx
25
+ import styles from './[ComponentName].module.css';
26
+ import clsx from 'clsx';
27
+
28
+ interface [ComponentName]Props {
29
+ className?: string;
30
+ children?: React.ReactNode;
31
+ }
32
+
33
+ export function [ComponentName]({ className, children }: [ComponentName]Props) {
34
+ return (
35
+ <div className={clsx(styles.root, className)}>
36
+ {children}
37
+ </div>
38
+ );
39
+ }
40
+ ```
41
+
42
+ // turbo
43
+ 3. Create `[ComponentName].module.css` with WDS tokens:
44
+
45
+ ```css
46
+ .root {
47
+ /* Layout */
48
+ display: flex;
49
+
50
+ /* Spacing - use WDS tokens */
51
+ padding: var(--space-4);
52
+ gap: var(--space-2);
53
+
54
+ /* Shape */
55
+ border-radius: var(--radius-md);
56
+
57
+ /* Colors */
58
+ background-color: var(--color-surface);
59
+ color: var(--color-text-primary);
60
+
61
+ /* Shadow */
62
+ box-shadow: var(--shadow-sm);
63
+
64
+ /* Motion */
65
+ transition: box-shadow var(--motion-duration-fast) var(--motion-ease-standard);
66
+ }
67
+
68
+ .root:hover {
69
+ box-shadow: var(--shadow-md);
70
+ }
71
+ ```
72
+
73
+ // turbo
74
+ 4. Create `index.ts` for re-export:
75
+
76
+ ```ts
77
+ export { [ComponentName] } from './[ComponentName]';
78
+ export type { [ComponentName]Props } from './[ComponentName]';
79
+ ```
80
+
81
+ ## Radix UI Wrapping (--radix flag)
82
+
83
+ <!-- Radix UI 컴포넌트 래핑 시 적용 -->
84
+
85
+ ```tsx
86
+ import * as Dialog from '@radix-ui/react-dialog';
87
+ import styles from './Modal.module.css';
88
+
89
+ export function Modal({ open, onOpenChange, children }) {
90
+ return (
91
+ <Dialog.Root open={open} onOpenChange={onOpenChange}>
92
+ <Dialog.Portal>
93
+ <Dialog.Overlay className={styles.overlay} />
94
+ <Dialog.Content className={styles.content}>
95
+ {children}
96
+ </Dialog.Content>
97
+ </Dialog.Portal>
98
+ </Dialog.Root>
99
+ );
100
+ }
101
+ ```
102
+
103
+ ## Domain Component (--domain flag)
104
+
105
+ <!-- 도메인 특화 컴포넌트 (BrixBadge, FinancialText 등) -->
106
+
107
+ Place in `src/components/domain/` folder.
108
+
109
+ ## WDS Token Reference
110
+
111
+ | Category | Tokens |
112
+ |----------|--------|
113
+ | Colors | `--color-orange-*`, `--color-grey-*` |
114
+ | Spacing | `--space-1` ~ `--space-12` |
115
+ | Radius | `--radius-sm/md/lg/xl/full` |
116
+ | Shadow | `--shadow-sm/md/lg/xl` |
117
+ | Motion | `--motion-duration-*`, `--motion-ease-*` |