@su-record/vibe 2.4.24 โ†’ 2.4.26

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 (31) hide show
  1. package/.claude/settings.json +49 -0
  2. package/.claude/settings.local.json +25 -1
  3. package/.claude/vibe/rules/languages/dart-flutter.md +509 -0
  4. package/.claude/vibe/rules/languages/go.md +396 -0
  5. package/.claude/vibe/rules/languages/java-spring.md +586 -0
  6. package/.claude/vibe/rules/languages/kotlin-android.md +491 -0
  7. package/.claude/vibe/rules/languages/python-django.md +371 -0
  8. package/.claude/vibe/rules/languages/python-fastapi.md +386 -0
  9. package/.claude/vibe/rules/languages/rust.md +425 -0
  10. package/.claude/vibe/rules/languages/swift-ios.md +516 -0
  11. package/.claude/vibe/rules/languages/typescript-nextjs.md +441 -0
  12. package/.claude/vibe/rules/languages/typescript-nuxt.md +521 -0
  13. package/.claude/vibe/rules/languages/typescript-react-native.md +446 -0
  14. package/.claude/vibe/rules/languages/typescript-react.md +525 -0
  15. package/.claude/vibe/rules/languages/typescript-vue.md +353 -0
  16. package/CLAUDE.md +0 -18
  17. package/hooks/hooks.json +18 -18
  18. package/package.json +1 -1
  19. package/hooks/scripts/code-quality-hook.mjs +0 -17
  20. package/hooks/scripts/complexity-hook.mjs +0 -17
  21. package/hooks/scripts/context-save-hook.mjs +0 -29
  22. package/hooks/scripts/gemini-code-hook.mjs +0 -28
  23. package/hooks/scripts/gemini-hook.mjs +0 -26
  24. package/hooks/scripts/gemini-uiux-hook.mjs +0 -28
  25. package/hooks/scripts/gpt-architect-hook.mjs +0 -28
  26. package/hooks/scripts/gpt-debug-hook.mjs +0 -28
  27. package/hooks/scripts/gpt-hook.mjs +0 -26
  28. package/hooks/scripts/memory-list-hook.mjs +0 -18
  29. package/hooks/scripts/memory-save-hook.mjs +0 -19
  30. package/hooks/scripts/post-tool-use-hook.mjs +0 -17
  31. package/hooks/scripts/session-start-hook.mjs +0 -26
