@malamute/ai-rules 1.0.0 → 1.2.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 (133) hide show
  1. package/README.md +270 -121
  2. package/bin/cli.js +5 -2
  3. package/configs/_shared/.claude/rules/conventions/documentation.md +324 -0
  4. package/configs/_shared/.claude/rules/conventions/git.md +265 -0
  5. package/configs/_shared/.claude/rules/{performance.md → conventions/performance.md} +1 -1
  6. package/configs/_shared/.claude/rules/conventions/principles.md +334 -0
  7. package/configs/_shared/.claude/rules/devops/ci-cd.md +262 -0
  8. package/configs/_shared/.claude/rules/devops/docker.md +275 -0
  9. package/configs/_shared/.claude/rules/devops/nx.md +194 -0
  10. package/configs/_shared/.claude/rules/domain/backend/api-design.md +203 -0
  11. package/configs/_shared/.claude/rules/lang/csharp/async.md +220 -0
  12. package/configs/_shared/.claude/rules/lang/csharp/csharp.md +314 -0
  13. package/configs/_shared/.claude/rules/lang/csharp/linq.md +210 -0
  14. package/configs/_shared/.claude/rules/lang/python/async.md +337 -0
  15. package/configs/_shared/.claude/rules/lang/python/celery.md +476 -0
  16. package/configs/_shared/.claude/rules/lang/python/config.md +339 -0
  17. package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/database/sqlalchemy.md +6 -1
  18. package/configs/_shared/.claude/rules/lang/python/deployment.md +523 -0
  19. package/configs/_shared/.claude/rules/lang/python/error-handling.md +330 -0
  20. package/configs/_shared/.claude/rules/lang/python/migrations.md +421 -0
  21. package/configs/_shared/.claude/rules/lang/python/python.md +172 -0
  22. package/configs/_shared/.claude/rules/lang/python/repository.md +383 -0
  23. package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/testing.md +2 -69
  24. package/configs/_shared/.claude/rules/lang/typescript/async.md +447 -0
  25. package/configs/_shared/.claude/rules/lang/typescript/generics.md +356 -0
  26. package/configs/_shared/.claude/rules/lang/typescript/typescript.md +212 -0
  27. package/configs/_shared/.claude/rules/quality/error-handling.md +48 -0
  28. package/configs/_shared/.claude/rules/quality/logging.md +45 -0
  29. package/configs/_shared/.claude/rules/quality/observability.md +240 -0
  30. package/configs/_shared/.claude/rules/quality/testing-patterns.md +65 -0
  31. package/configs/_shared/.claude/rules/security/secrets-management.md +222 -0
  32. package/configs/_shared/.claude/skills/analysis/explore/SKILL.md +257 -0
  33. package/configs/_shared/.claude/skills/analysis/security-audit/SKILL.md +184 -0
  34. package/configs/_shared/.claude/skills/dev/api-endpoint/SKILL.md +126 -0
  35. package/configs/_shared/.claude/{commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
  36. package/configs/_shared/.claude/{commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
  37. package/configs/_shared/.claude/{commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
  38. package/configs/_shared/.claude/skills/infra/deploy/SKILL.md +139 -0
  39. package/configs/_shared/.claude/skills/infra/docker/SKILL.md +95 -0
  40. package/configs/_shared/.claude/skills/infra/migration/SKILL.md +158 -0
  41. package/configs/_shared/.claude/skills/nx/nx-affected/SKILL.md +72 -0
  42. package/configs/_shared/.claude/skills/nx/nx-lib/SKILL.md +375 -0
  43. package/configs/_shared/CLAUDE.md +52 -149
  44. package/configs/angular/.claude/rules/{components.md → core/components.md} +69 -15
  45. package/configs/angular/.claude/rules/core/resource.md +285 -0
  46. package/configs/angular/.claude/rules/core/signals.md +323 -0
  47. package/configs/angular/.claude/rules/http.md +338 -0
  48. package/configs/angular/.claude/rules/routing.md +291 -0
  49. package/configs/angular/.claude/rules/ssr.md +312 -0
  50. package/configs/angular/.claude/rules/state/signal-store.md +408 -0
  51. package/configs/angular/.claude/rules/{state.md → state/state.md} +2 -2
  52. package/configs/angular/.claude/rules/testing.md +7 -7
  53. package/configs/angular/.claude/rules/ui/aria.md +422 -0
  54. package/configs/angular/.claude/rules/ui/forms.md +424 -0
  55. package/configs/angular/.claude/rules/ui/pipes-directives.md +335 -0
  56. package/configs/angular/.claude/settings.json +1 -0
  57. package/configs/angular/.claude/skills/ngrx-slice/SKILL.md +362 -0
  58. package/configs/angular/.claude/skills/signal-store/SKILL.md +445 -0
  59. package/configs/angular/CLAUDE.md +24 -216
  60. package/configs/dotnet/.claude/rules/background-services.md +552 -0
  61. package/configs/dotnet/.claude/rules/configuration.md +426 -0
  62. package/configs/dotnet/.claude/rules/ddd.md +447 -0
  63. package/configs/dotnet/.claude/rules/dependency-injection.md +343 -0
  64. package/configs/dotnet/.claude/rules/mediatr.md +320 -0
  65. package/configs/dotnet/.claude/rules/middleware.md +489 -0
  66. package/configs/dotnet/.claude/rules/result-pattern.md +363 -0
  67. package/configs/dotnet/.claude/rules/validation.md +388 -0
  68. package/configs/dotnet/.claude/settings.json +21 -3
  69. package/configs/dotnet/CLAUDE.md +53 -286
  70. package/configs/fastapi/.claude/rules/background-tasks.md +254 -0
  71. package/configs/fastapi/.claude/rules/dependencies.md +170 -0
  72. package/configs/{python → fastapi}/.claude/rules/fastapi.md +61 -1
  73. package/configs/fastapi/.claude/rules/lifespan.md +274 -0
  74. package/configs/fastapi/.claude/rules/middleware.md +229 -0
  75. package/configs/fastapi/.claude/rules/pydantic.md +433 -0
  76. package/configs/fastapi/.claude/rules/responses.md +251 -0
  77. package/configs/fastapi/.claude/rules/routers.md +202 -0
  78. package/configs/fastapi/.claude/rules/security.md +222 -0
  79. package/configs/fastapi/.claude/rules/testing.md +251 -0
  80. package/configs/fastapi/.claude/rules/websockets.md +298 -0
  81. package/configs/fastapi/.claude/settings.json +33 -0
  82. package/configs/fastapi/CLAUDE.md +144 -0
  83. package/configs/flask/.claude/rules/blueprints.md +208 -0
  84. package/configs/flask/.claude/rules/cli.md +285 -0
  85. package/configs/flask/.claude/rules/configuration.md +281 -0
  86. package/configs/flask/.claude/rules/context.md +238 -0
  87. package/configs/flask/.claude/rules/error-handlers.md +278 -0
  88. package/configs/flask/.claude/rules/extensions.md +278 -0
  89. package/configs/flask/.claude/rules/flask.md +171 -0
  90. package/configs/flask/.claude/rules/marshmallow.md +206 -0
  91. package/configs/flask/.claude/rules/security.md +267 -0
  92. package/configs/flask/.claude/rules/testing.md +284 -0
  93. package/configs/flask/.claude/settings.json +33 -0
  94. package/configs/flask/CLAUDE.md +166 -0
  95. package/configs/nestjs/.claude/rules/common-patterns.md +300 -0
  96. package/configs/nestjs/.claude/rules/filters.md +376 -0
  97. package/configs/nestjs/.claude/rules/interceptors.md +317 -0
  98. package/configs/nestjs/.claude/rules/middleware.md +321 -0
  99. package/configs/nestjs/.claude/rules/modules.md +26 -0
  100. package/configs/nestjs/.claude/rules/pipes.md +351 -0
  101. package/configs/nestjs/.claude/rules/websockets.md +451 -0
  102. package/configs/nestjs/.claude/settings.json +16 -2
  103. package/configs/nestjs/CLAUDE.md +57 -215
  104. package/configs/nextjs/.claude/rules/api-routes.md +358 -0
  105. package/configs/nextjs/.claude/rules/authentication.md +355 -0
  106. package/configs/nextjs/.claude/rules/components.md +52 -0
  107. package/configs/nextjs/.claude/rules/data-fetching.md +249 -0
  108. package/configs/nextjs/.claude/rules/database.md +400 -0
  109. package/configs/nextjs/.claude/rules/middleware.md +303 -0
  110. package/configs/nextjs/.claude/rules/routing.md +324 -0
  111. package/configs/nextjs/.claude/rules/seo.md +350 -0
  112. package/configs/nextjs/.claude/rules/server-actions.md +353 -0
  113. package/configs/nextjs/.claude/rules/state/zustand.md +6 -6
  114. package/configs/nextjs/.claude/settings.json +5 -0
  115. package/configs/nextjs/CLAUDE.md +69 -331
  116. package/package.json +23 -9
  117. package/src/cli.js +220 -0
  118. package/src/config.js +29 -0
  119. package/src/index.js +13 -0
  120. package/src/installer.js +361 -0
  121. package/src/merge.js +116 -0
  122. package/src/tech-config.json +29 -0
  123. package/src/utils.js +96 -0
  124. package/configs/python/.claude/rules/flask.md +0 -332
  125. package/configs/python/.claude/settings.json +0 -18
  126. package/configs/python/CLAUDE.md +0 -273
  127. package/src/install.js +0 -315
  128. /package/configs/_shared/.claude/rules/{accessibility.md → domain/frontend/accessibility.md} +0 -0
  129. /package/configs/_shared/.claude/rules/{security.md → security/security.md} +0 -0
  130. /package/configs/_shared/.claude/skills/{debug → dev/debug}/SKILL.md +0 -0
  131. /package/configs/_shared/.claude/skills/{learning → dev/learning}/SKILL.md +0 -0
  132. /package/configs/_shared/.claude/skills/{spec → dev/spec}/SKILL.md +0 -0
  133. /package/configs/_shared/.claude/skills/{review → git/review}/SKILL.md +0 -0
@@ -0,0 +1,388 @@
1
+ ---
2
+ paths:
3
+ - "**/*.Validator.cs"
4
+ - "**/Validators/**/*.cs"
5
+ - "**/Validation/**/*.cs"
6
+ ---
7
+
8
+ # .NET Validation (FluentValidation)
9
+
10
+ ## Basic Validator
11
+
12
+ ```csharp
13
+ // Validators/CreateUserRequestValidator.cs
14
+ using FluentValidation;
15
+
16
+ public class CreateUserRequestValidator : AbstractValidator<CreateUserRequest>
17
+ {
18
+ public CreateUserRequestValidator()
19
+ {
20
+ RuleFor(x => x.Email)
21
+ .NotEmpty().WithMessage("Email is required")
22
+ .EmailAddress().WithMessage("Invalid email format")
23
+ .MaximumLength(255);
24
+
25
+ RuleFor(x => x.Name)
26
+ .NotEmpty().WithMessage("Name is required")
27
+ .Length(2, 100).WithMessage("Name must be between 2 and 100 characters")
28
+ .Matches(@"^[a-zA-Z\s'-]+$").WithMessage("Name contains invalid characters");
29
+
30
+ RuleFor(x => x.Password)
31
+ .NotEmpty()
32
+ .MinimumLength(8)
33
+ .Matches(@"[A-Z]").WithMessage("Password must contain uppercase letter")
34
+ .Matches(@"[a-z]").WithMessage("Password must contain lowercase letter")
35
+ .Matches(@"[0-9]").WithMessage("Password must contain digit")
36
+ .Matches(@"[^a-zA-Z0-9]").WithMessage("Password must contain special character");
37
+
38
+ RuleFor(x => x.ConfirmPassword)
39
+ .Equal(x => x.Password).WithMessage("Passwords do not match");
40
+
41
+ RuleFor(x => x.DateOfBirth)
42
+ .NotEmpty()
43
+ .LessThan(DateTime.Today).WithMessage("Date of birth must be in the past")
44
+ .Must(BeAtLeast18).WithMessage("Must be at least 18 years old");
45
+ }
46
+
47
+ private bool BeAtLeast18(DateTime dateOfBirth)
48
+ {
49
+ return dateOfBirth <= DateTime.Today.AddYears(-18);
50
+ }
51
+ }
52
+ ```
53
+
54
+ ## Async Validation
55
+
56
+ ```csharp
57
+ public class CreateUserRequestValidator : AbstractValidator<CreateUserRequest>
58
+ {
59
+ private readonly IUserRepository _userRepository;
60
+
61
+ public CreateUserRequestValidator(IUserRepository userRepository)
62
+ {
63
+ _userRepository = userRepository;
64
+
65
+ RuleFor(x => x.Email)
66
+ .NotEmpty()
67
+ .EmailAddress()
68
+ .MustAsync(BeUniqueEmail).WithMessage("Email already exists");
69
+
70
+ RuleFor(x => x.Username)
71
+ .NotEmpty()
72
+ .MustAsync(BeUniqueUsername).WithMessage("Username is taken");
73
+ }
74
+
75
+ private async Task<bool> BeUniqueEmail(string email, CancellationToken ct)
76
+ {
77
+ return !await _userRepository.ExistsAsync(u => u.Email == email, ct);
78
+ }
79
+
80
+ private async Task<bool> BeUniqueUsername(string username, CancellationToken ct)
81
+ {
82
+ return !await _userRepository.ExistsAsync(u => u.Username == username, ct);
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Conditional Validation
88
+
89
+ ```csharp
90
+ public class OrderValidator : AbstractValidator<CreateOrderRequest>
91
+ {
92
+ public OrderValidator()
93
+ {
94
+ RuleFor(x => x.ShippingAddress)
95
+ .NotEmpty()
96
+ .When(x => x.DeliveryMethod == DeliveryMethod.Shipping);
97
+
98
+ RuleFor(x => x.PickupLocation)
99
+ .NotEmpty()
100
+ .When(x => x.DeliveryMethod == DeliveryMethod.Pickup);
101
+
102
+ // Complex condition
103
+ When(x => x.PaymentMethod == PaymentMethod.CreditCard, () =>
104
+ {
105
+ RuleFor(x => x.CardNumber).NotEmpty().CreditCard();
106
+ RuleFor(x => x.ExpiryDate).NotEmpty().Must(BeValidExpiryDate);
107
+ RuleFor(x => x.Cvv).NotEmpty().Length(3, 4);
108
+ });
109
+
110
+ // Otherwise
111
+ Otherwise(() =>
112
+ {
113
+ RuleFor(x => x.BankAccountNumber).NotEmpty();
114
+ });
115
+ }
116
+ }
117
+ ```
118
+
119
+ ## Collection Validation
120
+
121
+ ```csharp
122
+ public class OrderValidator : AbstractValidator<CreateOrderRequest>
123
+ {
124
+ public OrderValidator()
125
+ {
126
+ RuleFor(x => x.Items)
127
+ .NotEmpty().WithMessage("Order must contain at least one item");
128
+
129
+ RuleForEach(x => x.Items)
130
+ .SetValidator(new OrderItemValidator());
131
+
132
+ // Custom collection rules
133
+ RuleFor(x => x.Items)
134
+ .Must(items => items.Sum(i => i.Quantity) <= 100)
135
+ .WithMessage("Maximum 100 items per order");
136
+ }
137
+ }
138
+
139
+ public class OrderItemValidator : AbstractValidator<OrderItem>
140
+ {
141
+ public OrderItemValidator()
142
+ {
143
+ RuleFor(x => x.ProductId).NotEmpty();
144
+ RuleFor(x => x.Quantity).GreaterThan(0).LessThanOrEqualTo(10);
145
+ RuleFor(x => x.Price).GreaterThan(0);
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Nested Objects
151
+
152
+ ```csharp
153
+ public class CustomerValidator : AbstractValidator<Customer>
154
+ {
155
+ public CustomerValidator()
156
+ {
157
+ RuleFor(x => x.Name).NotEmpty();
158
+
159
+ RuleFor(x => x.Address)
160
+ .NotNull()
161
+ .SetValidator(new AddressValidator());
162
+
163
+ // Inline nested validation
164
+ RuleFor(x => x.Contact)
165
+ .ChildRules(contact =>
166
+ {
167
+ contact.RuleFor(c => c.Phone).NotEmpty();
168
+ contact.RuleFor(c => c.Email).EmailAddress();
169
+ });
170
+ }
171
+ }
172
+
173
+ public class AddressValidator : AbstractValidator<Address>
174
+ {
175
+ public AddressValidator()
176
+ {
177
+ RuleFor(x => x.Street).NotEmpty().MaximumLength(200);
178
+ RuleFor(x => x.City).NotEmpty().MaximumLength(100);
179
+ RuleFor(x => x.PostalCode).NotEmpty().Matches(@"^\d{5}(-\d{4})?$");
180
+ RuleFor(x => x.Country).NotEmpty().Length(2);
181
+ }
182
+ }
183
+ ```
184
+
185
+ ## Custom Validators
186
+
187
+ ```csharp
188
+ // Extensions/ValidationExtensions.cs
189
+ public static class ValidationExtensions
190
+ {
191
+ public static IRuleBuilderOptions<T, string> PhoneNumber<T>(
192
+ this IRuleBuilder<T, string> ruleBuilder)
193
+ {
194
+ return ruleBuilder
195
+ .Matches(@"^\+?[1-9]\d{1,14}$")
196
+ .WithMessage("Invalid phone number format");
197
+ }
198
+
199
+ public static IRuleBuilderOptions<T, string> Slug<T>(
200
+ this IRuleBuilder<T, string> ruleBuilder)
201
+ {
202
+ return ruleBuilder
203
+ .Matches(@"^[a-z0-9]+(?:-[a-z0-9]+)*$")
204
+ .WithMessage("Invalid slug format");
205
+ }
206
+
207
+ public static IRuleBuilderOptions<T, decimal> Currency<T>(
208
+ this IRuleBuilder<T, decimal> ruleBuilder)
209
+ {
210
+ return ruleBuilder
211
+ .GreaterThanOrEqualTo(0)
212
+ .PrecisionScale(18, 2, true)
213
+ .WithMessage("Invalid currency format");
214
+ }
215
+ }
216
+
217
+ // Usage
218
+ RuleFor(x => x.Phone).PhoneNumber();
219
+ RuleFor(x => x.Slug).Slug();
220
+ RuleFor(x => x.Price).Currency();
221
+ ```
222
+
223
+ ## Reusable Property Validators
224
+
225
+ ```csharp
226
+ // Validators/PropertyValidators/UniqueEmailValidator.cs
227
+ public class UniqueEmailValidator<T> : AsyncPropertyValidator<T, string>
228
+ {
229
+ private readonly IUserRepository _userRepository;
230
+ private readonly Guid? _excludeUserId;
231
+
232
+ public UniqueEmailValidator(IUserRepository userRepository, Guid? excludeUserId = null)
233
+ {
234
+ _userRepository = userRepository;
235
+ _excludeUserId = excludeUserId;
236
+ }
237
+
238
+ public override string Name => "UniqueEmailValidator";
239
+
240
+ public override async Task<bool> IsValidAsync(
241
+ ValidationContext<T> context,
242
+ string value,
243
+ CancellationToken ct)
244
+ {
245
+ if (string.IsNullOrEmpty(value)) return true;
246
+
247
+ var existingUser = await _userRepository.FindByEmailAsync(value, ct);
248
+
249
+ if (existingUser == null) return true;
250
+
251
+ return _excludeUserId.HasValue && existingUser.Id == _excludeUserId.Value;
252
+ }
253
+
254
+ protected override string GetDefaultMessageTemplate(string errorCode)
255
+ => "Email is already in use";
256
+ }
257
+
258
+ // Usage
259
+ RuleFor(x => x.Email).SetAsyncValidator(new UniqueEmailValidator<Request>(_userRepository));
260
+ ```
261
+
262
+ ## Registration
263
+
264
+ ```csharp
265
+ // Program.cs or Startup.cs
266
+ builder.Services.AddValidatorsFromAssemblyContaining<CreateUserRequestValidator>();
267
+
268
+ // With pipeline behavior for MediatR
269
+ builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
270
+ ```
271
+
272
+ ## MediatR Validation Behavior
273
+
274
+ ```csharp
275
+ // Behaviors/ValidationBehavior.cs
276
+ public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
277
+ where TRequest : IRequest<TResponse>
278
+ {
279
+ private readonly IEnumerable<IValidator<TRequest>> _validators;
280
+
281
+ public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
282
+ {
283
+ _validators = validators;
284
+ }
285
+
286
+ public async Task<TResponse> Handle(
287
+ TRequest request,
288
+ RequestHandlerDelegate<TResponse> next,
289
+ CancellationToken cancellationToken)
290
+ {
291
+ if (!_validators.Any())
292
+ {
293
+ return await next();
294
+ }
295
+
296
+ var context = new ValidationContext<TRequest>(request);
297
+
298
+ var validationResults = await Task.WhenAll(
299
+ _validators.Select(v => v.ValidateAsync(context, cancellationToken)));
300
+
301
+ var failures = validationResults
302
+ .SelectMany(r => r.Errors)
303
+ .Where(f => f != null)
304
+ .ToList();
305
+
306
+ if (failures.Count != 0)
307
+ {
308
+ throw new ValidationException(failures);
309
+ }
310
+
311
+ return await next();
312
+ }
313
+ }
314
+ ```
315
+
316
+ ## API Endpoint Integration
317
+
318
+ ```csharp
319
+ // Using Minimal APIs
320
+ app.MapPost("/users", async (
321
+ CreateUserRequest request,
322
+ IValidator<CreateUserRequest> validator,
323
+ IMediator mediator) =>
324
+ {
325
+ var result = await validator.ValidateAsync(request);
326
+
327
+ if (!result.IsValid)
328
+ {
329
+ return Results.ValidationProblem(result.ToDictionary());
330
+ }
331
+
332
+ var user = await mediator.Send(new CreateUserCommand(request));
333
+ return Results.Created($"/users/{user.Id}", user);
334
+ });
335
+
336
+ // Extension for automatic validation
337
+ public static class ValidationExtensions
338
+ {
339
+ public static async Task<IResult> ValidateAndExecute<T>(
340
+ this T request,
341
+ IValidator<T> validator,
342
+ Func<Task<IResult>> onValid)
343
+ {
344
+ var result = await validator.ValidateAsync(request);
345
+
346
+ return result.IsValid
347
+ ? await onValid()
348
+ : Results.ValidationProblem(result.ToDictionary());
349
+ }
350
+ }
351
+ ```
352
+
353
+ ## Anti-patterns
354
+
355
+ ```csharp
356
+ // BAD: Business logic in validators
357
+ public class OrderValidator : AbstractValidator<Order>
358
+ {
359
+ public OrderValidator(IInventoryService inventory)
360
+ {
361
+ RuleFor(x => x.Items)
362
+ .MustAsync(async (items, ct) =>
363
+ {
364
+ await inventory.ReserveItems(items); // Side effect!
365
+ return true;
366
+ });
367
+ }
368
+ }
369
+
370
+ // GOOD: Validators only validate, services handle business logic
371
+
372
+ // BAD: Catching exceptions in validators
373
+ RuleFor(x => x.Value)
374
+ .Must(v =>
375
+ {
376
+ try { return Parse(v); }
377
+ catch { return false; } // Silent failure
378
+ });
379
+
380
+ // GOOD: Clear validation
381
+ RuleFor(x => x.Value).Must(BeValidFormat).WithMessage("Invalid format");
382
+
383
+ // BAD: Overly specific error messages exposing internals
384
+ .WithMessage($"Query failed: {exception.Message}");
385
+
386
+ // GOOD: User-friendly messages
387
+ .WithMessage("Email validation failed. Please try again.");
388
+ ```
@@ -1,9 +1,27 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(dotnet *)",
5
- "Bash(dotnet-ef *)"
4
+ "Bash(dotnet run *)",
5
+ "Bash(dotnet build *)",
6
+ "Bash(dotnet test *)",
7
+ "Bash(dotnet watch *)",
8
+ "Bash(dotnet ef *)",
9
+ "Bash(dotnet add *)",
10
+ "Bash(dotnet restore)",
11
+ "Bash(dotnet format *)",
12
+ "Read",
13
+ "Edit",
14
+ "Write"
6
15
  ],
7
- "deny": []
16
+ "deny": [
17
+ "Bash(rm -rf *)",
18
+ "Read(appsettings.*.json)",
19
+ "Read(**/secrets.json)",
20
+ "Read(**/*.pfx)"
21
+ ]
22
+ },
23
+ "env": {
24
+ "ASPNETCORE_ENVIRONMENT": "Development",
25
+ "DOTNET_WATCH_RESTART_ON_RUDE_EDIT": "true"
8
26
  }
9
27
  }