ginskill-init 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.
Files changed (92) hide show
  1. package/README.md +77 -0
  2. package/agents/developer.md +56 -0
  3. package/agents/frontend-design.md +69 -0
  4. package/agents/mobile-reviewer.md +36 -0
  5. package/agents/review-code.md +49 -0
  6. package/agents/security-scanner.md +50 -0
  7. package/agents/tester.md +72 -0
  8. package/bin/cli.js +226 -0
  9. package/package.json +20 -0
  10. package/skills/ai-asset-generator/SKILL.md +255 -0
  11. package/skills/ai-asset-generator/docs/gen-image.md +274 -0
  12. package/skills/ai-asset-generator/docs/genvideo.md +341 -0
  13. package/skills/ai-asset-generator/docs/remove-background.md +19 -0
  14. package/skills/ai-asset-generator/generate-credit-assets.mjs +180 -0
  15. package/skills/ai-asset-generator/generate-ginbrowser-assets.mjs +242 -0
  16. package/skills/ai-asset-generator/generate-sty-icon.mjs +149 -0
  17. package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
  18. package/skills/ai-asset-generator/lib/env.mjs +38 -0
  19. package/skills/ai-asset-generator/lib/kie-client.mjs +88 -0
  20. package/skills/ai-asset-generator/scripts/scaffold-generator.mjs +203 -0
  21. package/skills/ai-build-ai/SKILL.md +124 -0
  22. package/skills/ai-build-ai/docs/agent-teams.md +293 -0
  23. package/skills/ai-build-ai/docs/checkpointing.md +161 -0
  24. package/skills/ai-build-ai/docs/create-agent.md +399 -0
  25. package/skills/ai-build-ai/docs/create-mcp.md +395 -0
  26. package/skills/ai-build-ai/docs/create-skill.md +299 -0
  27. package/skills/ai-build-ai/docs/headless-mode.md +614 -0
  28. package/skills/ai-build-ai/docs/hooks.md +578 -0
  29. package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
  30. package/skills/ai-build-ai/docs/output-styles.md +208 -0
  31. package/skills/ai-build-ai/docs/overview.md +162 -0
  32. package/skills/ai-build-ai/docs/permissions.md +391 -0
  33. package/skills/ai-build-ai/docs/plugins.md +396 -0
  34. package/skills/ai-build-ai/docs/sandbox.md +262 -0
  35. package/skills/ai-build-ai/scripts/load-tutorial.sh +54 -0
  36. package/skills/icon-generator/SKILL.md +270 -0
  37. package/skills/mobile-app-review/SKILL.md +321 -0
  38. package/skills/mobile-app-review/references/apple-review.md +132 -0
  39. package/skills/mobile-app-review/references/google-play-review.md +203 -0
  40. package/skills/mongodb/SKILL.md +667 -0
  41. package/skills/mongodb/references/mongoose-patterns.md +368 -0
  42. package/skills/nestjs-architecture/SKILL.md +1086 -0
  43. package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
  44. package/skills/performance/SKILL.md +509 -0
  45. package/skills/react-fsd-architecture/SKILL.md +693 -0
  46. package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
  47. package/skills/react-query/SKILL.md +685 -0
  48. package/skills/react-query/references/query-patterns.md +365 -0
  49. package/skills/review-code/SKILL.md +321 -0
  50. package/skills/review-code/references/clean-code-principles.md +395 -0
  51. package/skills/review-code/references/frontend-patterns.md +136 -0
  52. package/skills/review-code/references/nestjs-patterns.md +184 -0
  53. package/skills/review-code/scripts/check-module.sh +201 -0
  54. package/skills/review-code/scripts/deep-scan.sh +604 -0
  55. package/skills/review-code/scripts/dep-check.sh +522 -0
  56. package/skills/review-code/scripts/detect-duplicates.sh +466 -0
  57. package/skills/review-code/scripts/format-check.sh +577 -0
  58. package/skills/review-code/scripts/run-review.sh +167 -0
  59. package/skills/review-code/scripts/scan-codebase.sh +152 -0
  60. package/skills/security-scanner/SKILL.md +327 -0
  61. package/skills/security-scanner/references/nestjs-security.md +260 -0
  62. package/skills/security-scanner/references/nextjs-security.md +201 -0
  63. package/skills/security-scanner/references/react-native-security.md +199 -0
  64. package/skills/security-scanner/scripts/security-scan.sh +478 -0
  65. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  66. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  67. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  68. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  69. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  70. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  71. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  72. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  73. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  74. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  75. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  76. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  77. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  78. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  79. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  80. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  81. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  82. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  83. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  84. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  85. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  86. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  87. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  88. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  89. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  90. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  91. package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  92. package/skills/ui-ux-pro-max/scripts/search.py +114 -0