@@ -0,0 +1,353 @@
1
+ # ๐ŸŸข TypeScript + Vue/Nuxt ํ’ˆ์งˆ ๊ทœ์น™
2
+
3
+ ## ํ•ต์‹ฌ ์›์น™ (core์—์„œ ์ƒ์†)
4
+
5
+ ```markdown
6
+ โœ… ๋‹จ์ผ ์ฑ…์ž„ (SRP)
7
+ โœ… ์ค‘๋ณต ์ œ๊ฑฐ (DRY)
8
+ โœ… ์žฌ์‚ฌ์šฉ์„ฑ
9
+ โœ… ๋‚ฎ์€ ๋ณต์žก๋„
10
+ โœ… ํ•จ์ˆ˜ โ‰ค 30์ค„, Template โ‰ค 100์ค„
11
+ โœ… ์ค‘์ฒฉ โ‰ค 3๋‹จ๊ณ„
12
+ โœ… Cyclomatic complexity โ‰ค 10
13
+ ```
14
+
15
+ ## Vue 3 + TypeScript ํŠนํ™” ๊ทœ์น™
16
+
17
+ ### 1. Composition API ์‚ฌ์šฉ (Options API ์ง€์–‘)
18
+
19
+ ```typescript
20
+ // โŒ Options API (๋ ˆ๊ฑฐ์‹œ)
21
+ export default {
22
+ data() {
23
+ return { count: 0 };
24
+ },
25
+ methods: {
26
+ increment() {
27
+ this.count++;
28
+ }
29
+ }
30
+ };
31
+
32
+ // โœ… Composition API + script setup
33
+ <script setup lang="ts">
34
+ import { ref, computed, onMounted } from 'vue';
35
+
36
+ const count = ref(0);
37
+ const doubled = computed(() => count.value * 2);
38
+
39
+ function increment() {
40
+ count.value++;
41
+ }
42
+
43
+ onMounted(() => {
44
+ console.log('์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ๋จ');
45
+ });
46
+ </script>
47
+ ```
48
+
49
+ ### 2. ํƒ€์ž… ์•ˆ์ „ํ•œ Props/Emits
50
+
51
+ ```typescript
52
+ // โœ… Props ํƒ€์ž… ์ •์˜
53
+ interface Props {
54
+ userId: string;
55
+ title?: string;
56
+ items: Item[];
57
+ }
58
+
59
+ const props = withDefaults(defineProps<Props>(), {
60
+ title: '๊ธฐ๋ณธ ์ œ๋ชฉ',
61
+ });
62
+
63
+ // โœ… Emits ํƒ€์ž… ์ •์˜
64
+ interface Emits {
65
+ (e: 'update', value: string): void;
66
+ (e: 'delete', id: number): void;
67
+ (e: 'select', item: Item): void;
68
+ }
69
+
70
+ const emit = defineEmits<Emits>();
71
+
72
+ // ์‚ฌ์šฉ
73
+ emit('update', '์ƒˆ ๊ฐ’');
74
+ emit('delete', 123);
75
+ ```
76
+
77
+ ### 3. Composables๋กœ ๋กœ์ง ๋ถ„๋ฆฌ
78
+
79
+ ```typescript
80
+ // โœ… composables/useUser.ts
81
+ import { ref, computed } from 'vue';
82
+ import type { User } from '@/types';
83
+
84
+ export function useUser(userId: string) {
85
+ const user = ref<User | null>(null);
86
+ const isLoading = ref(false);
87
+ const error = ref<string | null>(null);
88
+
89
+ const fullName = computed(() =>
90
+ user.value ? `${user.value.firstName} ${user.value.lastName}` : ''
91
+ );
92
+
93
+ async function fetchUser() {
94
+ isLoading.value = true;
95
+ error.value = null;
96
+ try {
97
+ const response = await api.getUser(userId);
98
+ user.value = response.data;
99
+ } catch (e) {
100
+ error.value = '์‚ฌ์šฉ์ž๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค';
101
+ } finally {
102
+ isLoading.value = false;
103
+ }
104
+ }
105
+
106
+ return {
107
+ user,
108
+ isLoading,
109
+ error,
110
+ fullName,
111
+ fetchUser,
112
+ };
113
+ }
114
+
115
+ // ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ
116
+ <script setup lang="ts">
117
+ const { user, isLoading, fetchUser } = useUser(props.userId);
118
+
119
+ onMounted(fetchUser);
120
+ </script>
121
+ ```
122
+
123
+ ### 4. Pinia ์ƒํƒœ ๊ด€๋ฆฌ
124
+
125
+ ```typescript
126
+ // โœ… stores/user.ts
127
+ import { defineStore } from 'pinia';
128
+ import type { User } from '@/types';
129
+
130
+ interface UserState {
131
+ currentUser: User | null;
132
+ users: User[];
133
+ isLoading: boolean;
134
+ }
135
+
136
+ export const useUserStore = defineStore('user', {
137
+ state: (): UserState => ({
138
+ currentUser: null,
139
+ users: [],
140
+ isLoading: false,
141
+ }),
142
+
143
+ getters: {
144
+ isLoggedIn: (state) => !!state.currentUser,
145
+ userCount: (state) => state.users.length,
146
+ },
147
+
148
+ actions: {
149
+ async login(email: string, password: string) {
150
+ this.isLoading = true;
151
+ try {
152
+ const user = await authApi.login(email, password);
153
+ this.currentUser = user;
154
+ } finally {
155
+ this.isLoading = false;
156
+ }
157
+ },
158
+
159
+ logout() {
160
+ this.currentUser = null;
161
+ },
162
+ },
163
+ });
164
+
165
+ // Setup Store ์Šคํƒ€์ผ (๊ถŒ์žฅ)
166
+ export const useUserStore = defineStore('user', () => {
167
+ const currentUser = ref<User | null>(null);
168
+ const isLoggedIn = computed(() => !!currentUser.value);
169
+
170
+ async function login(email: string, password: string) {
171
+ currentUser.value = await authApi.login(email, password);
172
+ }
173
+
174
+ return { currentUser, isLoggedIn, login };
175
+ });
176
+ ```
177
+
178
+ ### 5. Nuxt 3 ํŠนํ™” ๊ทœ์น™
179
+
180
+ ```typescript
181
+ // โœ… Server API Routes (server/api/)
182
+ // server/api/users/[id].get.ts
183
+ export default defineEventHandler(async (event) => {
184
+ const id = getRouterParam(event, 'id');
185
+
186
+ if (!id) {
187
+ throw createError({
188
+ statusCode: 400,
189
+ message: 'ID๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค',
190
+ });
191
+ }
192
+
193
+ const user = await prisma.user.findUnique({ where: { id } });
194
+
195
+ if (!user) {
196
+ throw createError({
197
+ statusCode: 404,
198
+ message: '์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค',
199
+ });
200
+ }
201
+
202
+ return user;
203
+ });
204
+
205
+ // โœ… useFetch / useAsyncData
206
+ <script setup lang="ts">
207
+ // SSR ์ง€์› ๋ฐ์ดํ„ฐ ํŽ˜์นญ
208
+ const { data: user, pending, error } = await useFetch<User>(
209
+ `/api/users/${props.userId}`
210
+ );
211
+
212
+ // ์บ์‹ฑ ํ‚ค ์ง€์ •
213
+ const { data: posts } = await useAsyncData(
214
+ `user-${props.userId}-posts`,
215
+ () => $fetch(`/api/users/${props.userId}/posts`)
216
+ );
217
+ </script>
218
+
219
+ // โœ… Middleware
220
+ // middleware/auth.ts
221
+ export default defineNuxtRouteMiddleware((to, from) => {
222
+ const { isLoggedIn } = useUserStore();
223
+
224
+ if (!isLoggedIn && to.path !== '/login') {
225
+ return navigateTo('/login');
226
+ }
227
+ });
228
+ ```
229
+
230
+ ### 6. ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ
231
+
232
+ ```vue
233
+ <!-- โœ… ๊ถŒ์žฅ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ -->
234
+ <script setup lang="ts">
235
+ // 1. ํƒ€์ž… import
236
+ import type { User, Item } from '@/types';
237
+
238
+ // 2. ์ปดํฌ๋„ŒํŠธ import
239
+ import UserAvatar from '@/components/UserAvatar.vue';
240
+
241
+ // 3. Props/Emits
242
+ interface Props {
243
+ user: User;
244
+ editable?: boolean;
245
+ }
246
+
247
+ const props = withDefaults(defineProps<Props>(), {
248
+ editable: false,
249
+ });
250
+
251
+ const emit = defineEmits<{
252
+ (e: 'update', user: User): void;
253
+ }>();
254
+
255
+ // 4. Composables
256
+ const { isLoading, save } = useUserForm();
257
+
258
+ // 5. Reactive state
259
+ const formData = ref({ ...props.user });
260
+ const isEditing = ref(false);
261
+
262
+ // 6. Computed
263
+ const canSave = computed(() =>
264
+ formData.value.name.length > 0 && !isLoading.value
265
+ );
266
+
267
+ // 7. Methods
268
+ async function handleSave() {
269
+ await save(formData.value);
270
+ emit('update', formData.value);
271
+ }
272
+
273
+ // 8. Lifecycle
274
+ onMounted(() => {
275
+ console.log('์ปดํฌ๋„ŒํŠธ ์ค€๋น„๋จ');
276
+ });
277
+ </script>
278
+
279
+ <template>
280
+ <div class="user-card">
281
+ <UserAvatar :src="user.avatar" />
282
+ <h2>{{ user.name }}</h2>
283
+ <button
284
+ v-if="editable"
285
+ :disabled="!canSave"
286
+ @click="handleSave"
287
+ >
288
+ ์ €์žฅ
289
+ </button>
290
+ </div>
291
+ </template>
292
+
293
+ <style scoped>
294
+ .user-card {
295
+ padding: 1rem;
296
+ border-radius: 8px;
297
+ }
298
+ </style>
299
+ ```
300
+
301
+ ## ์•ˆํ‹ฐํŒจํ„ด
302
+
303
+ ```typescript
304
+ // โŒ v-if์™€ v-for ํ•จ๊ป˜ ์‚ฌ์šฉ
305
+ <li v-for="user in users" v-if="user.isActive">
306
+
307
+ // โœ… computed๋กœ ํ•„ํ„ฐ๋ง
308
+ const activeUsers = computed(() => users.value.filter(u => u.isActive));
309
+ <li v-for="user in activeUsers">
310
+
311
+ // โŒ Props ์ง์ ‘ ์ˆ˜์ •
312
+ props.user.name = '์ƒˆ ์ด๋ฆ„';
313
+
314
+ // โœ… emit์œผ๋กœ ๋ถ€๋ชจ์—๊ฒŒ ์•Œ๋ฆผ
315
+ emit('update', { ...props.user, name: '์ƒˆ ์ด๋ฆ„' });
316
+
317
+ // โŒ $refs ๋‚จ์šฉ
318
+ this.$refs.input.focus();
319
+
320
+ // โœ… template ref + expose
321
+ const inputRef = ref<HTMLInputElement>();
322
+ defineExpose({ focus: () => inputRef.value?.focus() });
323
+ ```
324
+
325
+ ## ํŒŒ์ผ ๊ตฌ์กฐ (Nuxt 3)
326
+
327
+ ```
328
+ project/
329
+ โ”œโ”€โ”€ components/
330
+ โ”‚ โ”œโ”€โ”€ ui/ # ๊ธฐ๋ณธ UI ์ปดํฌ๋„ŒํŠธ
331
+ โ”‚ โ”œโ”€โ”€ features/ # ๊ธฐ๋Šฅ๋ณ„ ์ปดํฌ๋„ŒํŠธ
332
+ โ”‚ โ””โ”€โ”€ layouts/ # ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ
333
+ โ”œโ”€โ”€ composables/ # Composition ํ•จ์ˆ˜
334
+ โ”œโ”€โ”€ stores/ # Pinia ์Šคํ† ์–ด
335
+ โ”œโ”€โ”€ server/
336
+ โ”‚ โ”œโ”€โ”€ api/ # API ๋ผ์šฐํŠธ
337
+ โ”‚ โ”œโ”€โ”€ middleware/ # ์„œ๋ฒ„ ๋ฏธ๋“ค์›จ์–ด
338
+ โ”‚ โ””โ”€โ”€ utils/ # ์„œ๋ฒ„ ์œ ํ‹ธ๋ฆฌํ‹ฐ
339
+ โ”œโ”€โ”€ pages/ # ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…
340
+ โ”œโ”€โ”€ middleware/ # ํด๋ผ์ด์–ธํŠธ ๋ฏธ๋“ค์›จ์–ด
341
+ โ”œโ”€โ”€ types/ # TypeScript ํƒ€์ž…
342
+ โ””โ”€โ”€ utils/ # ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
343
+ ```
344
+
345
+ ## ์ฒดํฌ๋ฆฌ์ŠคํŠธ
346
+
347
+ - [ ] Composition API + `<script setup>` ์‚ฌ์šฉ
348
+ - [ ] Props/Emits ํƒ€์ž… ์ •์˜
349
+ - [ ] Composables๋กœ ๋กœ์ง ๋ถ„๋ฆฌ
350
+ - [ ] Pinia Setup Store ์Šคํƒ€์ผ ์‚ฌ์šฉ
351
+ - [ ] `any` ํƒ€์ž… ์‚ฌ์šฉ ๊ธˆ์ง€
352
+ - [ ] v-if/v-for ๋ถ„๋ฆฌ
353
+ - [ ] scoped ์Šคํƒ€์ผ ์‚ฌ์šฉ
package/CLAUDE.md CHANGED
@@ -25,24 +25,6 @@ SPEC ์ฃผ๋„ AI ์ฝ”๋”ฉ ํ”„๋ ˆ์ž„์›Œํฌ (Claude Code ์ „์šฉ)
25
25
  - `@ts-ignore` ๊ธˆ์ง€ โ†’ ํƒ€์ž… ๋ฌธ์ œ ๊ทผ๋ณธ ํ•ด๊ฒฐ
