@hustle-together/api-dev-tools 3.12.3 → 4.5.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 (159) hide show
  1. package/.claude/adr-requests/.gitkeep +10 -0
  2. package/.claude/agents/adr-researcher.md +109 -0
  3. package/.claude/agents/visual-analyzer.md +183 -0
  4. package/.claude/api-dev-state.json +7 -463
  5. package/.claude/documentation-audit.json +114 -0
  6. package/.claude/registry.json +289 -0
  7. package/.claude/settings.json +45 -1
  8. package/.claude/workflow-logs/None.json +49 -0
  9. package/.claude/workflow-logs/session-20251230-143727.json +106 -0
  10. package/.skills/adr-deep-research/SKILL.md +351 -0
  11. package/.skills/api-create/SKILL.md +116 -17
  12. package/.skills/api-research/SKILL.md +130 -0
  13. package/.skills/docs-sync/SKILL.md +260 -0
  14. package/.skills/docs-update/SKILL.md +205 -0
  15. package/.skills/hustle-brand/SKILL.md +368 -0
  16. package/.skills/hustle-build/SKILL.md +786 -0
  17. package/.skills/hustle-build-review/SKILL.md +518 -0
  18. package/.skills/parallel-spawn/SKILL.md +212 -0
  19. package/.skills/ralph-continue/SKILL.md +151 -0
  20. package/.skills/ralph-loop/SKILL.md +341 -0
  21. package/.skills/ralph-status/SKILL.md +87 -0
  22. package/.skills/refactor/SKILL.md +59 -0
  23. package/.skills/shadcn/SKILL.md +522 -0
  24. package/.skills/test-all/SKILL.md +210 -0
  25. package/.skills/test-builds/SKILL.md +208 -0
  26. package/.skills/test-debug/SKILL.md +212 -0
  27. package/.skills/test-e2e/SKILL.md +168 -0
  28. package/.skills/test-review/SKILL.md +707 -0
  29. package/.skills/test-unit/SKILL.md +143 -0
  30. package/.skills/test-visual/SKILL.md +301 -0
  31. package/.skills/token-report/SKILL.md +132 -0
  32. package/CHANGELOG.md +575 -0
  33. package/README.md +426 -56
  34. package/bin/cli.js +1538 -88
  35. package/commands/hustle-api-create.md +22 -0
  36. package/commands/hustle-build.md +259 -0
  37. package/commands/hustle-combine.md +81 -2
  38. package/commands/hustle-ui-create-page.md +84 -2
  39. package/commands/hustle-ui-create.md +82 -2
  40. package/hooks/__pycache__/api-workflow-check.cpython-314.pyc +0 -0
  41. package/hooks/__pycache__/auto-answer.cpython-314.pyc +0 -0
  42. package/hooks/__pycache__/cache-research.cpython-314.pyc +0 -0
  43. package/hooks/__pycache__/check-api-routes.cpython-314.pyc +0 -0
  44. package/hooks/__pycache__/check-playwright-setup.cpython-314.pyc +0 -0
  45. package/hooks/__pycache__/check-storybook-setup.cpython-314.pyc +0 -0
  46. package/hooks/__pycache__/check-update.cpython-314.pyc +0 -0
  47. package/hooks/__pycache__/completion-promise-detector.cpython-314.pyc +0 -0
  48. package/hooks/__pycache__/context-capacity-warning.cpython-314.pyc +0 -0
  49. package/hooks/__pycache__/detect-interruption.cpython-314.pyc +0 -0
  50. package/hooks/__pycache__/docs-update-check.cpython-314.pyc +0 -0
  51. package/hooks/__pycache__/enforce-a11y-audit.cpython-314.pyc +0 -0
  52. package/hooks/__pycache__/enforce-brand-guide.cpython-314.pyc +0 -0
  53. package/hooks/__pycache__/enforce-component-type-confirm.cpython-314.pyc +0 -0
  54. package/hooks/__pycache__/enforce-deep-research.cpython-314.pyc +0 -0
  55. package/hooks/__pycache__/enforce-disambiguation.cpython-314.pyc +0 -0
  56. package/hooks/__pycache__/enforce-documentation.cpython-314.pyc +0 -0
  57. package/hooks/__pycache__/enforce-dry-run.cpython-314.pyc +0 -0
  58. package/hooks/__pycache__/enforce-environment.cpython-314.pyc +0 -0
  59. package/hooks/__pycache__/enforce-external-research.cpython-314.pyc +0 -0
  60. package/hooks/__pycache__/enforce-freshness.cpython-314.pyc +0 -0
  61. package/hooks/__pycache__/enforce-interview.cpython-314.pyc +0 -0
  62. package/hooks/__pycache__/enforce-page-components.cpython-314.pyc +0 -0
  63. package/hooks/__pycache__/enforce-page-data-schema.cpython-314.pyc +0 -0
  64. package/hooks/__pycache__/enforce-questions-sourced.cpython-314.pyc +0 -0
  65. package/hooks/__pycache__/enforce-refactor.cpython-314.pyc +0 -0
  66. package/hooks/__pycache__/enforce-research.cpython-314.pyc +0 -0
  67. package/hooks/__pycache__/enforce-schema-from-interview.cpython-314.pyc +0 -0
  68. package/hooks/__pycache__/enforce-schema.cpython-314.pyc +0 -0
  69. package/hooks/__pycache__/enforce-scope.cpython-314.pyc +0 -0
  70. package/hooks/__pycache__/enforce-tdd-red.cpython-314.pyc +0 -0
  71. package/hooks/__pycache__/enforce-ui-disambiguation.cpython-314.pyc +0 -0
  72. package/hooks/__pycache__/enforce-ui-interview.cpython-314.pyc +0 -0
  73. package/hooks/__pycache__/enforce-verify.cpython-314.pyc +0 -0
  74. package/hooks/__pycache__/generate-adr-options.cpython-314.pyc +0 -0
  75. package/hooks/__pycache__/generate-manifest-entry.cpython-314.pyc +0 -0
  76. package/hooks/__pycache__/hook_utils.cpython-314.pyc +0 -0
  77. package/hooks/__pycache__/notify-input-needed.cpython-314.pyc +0 -0
  78. package/hooks/__pycache__/notify-phase-complete.cpython-314.pyc +0 -0
  79. package/hooks/__pycache__/ntfy-on-question.cpython-314.pyc +0 -0
  80. package/hooks/__pycache__/orchestrator-completion.cpython-314.pyc +0 -0
  81. package/hooks/__pycache__/orchestrator-handoff.cpython-314.pyc +0 -0
  82. package/hooks/__pycache__/orchestrator-session-startup.cpython-314.pyc +0 -0
  83. package/hooks/__pycache__/parallel-orchestrator.cpython-314.pyc +0 -0
  84. package/hooks/__pycache__/periodic-reground.cpython-314.pyc +0 -0
  85. package/hooks/__pycache__/project-document-prompt.cpython-314.pyc +0 -0
  86. package/hooks/__pycache__/remote-question-proxy.cpython-314.pyc +0 -0
  87. package/hooks/__pycache__/remote-question-server.cpython-314.pyc +0 -0
  88. package/hooks/__pycache__/run-code-review.cpython-314.pyc +0 -0
  89. package/hooks/__pycache__/run-visual-qa.cpython-314.pyc +0 -0
  90. package/hooks/__pycache__/session-logger.cpython-314.pyc +0 -0
  91. package/hooks/__pycache__/session-startup.cpython-314.pyc +0 -0
  92. package/hooks/__pycache__/track-scope-coverage.cpython-314.pyc +0 -0
  93. package/hooks/__pycache__/track-token-usage.cpython-314.pyc +0 -0
  94. package/hooks/__pycache__/track-tool-use.cpython-314.pyc +0 -0
  95. package/hooks/__pycache__/update-adr-decision.cpython-314.pyc +0 -0
  96. package/hooks/__pycache__/update-api-showcase.cpython-314.pyc +0 -0
  97. package/hooks/__pycache__/update-registry.cpython-314.pyc +0 -0
  98. package/hooks/__pycache__/update-ui-showcase.cpython-314.pyc +0 -0
  99. package/hooks/__pycache__/verify-after-green.cpython-314.pyc +0 -0
  100. package/hooks/__pycache__/verify-implementation.cpython-314.pyc +0 -0
  101. package/hooks/api-workflow-check.py +34 -0
  102. package/hooks/auto-answer.py +305 -0
  103. package/hooks/check-update.py +132 -0
  104. package/hooks/completion-promise-detector.py +293 -0
  105. package/hooks/context-capacity-warning.py +171 -0
  106. package/hooks/docs-update-check.py +120 -0
  107. package/hooks/enforce-dry-run.py +134 -0
  108. package/hooks/enforce-external-research.py +25 -0
  109. package/hooks/enforce-interview.py +20 -0
  110. package/hooks/generate-adr-options.py +282 -0
  111. package/hooks/hook_utils.py +609 -0
  112. package/hooks/lib/__pycache__/__init__.cpython-314.pyc +0 -0
  113. package/hooks/lib/__pycache__/greptile.cpython-314.pyc +0 -0
  114. package/hooks/lib/__pycache__/ntfy.cpython-314.pyc +0 -0
  115. package/hooks/ntfy-on-question.py +240 -0
  116. package/hooks/orchestrator-completion.py +313 -0
  117. package/hooks/orchestrator-handoff.py +267 -0
  118. package/hooks/orchestrator-session-startup.py +146 -0
  119. package/hooks/parallel-orchestrator.py +451 -0
  120. package/hooks/periodic-reground.py +270 -67
  121. package/hooks/project-document-prompt.py +302 -0
  122. package/hooks/remote-question-proxy.py +284 -0
  123. package/hooks/remote-question-server.py +1224 -0
  124. package/hooks/run-code-review.py +176 -29
  125. package/hooks/run-visual-qa.py +338 -0
  126. package/hooks/session-logger.py +27 -1
  127. package/hooks/session-startup.py +113 -0
  128. package/hooks/update-adr-decision.py +236 -0
  129. package/hooks/update-api-showcase.py +13 -1
  130. package/hooks/update-testing-checklist.py +195 -0
  131. package/hooks/update-ui-showcase.py +13 -1
  132. package/package.json +7 -3
  133. package/scripts/extract-schema-docs.cjs +322 -0
  134. package/templates/.skills/hustle-interview/SKILL.md +174 -0
  135. package/templates/CLAUDE-SECTION.md +89 -64
  136. package/templates/adr-viewer/_components/ADRViewer.tsx +326 -0
  137. package/templates/api-dev-state.json +33 -1
  138. package/templates/api-showcase/_components/APIModal.tsx +100 -8
  139. package/templates/api-showcase/_components/APIShowcase.tsx +36 -4
  140. package/templates/api-showcase/_components/APITester.tsx +367 -58
  141. package/templates/brand-page/page.tsx +645 -0
  142. package/templates/component/Component.visual.spec.ts +30 -24
  143. package/templates/docs/page.tsx +230 -0
  144. package/templates/eslint-plugin-zod-schema/index.js +446 -0
  145. package/templates/eslint-plugin-zod-schema/package.json +26 -0
  146. package/templates/github-workflows/security.yml +274 -0
  147. package/templates/hustle-build-defaults.json +136 -0
  148. package/templates/hustle-dev-dashboard/page.tsx +365 -0
  149. package/templates/page/page.e2e.test.ts +30 -26
  150. package/templates/performance-budgets.json +63 -5
  151. package/templates/playwright-report/page.tsx +258 -0
  152. package/templates/registry.json +279 -3
  153. package/templates/review-dashboard/page.tsx +510 -0
  154. package/templates/settings.json +155 -7
  155. package/templates/test-results/page.tsx +237 -0
  156. package/templates/typedoc.json +19 -0
  157. package/templates/ui-showcase/_components/UIShowcase.tsx +48 -1
  158. package/templates/ui-showcase/_components/VisualTestingDashboard.tsx +579 -0
  159. package/templates/ui-showcase/page.tsx +1 -1