@@ -0,0 +1,368 @@
1
+ # Advanced Mongoose Patterns
2
+
3
+ Detailed reference for advanced patterns beyond the main SKILL.md. Load this when working on specific advanced scenarios.
4
+
5
+ ## Pre/Post Hooks (Middleware)
6
+
7
+ ### Pre-save: Hash Password
8
+
9
+ ```typescript
10
+ UserSchema.pre<UserDocument>('save', async function (next) {
11
+ if (!this.isModified('password')) return next()
12
+ this.password = await bcrypt.hash(this.password, 12)
13
+ next()
14
+ })
15
+ ```
16
+
17
+ ### Pre-find: Auto-exclude soft-deleted
18
+
19
+ ```typescript
20
+ ProductSchema.pre('find', function () {
21
+ this.where({ deletedAt: null })
22
+ })
23
+
24
+ ProductSchema.pre('findOne', function () {
25
+ this.where({ deletedAt: null })
26
+ })
27
+
28
+ ProductSchema.pre('countDocuments', function () {
29
+ this.where({ deletedAt: null })
30
+ })
31
+ ```
32
+
33
+ ### Post-save: Side Effects
34
+
35
+ ```typescript
36
+ OrderSchema.post<OrderDocument>('save', async function (doc) {
37
+ // Send notification after order created
38
+ await notificationService.send(doc.userId, `Order ${doc._id} placed`)
39
+ })
40
+ ```
41
+
42
+ ### Hook Gotchas
43
+
44
+ - `findOneAndUpdate` does NOT trigger `save` hooks — use `pre('findOneAndUpdate')` instead
45
+ - `insertMany` does NOT trigger `save` hooks — use `pre('insertMany')` if needed
46
+ - Arrow functions lose `this` context — always use `function` keyword in hooks
47
+
48
+ ## Custom Methods & Statics
49
+
50
+ ### Instance Methods
51
+
52
+ ```typescript
53
+ // Schema definition
54
+ UserSchema.methods.comparePassword = async function (candidate: string): Promise<boolean> {
55
+ return bcrypt.compare(candidate, this.password)
56
+ }
57
+
58
+ UserSchema.methods.toPublicJSON = function () {
59
+ const { password, __v, ...rest } = this.toObject()
60
+ return rest
61
+ }
62
+
63
+ // Usage
64
+ const user = await User.findOne({ email })
65
+ const isValid = await user.comparePassword(inputPassword)
66
+ ```
67
+
68
+ ### Static Methods
69
+
70
+ ```typescript
71
+ // Schema definition
72
+ UserSchema.statics.findByEmail = function (email: string) {
73
+ return this.findOne({ email: email.toLowerCase() }).lean()
74
+ }
75
+
76
+ UserSchema.statics.findActiveByOrg = function (orgId: string) {
77
+ return this.find({ organization: orgId, status: 'active' }).lean()
78
+ }
79
+
80
+ // Usage
81
+ const user = await User.findByEmail('john@example.com')
82
+ ```
83
+
84
+ ### TypeScript Typing for Methods/Statics
85
+
86
+ ```typescript
87
+ // Define interfaces
88
+ interface IUserMethods {
89
+ comparePassword(candidate: string): Promise<boolean>
90
+ toPublicJSON(): Omit<User, 'password'>
91
+ }
92
+
93
+ interface UserModel extends Model<User, {}, IUserMethods> {
94
+ findByEmail(email: string): Promise<User | null>
95
+ findActiveByOrg(orgId: string): Promise<User[]>
96
+ }
97
+
98
+ // In NestJS module
99
+ @InjectModel(User.name) private userModel: UserModel
100
+ ```
101
+
102
+ ## Mongoose Plugins
103
+
104
+ ### Global Plugins
105
+
106
+ ```typescript
107
+ // Apply to all schemas
108
+ import mongooseLeanVirtuals from 'mongoose-lean-virtuals'
109
+ import mongooseLeanGetters from 'mongoose-lean-getters'
110
+
111
+ mongoose.plugin(mongooseLeanVirtuals)
112
+ mongoose.plugin(mongooseLeanGetters)
113
+ ```
114
+
115
+ ### Soft Delete Plugin
116
+
117
+ ```typescript
118
+ function softDeletePlugin(schema: Schema) {
119
+ schema.add({ deletedAt: { type: Date, default: null } })
120
+
121
+ schema.methods.softDelete = function () {
122
+ this.deletedAt = new Date()
123
+ return this.save()
124
+ }
125
+
126
+ schema.methods.restore = function () {
127
+ this.deletedAt = null
128
+ return this.save()
129
+ }
130
+
131
+ // Auto-filter soft-deleted docs
132
+ schema.pre('find', function () { this.where({ deletedAt: null }) })
133
+ schema.pre('findOne', function () { this.where({ deletedAt: null }) })
134
+ schema.pre('countDocuments', function () { this.where({ deletedAt: null }) })
135
+
136
+ // Index for queries that include deleted docs
137
+ schema.index({ deletedAt: 1 })
138
+ }
139
+
140
+ // Apply
141
+ UserSchema.plugin(softDeletePlugin)
142
+ ```
143
+
144
+ ### Pagination Plugin
145
+
146
+ ```typescript
147
+ interface PaginateResult<T> {
148
+ docs: T[]
149
+ totalDocs: number
150
+ page: number
151
+ totalPages: number
152
+ hasNextPage: boolean
153
+ hasPrevPage: boolean
154
+ }
155
+
156
+ function paginatePlugin(schema: Schema) {
157
+ schema.statics.paginate = async function (
158
+ filter: FilterQuery<any> = {},
159
+ options: { page?: number; limit?: number; sort?: any; select?: string; lean?: boolean } = {},
160
+ ): Promise<PaginateResult<any>> {
161
+ const page = Math.max(1, options.page || 1)
162
+ const limit = Math.min(100, Math.max(1, options.limit || 20))
163
+ const skip = (page - 1) * limit
164
+
165
+ const [docs, totalDocs] = await Promise.all([
166
+ this.find(filter)
167
+ .sort(options.sort || { createdAt: -1 })
168
+ .skip(skip)
169
+ .limit(limit)
170
+ .select(options.select || '')
171
+ .lean(options.lean ?? true)
172
+ .exec(),
173
+ this.countDocuments(filter),
174
+ ])
175
+
176
+ const totalPages = Math.ceil(totalDocs / limit)
177
+ return {
178
+ docs,
179
+ totalDocs,
180
+ page,
181
+ totalPages,
182
+ hasNextPage: page < totalPages,
183
+ hasPrevPage: page > 1,
184
+ }
185
+ }
186
+ }
187
+ ```
188
+
189
+ ## Change Streams
190
+
191
+ Watch real-time changes to a collection (requires replica set).
192
+
193
+ ```typescript
194
+ // Watch for new orders
195
+ const changeStream = this.orderModel.watch([
196
+ { $match: { operationType: 'insert' } },
197
+ ])
198
+
199
+ changeStream.on('change', (change) => {
200
+ console.log('New order:', change.fullDocument)
201
+ // Trigger notifications, update dashboards, etc.
202
+ })
203
+
204
+ // Watch for specific field updates
205
+ const priceStream = this.productModel.watch([
206
+ { $match: { 'updateDescription.updatedFields.price': { $exists: true } } },
207
+ ])
208
+
209
+ // Cleanup
210
+ process.on('SIGTERM', () => changeStream.close())
211
+ ```
212
+
213
+ ### Resume After Disconnect
214
+
215
+ ```typescript
216
+ let resumeToken: unknown
217
+
218
+ const stream = this.orderModel.watch([], {
219
+ fullDocument: 'updateLookup', // include full doc on updates
220
+ ...(resumeToken ? { resumeAfter: resumeToken } : {}),
221
+ })
222
+
223
+ stream.on('change', (change) => {
224
+ resumeToken = change._id // save for resume
225
+ handleChange(change)
226
+ })
227
+
228
+ stream.on('error', (err) => {
229
+ logger.error('Change stream error:', err)
230
+ // Reconnect with resumeToken after delay
231
+ setTimeout(() => startChangeStream(), 5000)
232
+ })
233
+ ```
234
+
235
+ ## Cursor-Based Streaming
236
+
237
+ Process large datasets without loading everything into memory.
238
+
239
+ ```typescript
240
+ // Process 1M documents with constant memory usage
241
+ const cursor = this.userModel.find({ status: 'active' }).lean().cursor()
242
+
243
+ for await (const user of cursor) {
244
+ await processUser(user)
245
+ }
246
+
247
+ // Or with batch size control
248
+ const cursor = this.orderModel.find().lean().cursor({ batchSize: 100 })
249
+ ```
250
+
251
+ ## Schema Versioning
252
+
253
+ Handle schema evolution in existing data.
254
+
255
+ ```typescript
256
+ @Schema({ timestamps: true })
257
+ export class User {
258
+ @Prop({ default: 2 })
259
+ schemaVersion: number
260
+
261
+ @Prop({ required: true })
262
+ name: string
263
+
264
+ // v2: contact methods as array (replaces v1 phone/email fields)
265
+ @Prop({ type: [{ type: String, value: String }], default: [] })
266
+ contactMethods: Array<{ type: string; value: string }>
267
+ }
268
+
269
+ // Migration on read
270
+ async findUser(id: string) {
271
+ const doc = await this.userModel.findById(id)
272
+ if (!doc.schemaVersion || doc.schemaVersion < 2) {
273
+ return this.migrateToV2(doc)
274
+ }
275
+ return doc.toObject()
276
+ }
277
+ ```
278
+
279
+ ## Multi-Tenant Patterns
280
+
281
+ ### Database-per-Tenant
282
+
283
+ ```typescript
284
+ const connectionMap = new Map<string, mongoose.Connection>()
285
+
286
+ async getTenantConnection(tenantId: string): Promise<mongoose.Connection> {
287
+ if (connectionMap.has(tenantId)) return connectionMap.get(tenantId)!
288
+
289
+ const conn = await mongoose.createConnection(`${baseUri}/${tenantId}`, {
290
+ maxPoolSize: 5,
291
+ })
292
+ connectionMap.set(tenantId, conn)
293
+ return conn
294
+ }
295
+
296
+ // Get model for tenant
297
+ async getTenantModel<T>(tenantId: string, name: string, schema: Schema): Promise<Model<T>> {
298
+ const conn = await this.getTenantConnection(tenantId)
299
+ return conn.model<T>(name, schema)
300
+ }
301
+ ```
302
+
303
+ ### Collection-per-Tenant (simpler, same database)
304
+
305
+ ```typescript
306
+ async getTenantModel(tenantId: string) {
307
+ return this.connection.model('Order', OrderSchema, `orders_${tenantId}`)
308
+ }
309
+ ```
310
+
311
+ ### Shared Collection with Tenant Field
312
+
313
+ ```typescript
314
+ @Schema({ timestamps: true })
315
+ export class Order {
316
+ @Prop({ required: true, index: true })
317
+ tenantId: string
318
+
319
+ // ... other fields
320
+ }
321
+
322
+ // Always include tenantId in queries
323
+ OrderSchema.index({ tenantId: 1, createdAt: -1 })
324
+ ```
325
+
326
+ ## Explain & Debug
327
+
328
+ ### Analyze Query Performance
329
+
330
+ ```typescript
331
+ // In development only
332
+ const explanation = await this.userModel
333
+ .find({ email: 'test@example.com' })
334
+ .explain('executionStats')
335
+
336
+ // Key metrics:
337
+ // executionStats.totalDocsExamined — docs scanned (lower is better)
338
+ // executionStats.totalKeysExamined — index keys scanned
339
+ // executionStats.executionTimeMillis — query time
340
+ // winningPlan.stage — IXSCAN (good) vs COLLSCAN (bad)
341
+ ```
342
+
343
+ ### Enable Mongoose Debug Logging
344
+
345
+ ```typescript
346
+ // Log all queries in development
347
+ mongoose.set('debug', true)
348
+
349
+ // Custom logger
350
+ mongoose.set('debug', (collectionName, method, query, doc) => {
351
+ logger.debug(`${collectionName}.${method}`, JSON.stringify(query))
352
+ })
353
+ ```
354
+
355
+ ### Monitor Connection Pool
356
+
357
+ ```typescript
358
+ const pool = mongoose.connection.getClient().options
359
+ // Check: pool.maxPoolSize, pool.minPoolSize
360
+
361
+ // Monitor pool events
362
+ mongoose.connection.getClient().on('connectionPoolCreated', (event) => {
363
+ logger.debug('Pool created:', event)
364
+ })
365
+ mongoose.connection.getClient().on('connectionCheckedOut', (event) => {
366
+ logger.debug('Connection checked out:', event)
367
+ })
368
+ ```