26
26
  - ๋ชจ๋“  ํ•จ์ˆ˜์— ๋ฐ˜ํ™˜ ํƒ€์ž… ๋ช…์‹œ
27
27
 
28
- ### TypeScript ๊ทœ์น™
29
- - `any` ํƒ€์ž… ์‚ฌ์šฉ ๊ธˆ์ง€ โ†’ `unknown` + ํƒ€์ž… ๊ฐ€๋“œ ์‚ฌ์šฉ
30
- - `as any` ์บ์ŠคํŒ… ๊ธˆ์ง€ โ†’ ์ ์ ˆํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
31
- - `@ts-ignore` ๊ธˆ์ง€ โ†’ ํƒ€์ž… ๋ฌธ์ œ ๊ทผ๋ณธ ํ•ด๊ฒฐ
32
- - ๋ชจ๋“  ํ•จ์ˆ˜์— ๋ฐ˜ํ™˜ ํƒ€์ž… ๋ช…์‹œ
33
-
34
- ### TypeScript ๊ทœ์น™
35
- - `any` ํƒ€์ž… ์‚ฌ์šฉ ๊ธˆ์ง€ โ†’ `unknown` + ํƒ€์ž… ๊ฐ€๋“œ ์‚ฌ์šฉ
36
- - `as any` ์บ์ŠคํŒ… ๊ธˆ์ง€ โ†’ ์ ์ ˆํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
37
- - `@ts-ignore` ๊ธˆ์ง€ โ†’ ํƒ€์ž… ๋ฌธ์ œ ๊ทผ๋ณธ ํ•ด๊ฒฐ
38
- - ๋ชจ๋“  ํ•จ์ˆ˜์— ๋ฐ˜ํ™˜ ํƒ€์ž… ๋ช…์‹œ
39
-
40
- ### TypeScript ๊ทœ์น™
41
- - `any` ํƒ€์ž… ์‚ฌ์šฉ ๊ธˆ์ง€ โ†’ `unknown` + ํƒ€์ž… ๊ฐ€๋“œ ์‚ฌ์šฉ
42
- - `as any` ์บ์ŠคํŒ… ๊ธˆ์ง€ โ†’ ์ ์ ˆํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
43
- - `@ts-ignore` ๊ธˆ์ง€ โ†’ ํƒ€์ž… ๋ฌธ์ œ ๊ทผ๋ณธ ํ•ด๊ฒฐ
44
- - ๋ชจ๋“  ํ•จ์ˆ˜์— ๋ฐ˜ํ™˜ ํƒ€์ž… ๋ช…์‹œ
45
-
46
28
  ### ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ•„์ˆ˜
