agent-directives 0.2.1 → 0.4.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.
package/manifest.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "directive",
7
7
  "path": "directives/adaptive-routing.md",
8
8
  "description": "Selects the lightest safe workflow path, relevant directives/skills, and handoff requirements based on task intent, risk, and touched surfaces.",
9
- "version": "1.3.0",
9
+ "version": "1.6.0",
10
10
  "required": true,
11
11
  "category": "workflow",
12
12
  "tools": [
@@ -382,6 +382,139 @@
382
382
  "codex",
383
383
  "cursor"
384
384
  ]
385
+ },
386
+ {
387
+ "id": "angular-coding-style",
388
+ "type": "rule",
389
+ "path": "rules/angular/coding-style.md",
390
+ "description": "Concrete Angular coding-style patterns — signals, dependency injection with inject(), change detection, RxJS usage, and TypeScript strictness for Angular code.",
391
+ "version": "1.0.0",
392
+ "required": false,
393
+ "category": "angular",
394
+ "tools": [
395
+ "claude",
396
+ "copilot",
397
+ "codex",
398
+ "cursor"
399
+ ],
400
+ "applies_to": [
401
+ "src/app/**/*.ts",
402
+ "src/**/*.ts"
403
+ ]
404
+ },
405
+ {
406
+ "id": "angular-components-and-templates",
407
+ "type": "rule",
408
+ "path": "rules/angular/components-and-templates.md",
409
+ "description": "Concrete patterns for building modern Angular components, signal-based inputs/outputs, OnPush change detection, and v17+ control-flow templates.",
410
+ "version": "1.1.0",
411
+ "required": false,
412
+ "category": "angular",
413
+ "tools": [
414
+ "claude",
415
+ "copilot",
416
+ "codex",
417
+ "cursor"
418
+ ],
419
+ "applies_to": [
420
+ "src/app/**/*.component.ts",
421
+ "src/app/**/*.component.html",
422
+ "src/app/**/*.component.css",
423
+ "src/app/**/*.component.scss"
424
+ ]
425
+ },
426
+ {
427
+ "id": "angular-patterns",
428
+ "type": "rule",
429
+ "path": "rules/angular/patterns.md",
430
+ "description": "Concrete Angular application patterns — smart/dumb component split, service-layer ownership, routing/guards/resolvers, HTTP interceptors, and reactive state with signals or RxJS.",
431
+ "version": "1.0.0",
432
+ "required": false,
433
+ "category": "angular",
434
+ "tools": [
435
+ "claude",
436
+ "copilot",
437
+ "codex",
438
+ "cursor"
439
+ ],
440
+ "applies_to": [
441
+ "src/app/**/*.component.ts",
442
+ "src/app/**/*.component.html",
443
+ "src/app/**/*.service.ts",
444
+ "src/app/**/*.store.ts",
445
+ "src/app/**/*.routes.ts",
446
+ "src/app/**/*.guard.ts",
447
+ "src/app/**/*.resolver.ts",
448
+ "src/app/**/*.interceptor.ts"
449
+ ]
450
+ },
451
+ {
452
+ "id": "angular-project-structure",
453
+ "type": "rule",
454
+ "path": "rules/angular/project-structure.md",
455
+ "description": "Concrete Angular workspace, file-naming, feature-folder, and provider-bootstrapping standards for agents working in Angular applications.",
456
+ "version": "1.1.0",
457
+ "required": false,
458
+ "category": "angular",
459
+ "tools": [
460
+ "claude",
461
+ "copilot",
462
+ "codex",
463
+ "cursor"
464
+ ],
465
+ "applies_to": [
466
+ "angular.json",
467
+ "package.json",
468
+ "src/main.ts",
469
+ "src/app/**/*.ts",
470
+ "src/app/**/*.html"
471
+ ]
472
+ },
473
+ {
474
+ "id": "angular-security",
475
+ "type": "rule",
476
+ "path": "rules/angular/security.md",
477
+ "description": "Concrete Angular security rules — XSS prevention, HttpClient discipline, secret handling, route guards, and SSR safety.",
478
+ "version": "1.0.0",
479
+ "required": false,
480
+ "category": "angular",
481
+ "tools": [
482
+ "claude",
483
+ "copilot",
484
+ "codex",
485
+ "cursor"
486
+ ],
487
+ "applies_to": [
488
+ "src/app/**/*.component.ts",
489
+ "src/app/**/*.component.html",
490
+ "src/app/**/*.service.ts",
491
+ "src/app/**/*.interceptor.ts",
492
+ "src/app/**/*.guard.ts",
493
+ "src/app/**/*.routes.ts",
494
+ "src/environments/**/*.ts",
495
+ "src/**/*.server.ts",
496
+ "server.ts"
497
+ ]
498
+ },
499
+ {
500
+ "id": "angular-testing",
501
+ "type": "rule",
502
+ "path": "rules/angular/testing.md",
503
+ "description": "Concrete Angular testing patterns — TestBed configuration, signal-input harnesses, router and HTTP testing utilities, and behavior-first test design.",
504
+ "version": "1.1.0",
505
+ "required": false,
506
+ "category": "angular",
507
+ "tools": [
508
+ "claude",
509
+ "copilot",
510
+ "codex",
511
+ "cursor"
512
+ ],
513
+ "applies_to": [
514
+ "src/app/**/*.spec.ts",
515
+ "src/app/**/*.test.ts",
516
+ "src/**/*.spec.ts"
517
+ ]
385
518
  }
