@su-record/vibe 2.4.56 → 2.4.58

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 (44) hide show
  1. package/CLAUDE.md +7 -18
  2. package/agents/compounder.md +1 -1
  3. package/agents/implementer.md +2 -1
  4. package/agents/simplifier.md +2 -1
  5. package/commands/vibe.run.md +4 -1
  6. package/commands/vibe.spec.md +56 -3
  7. package/dist/cli/index.d.ts.map +1 -1
  8. package/dist/cli/index.js +0 -4
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/postinstall.js +32 -1
  11. package/dist/cli/postinstall.js.map +1 -1
  12. package/dist/cli/setup.d.ts +18 -4
  13. package/dist/cli/setup.d.ts.map +1 -1
  14. package/dist/cli/setup.js +107 -27
  15. package/dist/cli/setup.js.map +1 -1
  16. package/dist/cli/types.d.ts +6 -0
  17. package/dist/cli/types.d.ts.map +1 -1
  18. package/languages/csharp-unity.md +516 -0
  19. package/languages/gdscript-godot.md +470 -0
  20. package/languages/ruby-rails.md +489 -0
  21. package/languages/typescript-angular.md +433 -0
  22. package/languages/typescript-astro.md +416 -0
  23. package/languages/typescript-electron.md +407 -0
  24. package/languages/typescript-nestjs.md +524 -0
  25. package/languages/typescript-svelte.md +407 -0
  26. package/languages/typescript-tauri.md +366 -0
  27. package/package.json +1 -1
  28. package/skills/vibe-capabilities.md +1 -1
  29. package/vibe/constitution.md +130 -97
  30. package/vibe/rules/core/communication-guide.md +50 -56
  31. package/vibe/rules/core/development-philosophy.md +35 -36
  32. package/vibe/rules/core/quick-start.md +66 -85
  33. package/vibe/rules/quality/bdd-contract-testing.md +94 -89
  34. package/vibe/rules/quality/checklist.md +132 -132
  35. package/vibe/rules/quality/testing-strategy.md +132 -129
  36. package/vibe/rules/standards/anti-patterns.md +74 -74
  37. package/vibe/rules/standards/code-structure.md +44 -44
  38. package/vibe/rules/standards/complexity-metrics.md +63 -62
  39. package/vibe/rules/standards/naming-conventions.md +72 -72
  40. package/vibe/templates/constitution-template.md +153 -95
  41. package/vibe/templates/contract-backend-template.md +41 -32
  42. package/vibe/templates/contract-frontend-template.md +35 -30
  43. package/vibe/templates/feature-template.md +33 -33
  44. package/vibe/templates/spec-template.md +118 -96