47
29
  - try-catch ๋˜๋Š” error state ํ•„์ˆ˜
48
30
  - ๋กœ๋”ฉ ์ƒํƒœ ์ฒ˜๋ฆฌ
package/hooks/hooks.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "hooks": [
11
11
  {
12
12
  "type": "command",
13
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/session-start-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
13
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/';const p='$CLAUDE_PROJECT_DIR';Promise.all([import(B+'memory/index.js').then(t=>t.startSession({projectPath:p})),import(B+'time/index.js').then(t=>t.getCurrentTime({format:'human',timezone:'Asia/Seoul'})),import(B+'memory/index.js').then(t=>t.listMemories({limit:5,projectPath:p}))]).then(([s,t,m])=>console.log(s.content[0].text+'\\n\\n'+t.content[0].text+'\\n\\n[Recent Memories]\\n'+m.content[0].text)).catch(e=>console.log('[Session] Error:',e.message))\""
14
14
  }
15
15
  ]
16
16
  }
@@ -32,7 +32,7 @@
32
32
  "hooks": [
33
33
  {
34
34
  "type": "command",
35
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/post-tool-use-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
35
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/convention/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.validateCodeQuality({targetPath:'.',projectPath:p}).then(r=>console.log('[CODE CHECK]',r.content[0].text.split('\\n').slice(0,3).join(' | ')))).catch(()=>console.log('[AUTO-CONTINUE] Code written. Continue.'))\""
36
36
  }