@@ -0,0 +1,446 @@
1
+ /**
2
+ * ESLint Plugin for Zod Schema Linting
3
+ *
4
+ * Enforces best practices for Zod schemas:
5
+ * - require-description: All schemas should have .describe()
6
+ * - consistent-naming: Keys should follow naming convention
7
+ * - require-error-message: String validations should have error messages
8
+ * - no-unsafe-defaults: Avoid empty/zero defaults
9
+ * - prefer-strict: Objects should use .strict()
10
+ *
11
+ * Installation:
12
+ * 1. Copy this to your project's eslint-plugin-zod-schema/index.js
13
+ * 2. Add to eslint.config.js (see bottom of file)
14
+ *
15
+ * @version 1.0.0
16
+ * @see docs/SCHEMA-LINT.md
17
+ */
18
+
19
+ // Helper: Check if node is a Zod method call
20
+ function isZodCall(node) {
21
+ if (node.type !== 'CallExpression') return false;
22
+
23
+ // Check for z.string(), z.object(), etc.
24
+ if (
25
+ node.callee.type === 'MemberExpression' &&
26
+ node.callee.object.name === 'z'
27
+ ) {
28
+ return true;
29
+ }
30
+
31
+ // Check for chained calls like z.string().email()
32
+ if (
33
+ node.callee.type === 'MemberExpression' &&
34
+ node.callee.object.type === 'CallExpression'
35
+ ) {
36
+ return isZodCall(node.callee.object);
37
+ }
38
+
39
+ return false;
40
+ }
41
+
42
+ // Helper: Check if chain has .describe()
43
+ function hasDescribe(node) {
44
+ let current = node;
45
+ while (current) {
46
+ if (
47
+ current.type === 'CallExpression' &&
48
+ current.callee.type === 'MemberExpression' &&
49
+ current.callee.property.name === 'describe'
50
+ ) {
51
+ return true;
52
+ }
53
+ // Move up the chain
54
+ if (current.callee && current.callee.object) {
55
+ current = current.callee.object;
56
+ } else {
57
+ break;
58
+ }
59
+ }
60
+ return false;
61
+ }
62
+
63
+ // Helper: Check naming convention
64
+ function matchesCase(name, caseType) {
65
+ if (caseType === 'camelCase') {
66
+ return /^[a-z][a-zA-Z0-9]*$/.test(name);
67
+ }
68
+ if (caseType === 'snake_case') {
69
+ return /^[a-z][a-z0-9_]*$/.test(name);
70
+ }
71
+ return true;
72
+ }
73
+
74
+ // Helper: Check if node is inside z.object()
75
+ function isInsideZodObject(node, context) {
76
+ const ancestors = context.getAncestors();
77
+ return ancestors.some(
78
+ (ancestor) =>
79
+ ancestor.type === 'CallExpression' &&
80
+ ancestor.callee.type === 'MemberExpression' &&
81
+ ancestor.callee.object.name === 'z' &&
82
+ ancestor.callee.property.name === 'object'
83
+ );
84
+ }
85
+
86
+ // Helper: Check if string validation has error message
87
+ function hasErrorMessage(node) {
88
+ // Check for { message: '...' } in validation call
89
+ if (node.arguments && node.arguments.length > 0) {
90
+ const lastArg = node.arguments[node.arguments.length - 1];
91
+ if (lastArg.type === 'ObjectExpression') {
92
+ return lastArg.properties.some(
93
+ (prop) => prop.key && prop.key.name === 'message'
94
+ );
95
+ }
96
+ // Some validations accept message as string directly
97
+ if (lastArg.type === 'Literal' && typeof lastArg.value === 'string') {
98
+ return true;
99
+ }
100
+ }
101
+ return false;
102
+ }
103
+
104
+ // Helper: Check for unsafe defaults
105
+ function isUnsafeDefault(node) {
106
+ if (
107
+ node.callee.type === 'MemberExpression' &&
108
+ node.callee.property.name === 'default'
109
+ ) {
110
+ const defaultArg = node.arguments[0];
111
+ if (!defaultArg) return true; // No argument is unsafe
112
+
113
+ // Empty string
114
+ if (defaultArg.type === 'Literal' && defaultArg.value === '') {
115
+ return true;
116
+ }
117
+ // Zero for numbers (might be intentional, but warn)
118
+ if (defaultArg.type === 'Literal' && defaultArg.value === 0) {
119
+ return true;
120
+ }
121
+ // null
122
+ if (defaultArg.type === 'Literal' && defaultArg.value === null) {
123
+ return true;
124
+ }
125
+ // Empty array
126
+ if (
127
+ defaultArg.type === 'ArrayExpression' &&
128
+ defaultArg.elements.length === 0
129
+ ) {
130
+ return true;
131
+ }
132
+ // Empty object
133
+ if (
134
+ defaultArg.type === 'ObjectExpression' &&
135
+ defaultArg.properties.length === 0
136
+ ) {
137
+ return true;
138
+ }
139
+ }
140
+ return false;
141
+ }
142
+
143
+ // String validation methods that should have error messages
144
+ const STRING_VALIDATIONS = [
145
+ 'email',
146
+ 'url',
147
+ 'uuid',
148
+ 'cuid',
149
+ 'regex',
150
+ 'min',
151
+ 'max',
152
+ 'length',
153
+ 'startsWith',
154
+ 'endsWith',
155
+ 'includes',
156
+ ];
157
+
158
+ module.exports = {
159
+ meta: {
160
+ name: 'eslint-plugin-zod-schema',
161
+ version: '1.0.0',
162
+ },
163
+ rules: {
164
+ /**
165
+ * Require .describe() on all Zod schemas
166
+ */
167
+ 'require-description': {
168
+ meta: {
169
+ type: 'suggestion',
170
+ docs: {
171
+ description: 'Require .describe() on Zod schemas for documentation',
172
+ category: 'Best Practices',
173
+ recommended: true,
174
+ },
175
+ messages: {
176
+ missingDescribe:
177
+ 'Zod schema should have .describe() for documentation and OpenAPI generation',
178
+ },
179
+ schema: [],
180
+ },
181
+ create(context) {
182
+ return {
183
+ VariableDeclarator(node) {
184
+ // Only check schemas (variables ending with Schema or containing schema)
185
+ const varName = node.id.name || '';
186
+ if (
187
+ !varName.toLowerCase().includes('schema') &&
188
+ !varName.endsWith('Schema')
189
+ ) {
190
+ return;
191
+ }
192
+
193
+ if (node.init && isZodCall(node.init) && !hasDescribe(node.init)) {
194
+ context.report({
195
+ node: node.init,
196
+ messageId: 'missingDescribe',
197
+ });
198
+ }
199
+ },
200
+ };
201
+ },
202
+ },
203
+
204
+ /**
205
+ * Enforce consistent naming in z.object() keys
206
+ */
207
+ 'consistent-naming': {
208
+ meta: {
209
+ type: 'problem',
210
+ docs: {
211
+ description: 'Enforce consistent naming convention in schema keys',
212
+ category: 'Stylistic Issues',
213
+ recommended: true,
214
+ },
215
+ messages: {
216
+ inconsistentCase: "Schema key '{{name}}' should be {{case}}",
217
+ },
218
+ schema: [
219
+ {
220
+ type: 'object',
221
+ properties: {
222
+ case: {
223
+ enum: ['camelCase', 'snake_case'],
224
+ default: 'camelCase',
225
+ },
226
+ },
227
+ additionalProperties: false,
228
+ },
229
+ ],
230
+ },
231
+ create(context) {
232
+ const options = context.options[0] || {};
233
+ const caseType = options.case || 'camelCase';
234
+
235
+ return {
236
+ Property(node) {
237
+ // Only check inside z.object()
238
+ if (!isInsideZodObject(node, context)) {
239
+ return;
240
+ }
241
+
242
+ const keyName = node.key.name || node.key.value;
243
+ if (keyName && !matchesCase(keyName, caseType)) {
244
+ context.report({
245
+ node: node.key,
246
+ messageId: 'inconsistentCase',
247
+ data: {
248
+ name: keyName,
249
+ case: caseType,
250
+ },
251
+ });
252
+ }
253
+ },
254
+ };
255
+ },
256
+ },
257
+
258
+ /**
259
+ * Require custom error messages on string validations
260
+ */
261
+ 'require-error-message': {
262
+ meta: {
263
+ type: 'suggestion',
264
+ docs: {
265
+ description:
266
+ 'Require custom error messages on string validation methods',
267
+ category: 'Best Practices',
268
+ recommended: false,
269
+ },
270
+ messages: {
271
+ missingErrorMessage:
272
+ "String validation '{{method}}' should have a custom error message",
273
+ },
274
+ schema: [],
275
+ },
276
+ create(context) {
277
+ return {
278
+ CallExpression(node) {
279
+ if (
280
+ node.callee.type === 'MemberExpression' &&
281
+ STRING_VALIDATIONS.includes(node.callee.property.name) &&
282
+ isZodCall(node)
283
+ ) {
284
+ if (!hasErrorMessage(node)) {
285
+ context.report({
286
+ node,
287
+ messageId: 'missingErrorMessage',
288
+ data: {
289
+ method: node.callee.property.name,
290
+ },
291
+ });
292
+ }
293
+ }
294
+ },
295
+ };
296
+ },
297
+ },
298
+
299
+ /**
300
+ * Warn about potentially unsafe default values
301
+ */
302
+ 'no-unsafe-defaults': {
303
+ meta: {
304
+ type: 'suggestion',
305
+ docs: {
306
+ description:
307
+ 'Warn about empty/zero default values that might cause issues',
308
+ category: 'Best Practices',
309
+ recommended: true,
310
+ },
311
+ messages: {
312
+ unsafeDefault:
313
+ 'Default value might be unsafe. Empty strings, zeros, nulls, and empty arrays/objects can cause issues. Use .optional() instead or provide a meaningful default.',
314
+ },
315
+ schema: [],
316
+ },
317
+ create(context) {
318
+ return {
319
+ CallExpression(node) {
320
+ if (isZodCall(node) && isUnsafeDefault(node)) {
321
+ context.report({
322
+ node,
323
+ messageId: 'unsafeDefault',
324
+ });
325
+ }
326
+ },
327
+ };
328
+ },
329
+ },
330
+
331
+ /**
332
+ * Prefer .strict() on z.object() to prevent extra properties
333
+ */
334
+ 'prefer-strict': {
335
+ meta: {
336
+ type: 'suggestion',
337
+ docs: {
338
+ description:
339
+ 'Prefer .strict() on z.object() to reject extra properties',
340
+ category: 'Best Practices',
341
+ recommended: false,
342
+ },
343
+ messages: {
344
+ preferStrict:
345
+ 'Consider using .strict() on z.object() to reject extra properties and prevent data leaks',
346
+ },
347
+ schema: [],
348
+ },
349
+ create(context) {
350
+ return {
351
+ CallExpression(node) {
352
+ // Check for z.object() without .strict()
353
+ if (
354
+ node.callee.type === 'MemberExpression' &&
355
+ node.callee.object.name === 'z' &&
356
+ node.callee.property.name === 'object'
357
+ ) {
358
+ // Check if parent chain includes .strict()
359
+ const parent = node.parent;
360
+ if (
361
+ parent &&
362
+ parent.type === 'MemberExpression' &&
363
+ parent.property.name === 'strict'
364
+ ) {
365
+ return; // Has .strict()
366
+ }
367
+
368
+ // Check full chain
369
+ let current = node.parent;
370
+ while (current) {
371
+ if (
372
+ current.type === 'CallExpression' &&
373
+ current.callee.type === 'MemberExpression' &&
374
+ current.callee.property.name === 'strict'
375
+ ) {
376
+ return; // Has .strict() somewhere in chain
377
+ }
378
+ current = current.parent;
379
+ }
380
+
381
+ context.report({
382
+ node,
383
+ messageId: 'preferStrict',
384
+ });
385
+ }
386
+ },
387
+ };
388
+ },
389
+ },
390
+ },
391
+
392
+ // Recommended config
393
+ configs: {
394
+ recommended: {
395
+ plugins: ['zod-schema'],
396
+ rules: {
397
+ 'zod-schema/require-description': 'warn',
398
+ 'zod-schema/consistent-naming': ['error', { case: 'camelCase' }],
399
+ 'zod-schema/no-unsafe-defaults': 'warn',
400
+ 'zod-schema/require-error-message': 'off',
401
+ 'zod-schema/prefer-strict': 'off',
402
+ },
403
+ },
404
+ strict: {
405
+ plugins: ['zod-schema'],
406
+ rules: {
407
+ 'zod-schema/require-description': 'error',
408
+ 'zod-schema/consistent-naming': ['error', { case: 'camelCase' }],
409
+ 'zod-schema/no-unsafe-defaults': 'error',
410
+ 'zod-schema/require-error-message': 'warn',
411
+ 'zod-schema/prefer-strict': 'warn',
412
+ },
413
+ },
414
+ },
415
+ };
416
+
417
+ /*
418
+ * USAGE IN eslint.config.js:
419
+ *
420
+ * import zodSchemaPlugin from './eslint-plugin-zod-schema';
421
+ *
422
+ * export default [
423
+ * {
424
+ * files: ['**\/*.schema.ts', '**\/*.schemas.ts'],
425
+ * plugins: {
426
+ * 'zod-schema': zodSchemaPlugin,
427
+ * },
428
+ * rules: {
429
+ * 'zod-schema/require-description': 'warn',
430
+ * 'zod-schema/consistent-naming': ['error', { case: 'camelCase' }],
431
+ * 'zod-schema/no-unsafe-defaults': 'warn',
432
+ * },
433
+ * },
434
+ * ];
435
+ *
436
+ * Or use the recommended config:
437
+ *
438
+ * import zodSchemaPlugin from './eslint-plugin-zod-schema';
439
+ *
440
+ * export default [
441
+ * {
442
+ * files: ['**\/*.schema.ts'],
443
+ * ...zodSchemaPlugin.configs.recommended,
444
+ * },
445
+ * ];
446
+ */
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "eslint-plugin-zod-schema",
3
+ "version": "1.0.0",
4
+ "description": "ESLint plugin for Zod schema best practices",
5
+ "main": "index.js",
6
+ "keywords": [
7
+ "eslint",
8
+ "eslintplugin",
9
+ "eslint-plugin",
10
+ "zod",
11
+ "schema",
12
+ "validation"
13
+ ],
14
+ "author": "Hustle Together",
15
+ "license": "MIT",
16
+ "peerDependencies": {
17
+ "eslint": ">=8.0.0"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/hustle-together/api-dev-tools"
22
+ },
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ }
26
+ }