386
519
  ]
387
520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-directives",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Reusable agent directives, skills, and CLI tooling for AI coding workflows",
5
5
  "license": "MIT",
6
6
  "author": "Rob Simpson <rsimpson2@me.com>",
@@ -15,6 +15,7 @@
15
15
  "dist/",
16
16
  "directives/",
17
17
  "skills/",
18
+ "rules/",
18
19
  "templates/",
19
20
  "manifest.json",
20
21
  "README.md"
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: angular-coding-style
3
+ description: Concrete Angular coding-style patterns — signals, dependency injection with inject(), change detection, RxJS usage, and TypeScript strictness for Angular code.
4
+ version: 1.0.0
5
+ required: false
6
+ category: angular
7
+ tools:
8
+ - claude
9
+ - copilot
10
+ - codex
11
+ - cursor
12
+ source_urls:
13
+ - https://angular.dev/style-guide
14
+ - https://angular.dev/guide/signals
15
+ - https://angular.dev/guide/di
16
+ - https://angular.dev/guide/components/dependency-injection
17
+ - https://rxjs.dev/guide/operators
18
+ applies_to:
19
+ - src/app/**/*.ts
20
+ - src/**/*.ts
21
+ ---
22
+
23
+ # Angular Coding Style Rules
24
+
25
+ **Load when:** Writing or reviewing Angular TypeScript — components, services, directives, pipes, guards, resolvers, interceptors, or any code that uses Angular's DI / signals / RxJS surface.
26
+
27
+ ## Version Awareness
28
+
29
+ Many of the patterns below (`inject()`, signal primitives, `linkedSignal`, `resource`, functional guards/interceptors, `takeUntilDestroyed`) are version-gated. Check `package.json` / `ng version` and use the patterns the installed version supports — do not introduce a v18+ API into a v15 project.
30
+
31
+ ## Sources
32
+
33
+ - Angular Style Guide — https://angular.dev/style-guide
34
+ - Angular Signals Guide — https://angular.dev/guide/signals
35
+ - Angular Dependency Injection Guide — https://angular.dev/guide/di
36
+ - RxJS Operators — https://rxjs.dev/guide/operators
37
+
38
+ ## Rules
39
+
40
+ ### Dependency injection
41
+
42
+ Use `inject()` over constructor injection in components, services, guards, resolvers, interceptors, and pipes. Keep constructors empty (or remove them) so DI calls live at field declarations next to their use.
43
+
44
+ ```typescript
45
+ @Injectable({ providedIn: 'root' })
46
+ export class UserService {
47
+ private http = inject(HttpClient);
48
+ private router = inject(Router);
49
+ }
50
+ ```
51
+
52
+ ```typescript
53
+ // Avoid on new code — verbose and harder to tree-shake/refactor
54
+ constructor(private http: HttpClient, private router: Router) {}
55
+ ```
56
+
57
+ Use `InjectionToken` for non-class dependencies (config, env, capability flags):
58
+
59
+ ```typescript
60
+ export const API_URL = new InjectionToken<string>('API_URL');
61
+
62
+ // In providers:
63
+ { provide: API_URL, useValue: 'https://api.example.com' }
64
+
65
+ // At call site:
66
+ private apiUrl = inject(API_URL);
67
+ ```
68
+
69
+ - Prefer `providedIn: 'root'` for app-wide singletons. Scope a service to a component/route only when its lifecycle must follow that subtree.
70
+ - `inject()` runs in an injection context. Calls outside a constructor/field initializer/factory need `runInInjectionContext` — do not stash `inject` calls inside arbitrary functions.
71
+
72
+ ### Signals
73
+
74
+ Use signals for reactive state. Three primitives:
75
+
76
+ ```typescript
77
+ count = signal(0); // writable
78
+ doubled = computed(() => this.count() * 2); // derived, read-only
79
+ selectedItem = linkedSignal(() => this.items()[0]); // writable derived: resets with source, also user-settable
80
+ ```
81
+
82
+ - Never duplicate derived data in a separate writable signal updated through `effect()` — use `computed` (or `linkedSignal` if it must also be writable).
83
+ - Bridge Observables to signals with `toSignal(stream$, { initialValue: ... })`. Do not assign Observable values into signals from manual `.subscribe()` callbacks.
84
+ - For async fetching backed by signals, prefer `resource({ request, loader })` on v19+ projects:
85
+
86
+ ```typescript
87
+ userResource = resource({
88
+ request: () => ({ id: this.userId() }),
89
+ loader: ({ request }) => fetch(`/api/users/${request.id}`).then(r => r.json()),
90
+ });
91
+ // Access: userResource.value(), userResource.isLoading(), userResource.error(), userResource.reload()
92
+ ```
93
+
94
+ #### `effect()` usage
95
+
96
+ Reserve `effect()` for genuine side effects that must react to signal changes — logging, third-party DOM libraries, telemetry. Never use `effect()` to keep two signals in sync; that is what `computed` / `linkedSignal` are for.
97
+
98
+ ```typescript
99
+ // Correct — side effect that must react
100
+ effect(() => analytics.track('user_changed', { id: this.user().id }));
101
+
102
+ // Wrong — derived state, use computed
103
+ effect(() => this.fullName.set(`${this.first()} ${this.last()}`));
104
+ ```
105
+
106
+ For DOM work that must run after the view renders, use `afterRenderEffect` (or `afterNextRender` for one-shot work).
107
+
108
+ ### Change detection
109
+
110
+ - Default to `ChangeDetectionStrategy.OnPush` on every new component.
111
+ - Drive view updates via signals or the `async` pipe. Avoid `ChangeDetectorRef.markForCheck()` / `detectChanges()` unless you have a narrow, documented reason (e.g., third-party callback outside the zone).
112
+ - Consider zoneless change detection (`provideExperimentalZonelessChangeDetection()` / `provideZonelessChangeDetection()` on supporting versions) only as a project-level decision, never as a side effect of a feature change.
113
+
114
+ ### RxJS
115
+
116
+ When the project still uses RxJS for streams alongside (or instead of) signals:
117
+
118
+ | Operator | Use for |
119
+ | --- | --- |
120
+ | `switchMap` | Search, navigation, latest-wins — cancels prior inner stream |
121
+ | `mergeMap` | Independent parallel inner streams |
122
+ | `exhaustMap` | Form submissions, idempotency — ignores new emissions until current completes |
123
+ | `concatMap` | Ordered queueing |
124
+
125
+ - Always handle errors with `catchError`. Never let a long-lived stream die silently and stop emitting.
126
+ - Use `takeUntilDestroyed(this.destroyRef)` for manual subscriptions in components/directives. Do not roll a manual `ngOnDestroy` + `Subject<void>` + `takeUntil` on new code.
127
+ - Prefer the `async` pipe in templates over manual subscribe + assign. If the data is needed in component logic too, expose it as a signal via `toSignal`.
128
+
129
+ ```typescript
130
+ search$ = this.query$.pipe(
131
+ debounceTime(300),
132
+ distinctUntilChanged(),
133
+ switchMap(q => this.service.search(q).pipe(catchError(() => of([])))),
134
+ );
135
+ ```
136
+
137
+ ### TypeScript strictness
138
+
139
+ - Run with `strict: true` and `strictTemplates: true` (Angular compiler option). Do not weaken either to make a change compile.
140
+ - Type every public surface: component inputs/outputs, service method signatures, route data, interceptor return types.
141
+ - Treat external data as `unknown` at the boundary. Narrow it with a validator (Zod, io-ts, hand-rolled type guard) before binding it to typed signals or components.
142
+ - Do not use `any`, `as any`, or non-null `!` to silence template type errors — fix the type or narrow the value.
143
+
144
+ ### File-level style
145
+
146
+ - One artifact per file. Co-locate template (`.html`) and styles (`.scss`/`.css`) with the component class.
147
+ - Imports ordered: Angular core/common, third-party, project absolute (`@/...`), project relative (`./...`). Match the project's existing convention if it differs.
148
+ - Member order inside a class: signal fields → injected dependencies → inputs/outputs → other state → constructor (if any) → lifecycle hooks → public methods → private methods. Adjust to project style if it has a stronger local convention.
149
+
150
+ ## Anti-patterns to refuse
151
+
152
+ - Constructor-injected dependencies on a project that has already adopted `inject()`.
153
+ - `effect()` used to synchronize signals.
154
+ - Manual `.subscribe()` in components without `takeUntilDestroyed`, or with a hand-rolled `destroy$` subject.
155
+ - `any` introduced to make typed templates compile, or `as any` casts on `HttpClient` responses.
156
+ - Calling `inject()` outside an injection context (e.g., inside an arbitrary helper function not invoked from a factory).
157
+
158
+ ## Evidence
159
+
160
+ For style-aligned changes, run the project's lint and typecheck:
161
+
162
+ - `ng lint` (or the project's lint script) on touched files
163
+ - `tsc --noEmit` or `ng build` to verify typed templates and the public TypeScript surface
164
+ - Targeted tests covering the changed behavior (see `rules/angular/testing.md`)
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: angular-components-and-templates
3
+ description: Concrete patterns for building modern Angular components, signal-based inputs/outputs, OnPush change detection, and v17+ control-flow templates.
4
+ version: 1.1.0
5
+ required: false
6
+ category: angular
7
+ tools:
8
+ - claude
9
+ - copilot
10
+ - codex
11
+ - cursor
12
+ source_urls:
13
+ - https://angular.dev/style-guide
14
+ - https://angular.dev/guide/components
15
+ - https://angular.dev/guide/templates
16
+ - https://angular.dev/guide/signals
17
+ - https://angular.dev/guide/components/inputs
18
+ - https://angular.dev/guide/components/outputs
19
+ applies_to:
20
+ - src/app/**/*.component.ts
21
+ - src/app/**/*.component.html
22
+ - src/app/**/*.component.css
23
+ - src/app/**/*.component.scss
24
+ ---
25
+
26
+ # Angular Components and Templates Rules
27
+
28
+ **Load when:** Creating, changing, or reviewing Angular components, templates, component styles, inputs/outputs, lifecycle behavior, or view logic.
29
+
30
+ ## Version Awareness
31
+
32
+ Check the project's Angular version before writing code — APIs differ significantly between versions. Use `ng version` or inspect `package.json`. Match the project's existing component style first; do not migrate component styles as part of an unrelated change.
33
+
34
+ ## Sources
35
+
36
+ - Angular Style Guide — https://angular.dev/style-guide
37
+ - Angular Components Guide — https://angular.dev/guide/components
38
+ - Angular Templates Guide — https://angular.dev/guide/templates
39
+ - Angular Signals Guide — https://angular.dev/guide/signals
40
+
41
+ ## Rules
42
+
43
+ ### Component shape
44
+
45
+ - Prefer standalone components (v17+ default). Add `standalone: true` and declare template dependencies in `imports`. Do not mix standalone and NgModule registration for the same component.
46
+ - Default to `ChangeDetectionStrategy.OnPush` on all new components.
47
+ - Keep components focused on presentation and UI coordination. Move data access, business rules, and cross-component state to services or state primitives the project already uses.
48
+ - One artifact per file — `user-card.component.ts`, `user-card.component.html`, `user-card.component.scss`, `user-card.component.spec.ts`.
49
+
50
+ ```typescript
51
+ @Component({
52
+ selector: 'app-user-card',
53
+ standalone: true,
54
+ imports: [RouterLink, DatePipe],
55
+ templateUrl: './user-card.component.html',
56
+ styleUrl: './user-card.component.scss',
57
+ changeDetection: ChangeDetectionStrategy.OnPush,
58
+ })
59
+ export class UserCardComponent {
60
+ user = input.required<User>();
61
+ highlight = input(false, { transform: booleanAttribute });
62
+ select = output<string>();
63
+
64
+ onClick() {
65
+ this.select.emit(this.user().id);
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### Inputs and outputs
71
+
72
+ - On v17.1+ projects, prefer signal-based `input()` / `input.required()` / `output()` over decorators. Stay on `@Input()`/`@Output()` only if the project is uniformly decorator-based and the file you are editing already uses them.
73
+ - Type every input and output. Do not introduce `any` to make a binding compile — narrow the source data at the boundary instead.
74
+ - Use `input.required<T>()` when a parent must supply the value. Provide defaults (`input(false)`) only when the absence has a meaningful, documented behavior.
75
+ - Two-way binding uses `model()` (e.g., `value = model<string>('')`). Do not invent custom `xChange` outputs when `model()` covers the use case.
76
+
77
+ ### Templates (v17+ control flow)
78
+
79
+ Use the built-in block syntax. Always provide `track` in `@for`.
80
+
81
+ ```html
82
+ @if (isLoading()) {
83
+ <app-spinner />
84
+ } @else if (error()) {
85
+ <app-error [message]="error()" />
86
+ } @else {
87
+ @for (item of items(); track item.id) {
88
+ <app-item [item]="item" (select)="onSelect($event)" />
89
+ } @empty {
90
+ <p>No items found.</p>
91
+ }
92
+ }
93
+
94
+ @switch (status()) {
95
+ @case ('active') { <app-active /> }
96
+ @case ('pending') { <app-pending /> }
97
+ @default { <app-unknown /> }
98
+ }
99
+ ```
100
+
101
+ - Keep templates declarative. Move complex branching, transformations, or side effects into the component class, a `computed`, or a pure pipe.
102
+ - Call signals as functions in the template (`items()`, not `items`). Do not access `.value` on a signal — that is not the public API.
103
+ - Use the `async` pipe for Observables in templates rather than subscribing manually. Prefer converting to signals via `toSignal()` when possible.
104
+ - Use `@defer` for non-critical UI blocks (below the fold, behind interaction). Pair with `@placeholder`, `@loading`, and `@error` blocks.
105
+
106
+ ### Lifecycle and DOM access
107
+
108
+ - Use `inject()` over constructor injection. Keep constructors empty.
109
+ - For DOM work that must run after the view renders, prefer `afterRenderEffect` / `afterNextRender`. Do not reach into the DOM from `ngOnInit`.
110
+ - Use `viewChild()` / `viewChildren()` / `contentChild()` (signal queries) over the decorator forms on v17.2+ projects.
111
+ - Avoid `ngOnChanges` when an `input()` signal plus a `computed` or `effect` expresses the dependency directly.
112
+
113
+ ### Styles
114
+
115
+ - Keep `ViewEncapsulation.Emulated` (default). Use `ViewEncapsulation.None` only for design-system roots that intentionally bleed styles.
116
+ - Scope styles to the component file. Use `:host`, `:host-context`, and CSS custom properties for themeable values rather than global selectors.
117
+ - Preserve existing accessibility patterns. New interactive elements need keyboard support, programmatic labels, focus management, and semantic HTML appropriate to the component.
118
+
119
+ ### Change detection hygiene
120
+
121
+ - Signals and the `async` pipe drive change detection on `OnPush` components automatically. Do not reach for `ChangeDetectorRef.markForCheck()` or `detectChanges()` unless you have a documented, narrow reason.
122
+ - Do not mutate input objects in place when `OnPush` is in effect — produce new references.
123
+
124
+ ## Anti-patterns to refuse
125
+
126
+ - `@Component({ standalone: false })` on new components without an NgModule that already owns it.
127
+ - `ChangeDetectionStrategy.Default` on new components.
128
+ - Using `*ngIf` / `*ngFor` / `*ngSwitch` on projects that have adopted block syntax.
129
+ - Calling `.subscribe()` from a template, or storing computed/derived values in plain signals updated via `effect()`.
130
+ - Typing inputs/outputs as `any`, or bypassing the type system with `!` to silence template errors.
131
+
132
+ ## Evidence
133
+
134
+ For component behavior changes, include one of:
135
+
136
+ - updated component/unit tests,
137
+ - existing tests that already cover the changed behavior,
138
+ - or a stated reason tests are unavailable plus a lower-confidence fallback such as build/typecheck output (`ng build`, `tsc --noEmit`).