37
37
  ]
38
38
  }
@@ -61,7 +61,7 @@
61
61
  "hooks": [
62
62
  {
63
63
  "type": "command",
64
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/memory-save-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
64
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/memory/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.saveMemory({key:'solution-'+Date.now(),value:'Solution documented at '+new Date().toISOString(),category:'solution',projectPath:p}).then(r=>console.log('[COMPOUND]',r.content[0].text))).catch(e=>console.log('[COMPOUND] \\u2717 Error:',e.message))\""
65
65
  }
66
66
  ]
67
67
  },
@@ -70,7 +70,7 @@
70
70
  "hooks": [
71
71
  {
72
72
  "type": "command",
73
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/code-quality-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
73
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/convention/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.validateCodeQuality({targetPath:'.',projectPath:p}).then(r=>console.log('[CODE REVIEW]',r.content[0].text.split('\\n').slice(0,5).join(' | ')))).catch(e=>console.log('[CODE REVIEW] Error:',e.message))\""
74
74
  }
75
75
  ]
76
76
  },
@@ -88,7 +88,7 @@
88
88
  "hooks": [
89
89
  {
90
90
  "type": "command",
91
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/complexity-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
91
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/convention/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.analyzeComplexity({targetPath:'.',projectPath:p}).then(r=>console.log('[COMPLEXITY]',r.content[0].text.split('\\n').slice(0,5).join(' | ')))).catch(e=>console.log('[COMPLEXITY] Error:',e.message))\""
92
92
  }