@@ -0,0 +1,407 @@
1
+ # ⚡ TypeScript + Electron 품질 규칙
2
+
3
+ ## 핵심 원칙 (core에서 상속)
4
+
5
+ ```markdown
6
+ ✅ 단일 책임 (SRP)
7
+ ✅ 중복 제거 (DRY)
8
+ ✅ 재사용성
9
+ ✅ 낮은 복잡도
10
+ ✅ 함수 ≤ 30줄
11
+ ✅ 중첩 ≤ 3단계
12
+ ✅ Cyclomatic complexity ≤ 10
13
+ ```
14
+
15
+ ## Electron 아키텍처 이해
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────────┐
19
+ │ Main Process (Node.js) │
20
+ │ - 앱 생명주기 관리 │
21
+ │ - 시스템 API (파일, 네트워크) │
22
+ │ - BrowserWindow 생성/관리 │
23
+ ├─────────────────────────────────────────────┤
24
+ │ Preload Script (격리된 컨텍스트) │
25
+ │ - contextBridge로 API 노출 │
26
+ │ - Main ↔ Renderer 브릿지 │
27
+ ├─────────────────────────────────────────────┤
28
+ │ Renderer Process (Chromium) │
29
+ │ - UI 렌더링 (React/Vue/etc) │
30
+ │ - window.electronAPI 사용 │
31
+ └─────────────────────────────────────────────┘
32
+ ```
33
+
34
+ ## TypeScript/Electron 특화 규칙
35
+
36
+ ### 1. 프로세스 분리 필수
37
+
38
+ ```typescript
39
+ // ❌ Renderer에서 직접 Node.js 사용 (보안 취약)
40
+ // nodeIntegration: true 금지!
41
+
42
+ // ✅ Main Process (main.ts)
43
+ import { app, BrowserWindow, ipcMain } from 'electron';
44
+ import path from 'path';
45
+
46
+ function createWindow(): BrowserWindow {
47
+ const win = new BrowserWindow({
48
+ width: 800,
49
+ height: 600,
50
+ webPreferences: {
51
+ preload: path.join(__dirname, 'preload.js'),
52
+ contextIsolation: true, // 필수!
53
+ nodeIntegration: false, // 필수!
54
+ sandbox: true // 권장
55
+ }
56
+ });
57
+
58
+ win.loadFile('index.html');
59
+ return win;
60
+ }
61
+
62
+ app.whenReady().then(createWindow);
63
+ ```
64
+
65
+ ### 2. Preload Script 패턴
66
+
67
+ ```typescript
68
+ // preload.ts
69
+ import { contextBridge, ipcRenderer } from 'electron';
70
+
71
+ // ✅ 타입 정의
72
+ interface ElectronAPI {
73
+ readFile: (path: string) => Promise<string>;
74
+ writeFile: (path: string, content: string) => Promise<void>;
75
+ onFileChanged: (callback: (path: string) => void) => () => void;
76
+ platform: NodeJS.Platform;
77
+ }
78
+
79
+ // ✅ 안전하게 API 노출
80
+ contextBridge.exposeInMainWorld('electronAPI', {
81
+ readFile: (path: string) => ipcRenderer.invoke('read-file', path),
82
+ writeFile: (path: string, content: string) =>
83
+ ipcRenderer.invoke('write-file', path, content),
84
+ onFileChanged: (callback: (path: string) => void) => {
85
+ const handler = (_event: Electron.IpcRendererEvent, path: string) => callback(path);
86
+ ipcRenderer.on('file-changed', handler);
87
+ return () => ipcRenderer.removeListener('file-changed', handler);
88
+ },
89
+ platform: process.platform
90
+ } satisfies ElectronAPI);
91
+
92
+ // ✅ 타입 선언 (renderer에서 사용)
93
+ declare global {
94
+ interface Window {
95
+ electronAPI: ElectronAPI;
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### 3. IPC 통신 타입 안전성
101
+
102
+ ```typescript
103
+ // shared/ipc-types.ts
104
+ export interface IpcChannels {
105
+ 'read-file': { args: [string]; return: string };
106
+ 'write-file': { args: [string, string]; return: void };
107
+ 'get-app-info': { args: []; return: AppInfo };
108
+ }
109
+
110
+ export interface AppInfo {
111
+ version: string;
112
+ name: string;
113
+ paths: {
114
+ userData: string;
115
+ temp: string;
116
+ };
117
+ }
118
+
119
+ // main.ts
120
+ import { ipcMain } from 'electron';
121
+ import fs from 'fs/promises';
122
+
123
+ // ✅ 타입 안전한 핸들러
124
+ ipcMain.handle('read-file', async (_event, path: string): Promise<string> => {
125
+ return fs.readFile(path, 'utf-8');
126
+ });
127
+
128
+ ipcMain.handle('write-file', async (_event, path: string, content: string): Promise<void> => {
129
+ await fs.writeFile(path, content, 'utf-8');
130
+ });
131
+
132
+ ipcMain.handle('get-app-info', async (): Promise<AppInfo> => {
133
+ return {
134
+ version: app.getVersion(),
135
+ name: app.getName(),
136
+ paths: {
137
+ userData: app.getPath('userData'),
138
+ temp: app.getPath('temp')
139
+ }
140
+ };
141
+ });
142
+ ```
143
+
144
+ ### 4. Renderer에서 IPC 사용
145
+
146
+ ```typescript
147
+ // renderer/hooks/useElectron.ts
148
+
149
+ // ✅ Custom Hook
150
+ function useFileReader() {
151
+ const [content, setContent] = useState<string | null>(null);
152
+ const [loading, setLoading] = useState(false);
153
+ const [error, setError] = useState<string | null>(null);
154
+
155
+ const readFile = useCallback(async (path: string) => {
156
+ setLoading(true);
157
+ setError(null);
158
+ try {
159
+ const result = await window.electronAPI.readFile(path);
160
+ setContent(result);
161
+ return result;
162
+ } catch (e) {
163
+ const msg = e instanceof Error ? e.message : 'Unknown error';
164
+ setError(msg);
165
+ throw e;
166
+ } finally {
167
+ setLoading(false);
168
+ }
169
+ }, []);
170
+
171
+ return { content, loading, error, readFile };
172
+ }
173
+
174
+ // ✅ 이벤트 구독 Hook
175
+ function useFileWatcher(onChanged: (path: string) => void) {
176
+ useEffect(() => {
177
+ const unsubscribe = window.electronAPI.onFileChanged(onChanged);
178
+ return unsubscribe;
179
+ }, [onChanged]);
180
+ }
181
+ ```
182
+
183
+ ### 5. 창 관리
184
+
185
+ ```typescript
186
+ // main.ts
187
+ import { BrowserWindow, screen } from 'electron';
188
+
189
+ // ✅ 창 상태 저장/복원
190
+ interface WindowState {
191
+ x?: number;
192
+ y?: number;
193
+ width: number;
194
+ height: number;
195
+ isMaximized: boolean;
196
+ }
197
+
198
+ function createWindowWithState(): BrowserWindow {
199
+ const state = loadWindowState();
200
+
201
+ const win = new BrowserWindow({
202
+ x: state.x,
203
+ y: state.y,
204
+ width: state.width,
205
+ height: state.height,
206
+ webPreferences: {
207
+ preload: path.join(__dirname, 'preload.js'),
208
+ contextIsolation: true,
209
+ nodeIntegration: false
210
+ }
211
+ });
212
+
213
+ if (state.isMaximized) {
214
+ win.maximize();
215
+ }
216
+
217
+ // 상태 변경 시 저장
218
+ win.on('close', () => {
219
+ saveWindowState({
220
+ ...win.getBounds(),
221
+ isMaximized: win.isMaximized()
222
+ });
223
+ });
224
+
225
+ return win;
226
+ }
227
+
228
+ // ✅ 다중 창 관리
229
+ const windows = new Map<string, BrowserWindow>();
230
+
231
+ function getOrCreateWindow(id: string): BrowserWindow {
232
+ const existing = windows.get(id);
233
+ if (existing && !existing.isDestroyed()) {
234
+ existing.focus();
235
+ return existing;
236
+ }
237
+
238
+ const win = new BrowserWindow({ /* ... */ });
239
+ windows.set(id, win);
240
+ win.on('closed', () => windows.delete(id));
241
+ return win;
242
+ }
243
+ ```
244
+
245
+ ### 6. 메뉴 구성
246
+
247
+ ```typescript
248
+ import { Menu, MenuItemConstructorOptions } from 'electron';
249
+
250
+ // ✅ 플랫폼별 메뉴
251
+ function createMenu(): Menu {
252
+ const isMac = process.platform === 'darwin';
253
+
254
+ const template: MenuItemConstructorOptions[] = [
255
+ ...(isMac ? [{
256
+ label: app.name,
257
+ submenu: [
258
+ { role: 'about' as const },
259
+ { type: 'separator' as const },
260
+ { role: 'quit' as const }
261
+ ]
262
+ }] : []),
263
+ {
264
+ label: 'File',
265
+ submenu: [
266
+ {
267
+ label: 'Open',
268
+ accelerator: 'CmdOrCtrl+O',
269
+ click: () => handleOpen()
270
+ },
271
+ {
272
+ label: 'Save',
273
+ accelerator: 'CmdOrCtrl+S',
274
+ click: () => handleSave()
275
+ },
276
+ { type: 'separator' },
277
+ isMac ? { role: 'close' } : { role: 'quit' }
278
+ ]
279
+ }
280
+ ];
281
+
282
+ return Menu.buildFromTemplate(template);
283
+ }
284
+ ```
285
+
286
+ ### 7. 자동 업데이트
287
+
288
+ ```typescript
289
+ import { autoUpdater } from 'electron-updater';
290
+
291
+ // ✅ 자동 업데이트 설정
292
+ function setupAutoUpdater(): void {
293
+ autoUpdater.autoDownload = false;
294
+ autoUpdater.autoInstallOnAppQuit = true;
295
+
296
+ autoUpdater.on('update-available', (info) => {
297
+ // 사용자에게 알림
298
+ dialog.showMessageBox({
299
+ type: 'info',
300
+ title: 'Update Available',
301
+ message: `Version ${info.version} is available.`,
302
+ buttons: ['Download', 'Later']
303
+ }).then(({ response }) => {
304
+ if (response === 0) {
305
+ autoUpdater.downloadUpdate();
306
+ }
307
+ });
308
+ });
309
+
310
+ autoUpdater.on('update-downloaded', () => {
311
+ dialog.showMessageBox({
312
+ type: 'info',
313
+ title: 'Update Ready',
314
+ message: 'Restart to install update?',
315
+ buttons: ['Restart', 'Later']
316
+ }).then(({ response }) => {
317
+ if (response === 0) {
318
+ autoUpdater.quitAndInstall();
319
+ }
320
+ });
321
+ });
322
+
323
+ // 앱 시작 시 업데이트 확인
324
+ autoUpdater.checkForUpdates();
325
+ }
326
+ ```
327
+
328
+ ### 8. 보안 체크리스트
329
+
330
+ ```typescript
331
+ // ✅ 보안 설정 검증
332
+ function validateSecuritySettings(win: BrowserWindow): void {
333
+ const webPrefs = win.webContents.getWebPreferences();
334
+
335
+ if (webPrefs.nodeIntegration) {
336
+ console.error('SECURITY: nodeIntegration should be false');
337
+ }
338
+ if (!webPrefs.contextIsolation) {
339
+ console.error('SECURITY: contextIsolation should be true');
340
+ }
341
+ if (!webPrefs.sandbox) {
342
+ console.warn('SECURITY: sandbox is recommended');
343
+ }
344
+ }
345
+
346
+ // ✅ 외부 링크 처리
347
+ win.webContents.setWindowOpenHandler(({ url }) => {
348
+ // 외부 URL은 시스템 브라우저에서 열기
349
+ if (url.startsWith('https://')) {
350
+ shell.openExternal(url);
351
+ }
352
+ return { action: 'deny' };
353
+ });
354
+ ```
355
+
356
+ ## 폴더 구조 권장
357
+
358
+ ```
359
+ my-electron-app/
360
+ ├── src/
361
+ │ ├── main/ # Main Process
362
+ │ │ ├── main.ts
363
+ │ │ ├── ipc-handlers.ts
364
+ │ │ └── menu.ts
365
+ │ ├── preload/ # Preload Scripts
366
+ │ │ └── preload.ts
367
+ │ ├── renderer/ # Renderer (React/Vue)
368
+ │ │ ├── components/
369
+ │ │ ├── hooks/
370
+ │ │ └── App.tsx
371
+ │ └── shared/ # 공유 타입
372
+ │ └── ipc-types.ts
373
+ ├── electron-builder.yml
374
+ └── package.json
375
+ ```
376
+
377
+ ## 빌드 설정 (electron-builder)
378
+
379
+ ```yaml
380
+ # electron-builder.yml
381
+ appId: com.example.myapp
382
+ productName: MyApp
383
+ directories:
384
+ output: dist
385
+ files:
386
+ - "build/**/*"
387
+ - "node_modules/**/*"
388
+ mac:
389
+ target: [dmg, zip]
390
+ category: public.app-category.developer-tools
391
+ win:
392
+ target: [nsis, portable]
393
+ linux:
394
+ target: [AppImage, deb]
395
+ ```
396
+
397
+ ## 체크리스트
398
+
399
+ - [ ] `contextIsolation: true` 설정
400
+ - [ ] `nodeIntegration: false` 설정
401
+ - [ ] Preload script로만 API 노출
402
+ - [ ] IPC 채널 타입 정의
403
+ - [ ] 외부 링크 처리 (setWindowOpenHandler)
404
+ - [ ] 창 상태 저장/복원
405
+ - [ ] 자동 업데이트 설정
406
+ - [ ] 플랫폼별 메뉴 구성
407
+ - [ ] CSP 헤더 설정