93
93
  ]
94
94
  },
@@ -97,7 +97,7 @@
97
97
  "hooks": [
98
98
  {
99
99
  "type": "command",
100
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/memory-list-hook.mjs'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
100
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/memory/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.listMemories({limit:10,projectPath:p}).then(r=>console.log('[RECALL] \\u2713 Found '+r.content[0].text.split('\\n').length+' memories:',r.content[0].text.split('\\n').slice(0,7).join(' | ')))).catch(e=>console.log('[RECALL] Error:',e.message))\""
101
101
  }
102
102
  ]
103
103
  },
@@ -106,7 +106,7 @@
106
106
  "hooks": [
107
107
  {
108
108
  "type": "command",
109
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gpt-architect-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
109
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gpt-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt;import(V).then(g=>g.chat({messages:[{role:'user',content:q}],systemPrompt:'You are a software architect. Analyze and review the architecture.'})).then(r=>console.log('GPT-5.2 ์‘๋‹ต:',r.content)).catch(e=>console.log('[GPT] Error:',e.message))})\"",
110
110
  "statusMessage": "GPT analyzing architecture..."
111
111
  }
112
112
  ]
@@ -116,28 +116,28 @@
116
116
  "hooks": [
117
117
  {
118
118
  "type": "command",
119
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gemini-uiux-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
119
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gemini-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt;import(V).then(g=>g.chat({messages:[{role:'user',content:q}],systemPrompt:'You are a UI/UX expert. Analyze and provide feedback.'})).then(r=>console.log('Gemini-3 ์‘๋‹ต:',r.content)).catch(e=>console.log('[Gemini] Error:',e.message))})\"",
120
120
  "statusMessage": "Gemini reviewing UI/UX..."
121
121
  }
122
122
  ]
123
123
  },
124
124
  {
125
- "matcher": "[Gg][Pp][Tt]",
125
+ "matcher": "(?!.*gemini)(gpt\\s*ํ•œํ…Œ|gpt\\s*์—๊ฒŒ|gpt์—\\s*๋ฌผ์–ด|gpt.*์งˆ๋ฌธ|ask\\s*gpt)",
126
126
  "hooks": [
127
127
  {
128
128
  "type": "command",
129
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gpt-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
129
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gpt-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt.replace(/gpt.*?(๋ฌผ์–ด|์งˆ๋ฌธ|ํ•œํ…Œ|๋ถ„์„)[^๊ฐ€-ํžฃ]*/i,'').trim();import(V).then(g=>g.quickAsk(q)).then(r=>console.log('GPT-5.2 ์‘๋‹ต:',r)).catch(e=>console.log('[GPT] Error:',e.message))})\"",
130
130
  "statusMessage": "Asking GPT-5.2..."
131
131
  }
132
132
  ]
133
133
  },
134
134
  {
135
- "matcher": "[Gg][Ee][Mm][Ii][Nn][Ii]|์ œ๋ฏธ๋‚˜์ด",
135
+ "matcher": "(?!.*gpt)(gemini\\s*ํ•œํ…Œ|gemini\\s*์—๊ฒŒ|gemini์—\\s*๋ฌผ์–ด|gemini.*์งˆ๋ฌธ|ask\\s*gemini|์ œ๋ฏธ๋‚˜์ด)",
136
136
  "hooks": [
137
137
  {
138
138
  "type": "command",
139
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gemini-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
140
- "statusMessage": "Asking Gemini-3..."
139
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gemini-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt.replace(/(gemini|์ œ๋ฏธ๋‚˜์ด).*?(๋ฌผ์–ด|์งˆ๋ฌธ|ํ•œํ…Œ|๋ถ„์„)[^๊ฐ€-ํžฃ]*/i,'').trim();import(V).then(g=>g.quickAsk(q)).then(r=>console.log('Gemini-3 ์‘๋‹ต:',r)).catch(e=>console.log('[Gemini] Error:',e.message))})\"",
140
+ "statusMessage": "Asking Gemini 3..."
141
141
  }
142
142
  ]
143
143
  },
@@ -146,7 +146,7 @@
146
146
  "hooks": [
147
147
  {
148
148
  "type": "command",
149
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gpt-debug-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
149
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gpt-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt;import(V).then(g=>g.chat({messages:[{role:'user',content:q}],systemPrompt:'You are a debugging expert. Find bugs and suggest fixes.'})).then(r=>console.log('GPT-5.2 ์‘๋‹ต:',r.content)).catch(e=>console.log('[GPT] Error:',e.message))})\"",
150
150
  "statusMessage": "GPT debugging..."
151
151
  }
152
152
  ]
@@ -156,7 +156,7 @@
156
156
  "hooks": [
157
157
  {
158
158
  "type": "command",
159
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();const p=spawn('node',[r+'/@su-record/vibe/hooks/scripts/gemini-code-hook.mjs'],{stdio:['pipe','inherit','inherit']});process.stdin.pipe(p.stdin);p.on('close',c=>process.exit(c))\"",
159
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const V='file:///'+R+'/@su-record/vibe/dist/lib/gemini-api.js';let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const q=JSON.parse(d).prompt;import(V).then(g=>g.chat({messages:[{role:'user',content:q}],systemPrompt:'You are a code analysis expert. Review and analyze the code.'})).then(r=>console.log('Gemini-3 ์‘๋‹ต:',r.content)).catch(e=>console.log('[Gemini] Error:',e.message))})\"",
160
160
  "statusMessage": "Gemini analyzing code..."
161
161
  }
162
162
  ]
@@ -168,7 +168,7 @@
168
168
  "hooks": [
169
169
  {
170
170
  "type": "command",
171
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/context-save-hook.mjs','80'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
171
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/memory/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.autoSaveContext({urgency:'medium',contextType:'progress',summary:'Context at 80% - auto checkpoint',projectPath:p}).then(r=>console.log('[CONTEXT 80%]',r.content[0].text))).catch(()=>{})\""
172
172
  }
173
173
  ]
174
174
  },
@@ -177,7 +177,7 @@
177
177
  "hooks": [
178
178
  {
179
179
  "type": "command",
180
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/context-save-hook.mjs','90'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
180
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/memory/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.autoSaveContext({urgency:'high',contextType:'progress',summary:'Context at 90% - save before overflow',projectPath:p}).then(r=>console.log('[CONTEXT 90%]',r.content[0].text))).catch(()=>{})\""
181
181
  }
182
182
  ]
183
183
  },
@@ -186,7 +186,7 @@
186
186
  "hooks": [
187
187
  {
188
188
  "type": "command",
189
- "command": "node -e \"const {execSync,spawn}=require('child_process');const r=execSync('npm root -g',{encoding:'utf-8'}).trim();spawn('node',[r+'/@su-record/vibe/hooks/scripts/context-save-hook.mjs','95'],{stdio:'inherit'}).on('close',c=>process.exit(c))\""
189
+ "command": "node -e \"const{execSync:X}=require('child_process');const R=process.platform==='win32'?process.env.APPDATA.replace(/\\\\/g,'/')+'/npm/node_modules':X('npm root -g').toString().trim();const B='file:///'+R+'/@su-record/vibe/dist/tools/memory/index.js';const p='$CLAUDE_PROJECT_DIR';import(B).then(t=>t.autoSaveContext({urgency:'critical',contextType:'progress',summary:'Context at 95% - CRITICAL save before session end',projectPath:p}).then(r=>console.log('[CONTEXT 95%]',r.content[0].text))).catch(()=>{})\""
190
190
  }
191
191
  ]
192
192
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "2.4.24",
3
+ "version": "2.4.26",
4
4
  "description": "Vibe - Claude Code exclusive SPEC-driven AI coding framework with 35+ integrated tools",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env node
2
- import { fileURLToPath } from "url";
3
- import { dirname, resolve } from "path";
4
-
5
- const __dirname = dirname(fileURLToPath(import.meta.url));
6
- const m = await import("file://" + resolve(__dirname, "../../dist/tools/convention/index.js"));
7
-
8
- try {
9
- const projectPath = process.env.CLAUDE_PROJECT_DIR || process.cwd();
10
- const r = await m.validateCodeQuality({
11
- targetPath: ".",
12
- projectPath
13
- });
14
- console.log("[CODE REVIEW]", r.content[0].text.split("\n").slice(0, 5).join(" | "));
15
- } catch (e) {
16
- console.log("[CODE REVIEW] Error:", e.message);
17
- }
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env node
2
- import { fileURLToPath } from "url";
3
- import { dirname, resolve } from "path";
4
-
5
- const __dirname = dirname(fileURLToPath(import.meta.url));
6
- const m = await import("file://" + resolve(__dirname, "../../dist/tools/convention/index.js"));
7
-
8
- try {
9
- const projectPath = process.env.CLAUDE_PROJECT_DIR || process.cwd();
10
- const r = await m.analyzeComplexity({
11
- targetPath: ".",
12
- projectPath
13
- });
14
- console.log("[COMPLEXITY]", r.content[0].text.split("\n").slice(0, 5).join(" | "));
15
- } catch (e) {
16
- console.log("[COMPLEXITY] Error:", e.message);
17
- }
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
- import { fileURLToPath } from "url";
3
- import { dirname, resolve } from "path";
4
-
5
- const __dirname = dirname(fileURLToPath(import.meta.url));
6
- const m = await import("file://" + resolve(__dirname, "../../dist/tools/memory/index.js"));
7
-
8
- // Get urgency from args: node context-save-hook.mjs 80|90|95
9
- const urgencyLevel = process.argv[2] || "80";
10
- const urgencyMap = {
11
- "80": { urgency: "medium", summary: "Context at 80% - auto checkpoint" },
12
- "90": { urgency: "high", summary: "Context at 90% - save before overflow" },
13
- "95": { urgency: "critical", summary: "Context at 95% - CRITICAL save before session end" }
14
- };
15
-
16
- const config = urgencyMap[urgencyLevel] || urgencyMap["80"];
17
-
18
- try {
19
- const projectPath = process.env.CLAUDE_PROJECT_DIR || process.cwd();
20
- const r = await m.autoSaveContext({
21
- urgency: config.urgency,
22
- contextType: "progress",
23
- summary: config.summary,
24
- projectPath
25
- });
26
- console.log(`[CONTEXT ${urgencyLevel}%]`, r.content[0].text);
27
- } catch (e) {
28
- // Silent fail for context save
29
- }
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env node
2
- import { fileURLToPath } from "url";
3
- import { dirname, resolve } from "path";
4
-
5
- // Read stdin
6
- let data = "";
7
- for await (const chunk of process.stdin) {
8
- data += chunk;
9
- }
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- const m = await import("file://" + resolve(__dirname, "../../dist/lib/gemini-api.js"));
13
-
14
- try {
15
- const json = JSON.parse(data || "{}");
16
- const prompt = json.prompt || "";
17
- if (prompt) {
18
- const r = await m.chat({
19
- messages: [{role: "user", content: prompt}],
20
- systemPrompt: "You are a code analysis expert. Review and analyze the code."
21
- });
22
- console.log("Gemini-3 ์‘๋‹ต:", r.content);
23
- } else {
24
- console.log("[Gemini] No prompt");
25
- }
26
- } catch (e) {
27
- console.log("[Gemini] Error:", e.message);
28
- }