argos-harness 0.1.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/LICENSE +21 -0
- package/README.md +21 -0
- package/assets/agents/auditor.md +140 -0
- package/assets/agents/commit-pr-pilot.md +154 -0
- package/assets/agents/explorer.md +93 -0
- package/assets/agents/implementer.md +117 -0
- package/assets/agents/leader.md +149 -0
- package/assets/agents/researcher.md +89 -0
- package/assets/agents/review-readability.md +87 -0
- package/assets/agents/review-reliability.md +100 -0
- package/assets/agents/review-resilience.md +87 -0
- package/assets/agents/review-risk.md +87 -0
- package/assets/agents/reviewer.md +167 -0
- package/assets/agents/ticket-audit.md +129 -0
- package/assets/hooks/argos-guard-destructive.sh +127 -0
- package/assets/hooks/argos-quality-gate.sh +129 -0
- package/assets/managed/aterrizaje.md +24 -0
- package/assets/managed/formato-respuesta.md +21 -0
- package/assets/managed/identidad.md +48 -0
- package/assets/managed/operaciones-seguras.md +14 -0
- package/assets/managed/orquestacion.md +169 -0
- package/assets/output-styles/argos.md +71 -0
- package/assets/skills/ai-sdk-5/SKILL.md +230 -0
- package/assets/skills/angular/SKILL.md +19 -0
- package/assets/skills/angular/references/architecture.md +137 -0
- package/assets/skills/angular/references/core.md +197 -0
- package/assets/skills/angular/references/forms.md +115 -0
- package/assets/skills/angular/references/performance.md +124 -0
- package/assets/skills/apollo-client/SKILL.md +61 -0
- package/assets/skills/app-blueprint/SKILL.md +45 -0
- package/assets/skills/app-blueprint/assets/module-template.md +48 -0
- package/assets/skills/app-blueprint/assets/system-template.md +38 -0
- package/assets/skills/app-blueprint/references/workflow.md +101 -0
- package/assets/skills/app-builder/SKILL.md +43 -0
- package/assets/skills/app-builder/phases/0-product.md +58 -0
- package/assets/skills/app-builder/phases/1-scaffold.md +33 -0
- package/assets/skills/app-builder/phases/10-store.md +40 -0
- package/assets/skills/app-builder/phases/2-data.md +34 -0
- package/assets/skills/app-builder/phases/3-domain.md +33 -0
- package/assets/skills/app-builder/phases/4-ui-nav.md +32 -0
- package/assets/skills/app-builder/phases/5-identity.md +30 -0
- package/assets/skills/app-builder/phases/6-polish.md +34 -0
- package/assets/skills/app-builder/phases/7-brand.md +31 -0
- package/assets/skills/app-builder/phases/8-web.md +30 -0
- package/assets/skills/app-builder/phases/9-docs.md +31 -0
- package/assets/skills/app-ia/SKILL.md +54 -0
- package/assets/skills/astro/SKILL.md +39 -0
- package/assets/skills/axios/SKILL.md +61 -0
- package/assets/skills/branch-pr/SKILL.md +200 -0
- package/assets/skills/bullmq/SKILL.md +55 -0
- package/assets/skills/chained-pr/SKILL.md +48 -0
- package/assets/skills/chained-pr/references/chaining-details.md +99 -0
- package/assets/skills/cognitive-doc-design/SKILL.md +81 -0
- package/assets/skills/comment-writer/SKILL.md +74 -0
- package/assets/skills/dashboard-ia/SKILL.md +54 -0
- package/assets/skills/django-drf/SKILL.md +180 -0
- package/assets/skills/go-testing/SKILL.md +47 -0
- package/assets/skills/go-testing/references/examples.md +89 -0
- package/assets/skills/issue-creation/SKILL.md +223 -0
- package/assets/skills/jira-epic/SKILL.md +306 -0
- package/assets/skills/jira-task/SKILL.md +382 -0
- package/assets/skills/judgment-day/SKILL.md +52 -0
- package/assets/skills/judgment-day/references/prompts-and-formats.md +98 -0
- package/assets/skills/lightsail-deploy/SKILL.md +44 -0
- package/assets/skills/lightsail-deploy/references/runbook.md +102 -0
- package/assets/skills/loop-back-debug/SKILL.md +102 -0
- package/assets/skills/mantine-form/SKILL.md +57 -0
- package/assets/skills/mongoose/SKILL.md +66 -0
- package/assets/skills/nextjs-15/SKILL.md +144 -0
- package/assets/skills/not-boring-mobile/SKILL.md +43 -0
- package/assets/skills/not-boring-mobile/references/not-boring-playbook.md +65 -0
- package/assets/skills/playwright/SKILL.md +315 -0
- package/assets/skills/pr-comments/SKILL.md +93 -0
- package/assets/skills/pr-create/SKILL.md +64 -0
- package/assets/skills/promo-video/SKILL.md +52 -0
- package/assets/skills/promo-video/assets/package.template.json +22 -0
- package/assets/skills/promo-video/assets/promo.template.tsx +469 -0
- package/assets/skills/promo-video/assets/theme.template.ts +27 -0
- package/assets/skills/promo-video/references/pipeline.md +119 -0
- package/assets/skills/promo-video-web/SKILL.md +51 -0
- package/assets/skills/promo-video-web/assets/browser-promo.template.tsx +385 -0
- package/assets/skills/promo-video-web/assets/capture.template.ts +70 -0
- package/assets/skills/promo-video-web/assets/package.template.json +26 -0
- package/assets/skills/promo-video-web/references/pipeline.md +84 -0
- package/assets/skills/pytest/SKILL.md +180 -0
- package/assets/skills/react-19/SKILL.md +118 -0
- package/assets/skills/react-hook-form/SKILL.md +59 -0
- package/assets/skills/react-router/SKILL.md +60 -0
- package/assets/skills/redux-toolkit/SKILL.md +60 -0
- package/assets/skills/review-diff/SKILL.md +101 -0
- package/assets/skills/ship-docs/SKILL.md +45 -0
- package/assets/skills/ship-docs/references/ship-docs-playbook.md +31 -0
- package/assets/skills/skill-creator/SKILL.md +97 -0
- package/assets/skills/skill-creator/assets/SKILL-TEMPLATE.md +68 -0
- package/assets/skills/skill-creator/references/skill-style-guide.md +79 -0
- package/assets/skills/skill-improver/SKILL.md +50 -0
- package/assets/skills/skill-improver/references/skill-style-guide.md +79 -0
- package/assets/skills/socketio/SKILL.md +58 -0
- package/assets/skills/spec-bootstrap/SKILL.md +62 -0
- package/assets/skills/store-ship/SKILL.md +52 -0
- package/assets/skills/store-ship/assets/android-supply.template.md +22 -0
- package/assets/skills/store-ship/assets/eas.template.json +32 -0
- package/assets/skills/store-ship/assets/maestro-flow.template.yaml +27 -0
- package/assets/skills/store-ship/assets/store.config.template.json +28 -0
- package/assets/skills/store-ship/references/pipeline.md +198 -0
- package/assets/skills/stripe/SKILL.md +83 -0
- package/assets/skills/tailwind-4/SKILL.md +193 -0
- package/assets/skills/tamagui/SKILL.md +60 -0
- package/assets/skills/tanstack-query/SKILL.md +58 -0
- package/assets/skills/ticket-intake/SKILL.md +55 -0
- package/assets/skills/typescript/SKILL.md +134 -0
- package/assets/skills/verify-before-done/SKILL.md +111 -0
- package/assets/skills/webapp-rebuilder/SKILL.md +48 -0
- package/assets/skills/webapp-rebuilder/assets/charter-template.md +46 -0
- package/assets/skills/webapp-rebuilder/references/workflow.md +47 -0
- package/assets/skills/winston-logging/SKILL.md +61 -0
- package/assets/skills/work-unit-commits/SKILL.md +84 -0
- package/assets/skills/zod-4/SKILL.md +210 -0
- package/assets/skills/zustand-5/SKILL.md +216 -0
- package/bin/argos.js +6 -0
- package/dist/commands/adopt.d.ts +35 -0
- package/dist/commands/adopt.d.ts.map +1 -0
- package/dist/commands/adopt.js +347 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/doctor.d.ts +20 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +478 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +32 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +358 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/remove.d.ts +62 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +487 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/workspace.d.ts +73 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +354 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/assets.d.ts +29 -0
- package/dist/lib/assets.d.ts.map +1 -0
- package/dist/lib/assets.js +57 -0
- package/dist/lib/assets.js.map +1 -0
- package/dist/lib/atomic-write.d.ts +17 -0
- package/dist/lib/atomic-write.d.ts.map +1 -0
- package/dist/lib/atomic-write.js +41 -0
- package/dist/lib/atomic-write.js.map +1 -0
- package/dist/lib/backup.d.ts +11 -0
- package/dist/lib/backup.d.ts.map +1 -0
- package/dist/lib/backup.js +42 -0
- package/dist/lib/backup.js.map +1 -0
- package/dist/lib/config.d.ts +36 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +52 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/detect.d.ts +58 -0
- package/dist/lib/detect.d.ts.map +1 -0
- package/dist/lib/detect.js +330 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/ficha.d.ts +10 -0
- package/dist/lib/ficha.d.ts.map +1 -0
- package/dist/lib/ficha.js +38 -0
- package/dist/lib/ficha.js.map +1 -0
- package/dist/lib/git.d.ts +27 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +79 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/managed-files.d.ts +35 -0
- package/dist/lib/managed-files.d.ts.map +1 -0
- package/dist/lib/managed-files.js +97 -0
- package/dist/lib/managed-files.js.map +1 -0
- package/dist/lib/markers.d.ts +64 -0
- package/dist/lib/markers.d.ts.map +1 -0
- package/dist/lib/markers.js +157 -0
- package/dist/lib/markers.js.map +1 -0
- package/dist/lib/navori-import.d.ts +42 -0
- package/dist/lib/navori-import.d.ts.map +1 -0
- package/dist/lib/navori-import.js +65 -0
- package/dist/lib/navori-import.js.map +1 -0
- package/dist/lib/openclaw-agents.d.ts +53 -0
- package/dist/lib/openclaw-agents.d.ts.map +1 -0
- package/dist/lib/openclaw-agents.js +118 -0
- package/dist/lib/openclaw-agents.js.map +1 -0
- package/dist/lib/package-root.d.ts +11 -0
- package/dist/lib/package-root.d.ts.map +1 -0
- package/dist/lib/package-root.js +23 -0
- package/dist/lib/package-root.js.map +1 -0
- package/dist/lib/paths.d.ts +11 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/settings-merge.d.ts +125 -0
- package/dist/lib/settings-merge.d.ts.map +1 -0
- package/dist/lib/settings-merge.js +373 -0
- package/dist/lib/settings-merge.js.map +1 -0
- package/dist/lib/version.d.ts +3 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +13 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/which.d.ts +8 -0
- package/dist/lib/which.d.ts.map +1 -0
- package/dist/lib/which.js +30 -0
- package/dist/lib/which.js.map +1 -0
- package/dist/lib/workspaces.d.ts +133 -0
- package/dist/lib/workspaces.d.ts.map +1 -0
- package/dist/lib/workspaces.js +241 -0
- package/dist/lib/workspaces.js.map +1 -0
- package/dist/lib/zod-messages.d.ts +4 -0
- package/dist/lib/zod-messages.d.ts.map +1 -0
- package/dist/lib/zod-messages.js +28 -0
- package/dist/lib/zod-messages.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
## Standalone Components (REQUIRED)
|
|
2
|
+
|
|
3
|
+
Components are standalone by default. Do NOT set `standalone: true`.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'app-user',
|
|
8
|
+
imports: [CommonModule],
|
|
9
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
10
|
+
template: `...`
|
|
11
|
+
})
|
|
12
|
+
export class UserComponent {}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Input/Output Functions (REQUIRED)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// ✅ ALWAYS: Function-based
|
|
21
|
+
readonly user = input.required<User>();
|
|
22
|
+
readonly disabled = input(false);
|
|
23
|
+
readonly selected = output<User>();
|
|
24
|
+
readonly checked = model(false); // Two-way binding
|
|
25
|
+
|
|
26
|
+
// ❌ NEVER: Decorators
|
|
27
|
+
@Input() user: User;
|
|
28
|
+
@Output() selected = new EventEmitter<User>();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Signals for State (REQUIRED)
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
readonly count = signal(0);
|
|
37
|
+
readonly doubled = computed(() => this.count() * 2);
|
|
38
|
+
|
|
39
|
+
// Update
|
|
40
|
+
this.count.set(5);
|
|
41
|
+
this.count.update(prev => prev + 1);
|
|
42
|
+
|
|
43
|
+
// Side effects
|
|
44
|
+
effect(() => localStorage.setItem('count', this.count().toString()));
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## NO Lifecycle Hooks (REQUIRED)
|
|
50
|
+
|
|
51
|
+
Signals replace lifecycle hooks. Do NOT use `ngOnInit`, `ngOnChanges`, `ngOnDestroy`.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// ❌ NEVER: Lifecycle hooks
|
|
55
|
+
ngOnInit() {
|
|
56
|
+
this.loadUser();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ngOnChanges(changes: SimpleChanges) {
|
|
60
|
+
if (changes['userId']) {
|
|
61
|
+
this.loadUser();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ✅ ALWAYS: Signals + effect
|
|
66
|
+
readonly userId = input.required<string>();
|
|
67
|
+
readonly user = signal<User | null>(null);
|
|
68
|
+
|
|
69
|
+
private userEffect = effect(() => {
|
|
70
|
+
// Runs automatically when userId() changes
|
|
71
|
+
this.loadUser(this.userId());
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ✅ For derived data, use computed
|
|
75
|
+
readonly displayName = computed(() => this.user()?.name ?? 'Guest');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### When to Use What
|
|
79
|
+
|
|
80
|
+
| Need | Use |
|
|
81
|
+
|------|-----|
|
|
82
|
+
| React to input changes | `effect()` watching the input signal |
|
|
83
|
+
| Derived/computed state | `computed()` |
|
|
84
|
+
| Side effects (API calls, localStorage) | `effect()` |
|
|
85
|
+
| Cleanup on destroy | `DestroyRef` + `inject()` |
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Cleanup example
|
|
89
|
+
private readonly destroyRef = inject(DestroyRef);
|
|
90
|
+
|
|
91
|
+
constructor() {
|
|
92
|
+
const subscription = someObservable$.subscribe();
|
|
93
|
+
this.destroyRef.onDestroy(() => subscription.unsubscribe());
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## inject() Over Constructor (REQUIRED)
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// ✅ ALWAYS
|
|
103
|
+
private readonly http = inject(HttpClient);
|
|
104
|
+
|
|
105
|
+
// ❌ NEVER
|
|
106
|
+
constructor(private http: HttpClient) {}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Native Control Flow (REQUIRED)
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
@if (loading()) {
|
|
115
|
+
<spinner />
|
|
116
|
+
} @else {
|
|
117
|
+
@for (item of items(); track item.id) {
|
|
118
|
+
<item-card [data]="item" />
|
|
119
|
+
} @empty {
|
|
120
|
+
<p>No items</p>
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@switch (status()) {
|
|
125
|
+
@case ('active') { <span>Active</span> }
|
|
126
|
+
@default { <span>Unknown</span> }
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## RxJS - Only When Needed
|
|
133
|
+
|
|
134
|
+
Signals are the default. Use RxJS ONLY for complex async operations.
|
|
135
|
+
|
|
136
|
+
| Use Signals | Use RxJS |
|
|
137
|
+
|-------------|----------|
|
|
138
|
+
| Component state | Combining multiple streams |
|
|
139
|
+
| Derived values | Debounce/throttle |
|
|
140
|
+
| Simple async (single API call) | Race conditions |
|
|
141
|
+
| Input/Output | WebSockets, real-time |
|
|
142
|
+
| | Complex error retry logic |
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// ✅ Simple API call - use signals
|
|
146
|
+
readonly user = signal<User | null>(null);
|
|
147
|
+
readonly loading = signal(false);
|
|
148
|
+
|
|
149
|
+
async loadUser(id: string) {
|
|
150
|
+
this.loading.set(true);
|
|
151
|
+
this.user.set(await firstValueFrom(this.http.get<User>(`/api/users/${id}`)));
|
|
152
|
+
this.loading.set(false);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ✅ Complex stream - use RxJS
|
|
156
|
+
readonly searchResults$ = this.searchTerm$.pipe(
|
|
157
|
+
debounceTime(300),
|
|
158
|
+
distinctUntilChanged(),
|
|
159
|
+
switchMap(term => this.http.get<Results>(`/api/search?q=${term}`))
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Convert to signal when needed in template
|
|
163
|
+
readonly searchResults = toSignal(this.searchResults$, { initialValue: [] });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Zoneless Angular (REQUIRED)
|
|
169
|
+
|
|
170
|
+
Angular is zoneless. Use `provideZonelessChangeDetection()`.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
bootstrapApplication(AppComponent, {
|
|
174
|
+
providers: [provideZonelessChangeDetection()]
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Remove ZoneJS:
|
|
179
|
+
```bash
|
|
180
|
+
npm uninstall zone.js
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Remove from `angular.json` polyfills: `zone.js` and `zone.js/testing`.
|
|
184
|
+
|
|
185
|
+
### Zoneless Requirements
|
|
186
|
+
- Use `OnPush` change detection
|
|
187
|
+
- Use signals for state (auto-notifies Angular)
|
|
188
|
+
- Use `AsyncPipe` for observables
|
|
189
|
+
- Use `markForCheck()` when needed
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Resources
|
|
194
|
+
|
|
195
|
+
- https://angular.dev/guide/signals
|
|
196
|
+
- https://angular.dev/guide/templates/control-flow
|
|
197
|
+
- https://angular.dev/guide/zoneless
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
## When to Use What
|
|
2
|
+
|
|
3
|
+
| Use Case | Recommendation |
|
|
4
|
+
|----------|----------------|
|
|
5
|
+
| New apps with signals | Signal Forms (experimental) |
|
|
6
|
+
| Production apps | Reactive Forms |
|
|
7
|
+
| Simple forms | Template-driven |
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Signal Forms (v21+, experimental)
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { form, FormField, required, email } from '@angular/forms/signals';
|
|
15
|
+
|
|
16
|
+
@Component({
|
|
17
|
+
imports: [FormField],
|
|
18
|
+
template: `
|
|
19
|
+
<form>
|
|
20
|
+
<input [formField]="emailField" type="email" />
|
|
21
|
+
<input [formField]="passwordField" type="password" />
|
|
22
|
+
<button (click)="submit()">Login</button>
|
|
23
|
+
</form>
|
|
24
|
+
`
|
|
25
|
+
})
|
|
26
|
+
export class LoginComponent {
|
|
27
|
+
readonly loginForm = form({
|
|
28
|
+
email: ['', [required, email]],
|
|
29
|
+
password: ['', required]
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
readonly emailField = this.loginForm.controls.email;
|
|
33
|
+
readonly passwordField = this.loginForm.controls.password;
|
|
34
|
+
|
|
35
|
+
submit() {
|
|
36
|
+
if (this.loginForm.valid()) {
|
|
37
|
+
const values = this.loginForm.value();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Signal Forms Benefits
|
|
44
|
+
- Automatic two-way binding
|
|
45
|
+
- Type-safe field access
|
|
46
|
+
- Schema-based validation
|
|
47
|
+
- Built on signals
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Reactive Forms (production)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
55
|
+
|
|
56
|
+
@Component({
|
|
57
|
+
imports: [ReactiveFormsModule],
|
|
58
|
+
template: `
|
|
59
|
+
<form [formGroup]="form" (ngSubmit)="submit()">
|
|
60
|
+
<input formControlName="email" type="email" />
|
|
61
|
+
<input formControlName="password" type="password" />
|
|
62
|
+
<button type="submit" [disabled]="form.invalid">Login</button>
|
|
63
|
+
</form>
|
|
64
|
+
`
|
|
65
|
+
})
|
|
66
|
+
export class LoginComponent {
|
|
67
|
+
private readonly fb = inject(FormBuilder);
|
|
68
|
+
|
|
69
|
+
form = this.fb.nonNullable.group({
|
|
70
|
+
email: ['', [Validators.required, Validators.email]],
|
|
71
|
+
password: ['', [Validators.required, Validators.minLength(8)]],
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
submit() {
|
|
75
|
+
if (this.form.valid) {
|
|
76
|
+
const { email, password } = this.form.getRawValue();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Key Points
|
|
83
|
+
- ALWAYS use `fb.nonNullable.group()` for type safety
|
|
84
|
+
- Use `getRawValue()` to get typed values
|
|
85
|
+
- Reactive Forms are synchronous (easier to test)
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Nested Forms & FormArray
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
form = this.fb.nonNullable.group({
|
|
93
|
+
name: [''],
|
|
94
|
+
address: this.fb.group({
|
|
95
|
+
street: [''],
|
|
96
|
+
city: [''],
|
|
97
|
+
}),
|
|
98
|
+
phones: this.fb.array([this.fb.control('')]),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
get phones() {
|
|
102
|
+
return this.form.get('phones') as FormArray;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
addPhone() {
|
|
106
|
+
this.phones.push(this.fb.control(''));
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Resources
|
|
113
|
+
|
|
114
|
+
- https://angular.dev/guide/forms/signals/overview
|
|
115
|
+
- https://angular.dev/guide/forms/reactive-forms
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
## NgOptimizedImage (REQUIRED for images)
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
import { NgOptimizedImage } from '@angular/common';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
imports: [NgOptimizedImage],
|
|
8
|
+
template: `
|
|
9
|
+
<!-- LCP image: add priority -->
|
|
10
|
+
<img ngSrc="hero.jpg" width="800" height="400" priority>
|
|
11
|
+
|
|
12
|
+
<!-- Regular: lazy loaded by default -->
|
|
13
|
+
<img ngSrc="thumb.jpg" width="200" height="200">
|
|
14
|
+
|
|
15
|
+
<!-- Fill mode (parent needs position: relative) -->
|
|
16
|
+
<img ngSrc="bg.jpg" fill>
|
|
17
|
+
|
|
18
|
+
<!-- With placeholder -->
|
|
19
|
+
<img ngSrc="photo.jpg" width="400" height="300" placeholder>
|
|
20
|
+
`
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Rules
|
|
25
|
+
- ALWAYS set `width` and `height` (or `fill`)
|
|
26
|
+
- Add `priority` to LCP (Largest Contentful Paint) image
|
|
27
|
+
- Use `ngSrc` not `src`
|
|
28
|
+
- Parent of `fill` image must have `position: relative/fixed/absolute`
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## @defer - Lazy Components
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
@defer (on viewport) {
|
|
36
|
+
<heavy-component />
|
|
37
|
+
} @placeholder {
|
|
38
|
+
<p>Placeholder shown immediately</p>
|
|
39
|
+
} @loading (minimum 200ms) {
|
|
40
|
+
<spinner />
|
|
41
|
+
} @error {
|
|
42
|
+
<p>Failed to load</p>
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Triggers
|
|
47
|
+
|
|
48
|
+
| Trigger | When to Use |
|
|
49
|
+
|---------|-------------|
|
|
50
|
+
| `on viewport` | Below the fold content |
|
|
51
|
+
| `on interaction` | Load on click/focus/hover |
|
|
52
|
+
| `on idle` | Load when browser is idle |
|
|
53
|
+
| `on timer(500ms)` | Load after delay |
|
|
54
|
+
| `when condition` | Load when expression is true |
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<!-- Multiple triggers -->
|
|
58
|
+
@defer (on viewport; on interaction) {
|
|
59
|
+
<comments />
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
<!-- Conditional -->
|
|
63
|
+
@defer (when showComments()) {
|
|
64
|
+
<comments />
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Lazy Routes
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// Single component
|
|
74
|
+
{
|
|
75
|
+
path: 'admin',
|
|
76
|
+
loadComponent: () => import('./features/admin/admin').then(c => c.AdminComponent)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Feature with child routes
|
|
80
|
+
{
|
|
81
|
+
path: 'users',
|
|
82
|
+
loadChildren: () => import('./features/users/routes').then(m => m.USERS_ROUTES)
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## SSR & Hydration
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
bootstrapApplication(AppComponent, {
|
|
92
|
+
providers: [
|
|
93
|
+
provideClientHydration()
|
|
94
|
+
]
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Scenario | Use |
|
|
99
|
+
|----------|-----|
|
|
100
|
+
| SEO critical (blog, e-commerce) | SSR |
|
|
101
|
+
| Dashboard/Admin | CSR |
|
|
102
|
+
| Static marketing site | SSG/Prerender |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Slow Computations
|
|
107
|
+
|
|
108
|
+
| Solution | When |
|
|
109
|
+
|----------|------|
|
|
110
|
+
| Optimize algorithm | First choice always |
|
|
111
|
+
| Pure pipes | Cache single result |
|
|
112
|
+
| Memoization | Cache multiple results |
|
|
113
|
+
| `computed()` | Derived signal state |
|
|
114
|
+
|
|
115
|
+
**NEVER** trigger reflows/repaints in lifecycle hooks (`ngOnInit`, `ngAfterViewInit`).
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Resources
|
|
120
|
+
|
|
121
|
+
- https://angular.dev/guide/image-optimization
|
|
122
|
+
- https://angular.dev/guide/defer
|
|
123
|
+
- https://angular.dev/best-practices/runtime-performance
|
|
124
|
+
- https://angular.dev/guide/ssr
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apollo-client
|
|
3
|
+
description: GraphQL con Apollo Client — hooks, fetchPolicy, normalización de caché y actualización tras mutaciones. Trigger: al escribir queries/mutations, configurar la caché o los links.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Apollo Client — el patrón canónico
|
|
7
|
+
|
|
8
|
+
Lecturas declarativas con hooks, caché **normalizada por id**, y la UI se mantiene en sync actualizando la caché tras cada mutación. Los concerns de red/auth viven en los links, no en los componentes.
|
|
9
|
+
|
|
10
|
+
## Cuándo usar este skill
|
|
11
|
+
|
|
12
|
+
Al escribir una query/mutation, configurar `InMemoryCache`/`typePolicies`, o la cadena de `links`.
|
|
13
|
+
|
|
14
|
+
## Hooks y aislamiento
|
|
15
|
+
|
|
16
|
+
`useQuery` (lectura al montar), `useLazyQuery` (bajo demanda, retorna `execute`), `useMutation` (retorna `[mutate, { data, loading, error }]`). Aísla los hooks en una capa (hook + adapter): el componente recibe un **modelo de dominio**, no el shape crudo de GraphQL.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
export function useReport(id: string) {
|
|
20
|
+
const { data, loading, error } = useGetReportQuery({ variables: { id }, fetchPolicy: 'cache-first' });
|
|
21
|
+
return { report: data?.report ? adaptReport(data.report) : null, loading, error };
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## fetchPolicy según el dato
|
|
26
|
+
|
|
27
|
+
- `cache-first` (default) — catálogos/detalles ya traídos por una lista.
|
|
28
|
+
- `cache-and-network` — feeds que cambian seguido (render instantáneo + refresh).
|
|
29
|
+
- `network-only` — sesión/bootstrap, datos críticos.
|
|
30
|
+
- Evita `no-cache` salvo PII estricta que no deba tocar disco.
|
|
31
|
+
|
|
32
|
+
## Normalización de caché
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const cache = new InMemoryCache({ typePolicies: { Report: { keyFields: ['id'] } } });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Con `keyFields`, Apollo identifica entidades por id y deduplica/actualiza solo. Sin normalización, las listas y detalles se desincronizan.
|
|
39
|
+
|
|
40
|
+
## Reglas duras
|
|
41
|
+
|
|
42
|
+
1. **Tras una mutation, actualiza la caché:** `update(cache, { data })` (`cache.modify`/`evict`/`writeQuery`) o `refetchQueries`. Nunca dejes la UI desincronizada.
|
|
43
|
+
2. **`optimisticResponse`** para UI instantánea (resultado temporal con `__typename` + id ficticio); `update` reconcilia al llegar la respuesta real.
|
|
44
|
+
3. **No over-fetch:** pide solo los campos que el componente usa; apóyate en **fragments con colocation** (el fragmento junto al componente que lo consume). Regenera tipos (codegen) tras editar `.graphql`.
|
|
45
|
+
4. **Maneja `loading` y `error` siempre.** Separa error de red (banner genérico, resuelto en un `errorLink`) de error de negocio (`graphQLErrors`, copy según `extensions.code`).
|
|
46
|
+
5. **Paginación** con `fetchMore` + `updateQuery`, o `relayStylePagination`/merge en `typePolicies`.
|
|
47
|
+
6. Red/auth/upload en la cadena de **links** (auth → error → upload), no en cada componente.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const [createReport] = useCreateReportMutation({
|
|
51
|
+
optimisticResponse: { createReport: { __typename: 'Report', id: 'temp', ...fields } },
|
|
52
|
+
update(cache) { cache.evict({ fieldName: 'reports' }); }, // invalida la lista
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Antes de declarar listo
|
|
57
|
+
|
|
58
|
+
- Hooks aislados en capa (hook + adapter); el componente ve el modelo de dominio.
|
|
59
|
+
- Caché normalizada por `keyFields`; mutaciones actualizan/invalidan la caché.
|
|
60
|
+
- `fetchPolicy` elegido por tipo de dato; `loading`/`error` manejados.
|
|
61
|
+
- El quality gate del repo (`qualityGate.fast` en `argos.config.json`) en verde.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: app-blueprint
|
|
3
|
+
description: Generate reconstruction-grade docs of an app — business rules, endpoints, routes, screens, contracts. Trigger: app blueprint, appblueprint, reverse-spec, mapear app, map app for reconstruction.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Activation Contract
|
|
7
|
+
|
|
8
|
+
Activate on `/app-blueprint <target>` or requests to map/document an app well enough to rebuild it without losing logic or features. Targets: `<repo-dir>` (one repo), `all` (every repo in the workspace root minus user exclusions), `system` (cross-repo synthesis from existing blueprints).
|
|
9
|
+
|
|
10
|
+
## Hard Rules
|
|
11
|
+
|
|
12
|
+
- Output goes to `<workspace-root>/blueprint/<repo>/`. All docs in English.
|
|
13
|
+
- Phase 0 inventory is mandatory and script-only (`rg`/`fd`, zero agent reading). `_inventory.json` is the coverage contract for the whole run.
|
|
14
|
+
- Module agents write their doc file directly to disk and return ONE summary line. Never pipe doc content through the orchestrator context.
|
|
15
|
+
- Business rules are numbered, testable statements with `file:line` refs. No prose-only rules.
|
|
16
|
+
- Partition modules by business domain, never by folder.
|
|
17
|
+
- The run is not done until the audit maps every inventory item (route, endpoint, model, page, slice, job) to a doc section, or lists it in `_gaps.md`.
|
|
18
|
+
|
|
19
|
+
## Decision Gates
|
|
20
|
+
|
|
21
|
+
| Target | Action |
|
|
22
|
+
|--------|--------|
|
|
23
|
+
| Single repo | Phases 0-2 on that repo per `references/workflow.md` |
|
|
24
|
+
| `all` | Phases 0-2 per repo, one repo at a time |
|
|
25
|
+
| `system` | Read existing blueprints only (no source code), cross-check contracts, write `SYSTEM.md` |
|
|
26
|
+
| Frontend stack detected | Module docs use frontend sections of the template |
|
|
27
|
+
| Backend stack detected | Module docs use backend sections of the template |
|
|
28
|
+
|
|
29
|
+
## Execution Steps
|
|
30
|
+
|
|
31
|
+
1. Read `references/workflow.md` in full before acting.
|
|
32
|
+
2. Phase 0: detect stack, run the inventory command cookbook, write `_inventory.json`.
|
|
33
|
+
3. Phase 1: partition into 6-12 domain modules; spawn all module agents in parallel (Agent tool, single message, `model: sonnet`), each pointed at `assets/module-template.md`.
|
|
34
|
+
4. Phase 2: audit coverage against `_inventory.json`; spawn gap agents for unmapped items; write the repo `README.md`.
|
|
35
|
+
5. `system` mode: cross-check consumed vs exposed endpoints across blueprints; write `SYSTEM.md`.
|
|
36
|
+
|
|
37
|
+
## Output Contract
|
|
38
|
+
|
|
39
|
+
Per repo: `blueprint/<repo>/{README.md, _inventory.json, <module>.md...}` plus `_gaps.md` if items remain unresolved. System mode: `blueprint/SYSTEM.md`. Final report to user: files written, coverage count (mapped/total), gaps.
|
|
40
|
+
|
|
41
|
+
## References
|
|
42
|
+
|
|
43
|
+
- `references/workflow.md` — phase details, inventory command cookbook, agent prompt templates, audit rules.
|
|
44
|
+
- `assets/module-template.md` — module doc template (frontend/backend sections).
|
|
45
|
+
- `assets/system-template.md` — SYSTEM.md skeleton with contract table.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Module: {name}
|
|
2
|
+
|
|
3
|
+
**Repo:** {repo} · **Kind:** {frontend|backend} · **Purpose:** one sentence.
|
|
4
|
+
|
|
5
|
+
## Screens & Routes (frontend) / Endpoints (backend)
|
|
6
|
+
|
|
7
|
+
Frontend:
|
|
8
|
+
|
|
9
|
+
| Route | Screen/Page | Guard | Purpose |
|
|
10
|
+
|-------|-------------|-------|---------|
|
|
11
|
+
|
|
12
|
+
Backend:
|
|
13
|
+
|
|
14
|
+
| Method | Path | Auth | Request | Response | Errors |
|
|
15
|
+
|--------|------|------|---------|----------|--------|
|
|
16
|
+
|
|
17
|
+
## Business Rules
|
|
18
|
+
|
|
19
|
+
Numbered, testable, with source refs. Capture validations, conditionals, permission checks, status transitions, limits, and defaults.
|
|
20
|
+
|
|
21
|
+
- **BR-1:** A session cannot be booked when the coach has no connected calendar. (`src/services/x.js:42`)
|
|
22
|
+
- **BR-2:** ...
|
|
23
|
+
|
|
24
|
+
## Data
|
|
25
|
+
|
|
26
|
+
Frontend: state used (slices/stores), key entities and their shapes as consumed.
|
|
27
|
+
Backend: models/schemas with fields, types, constraints, indexes, relations.
|
|
28
|
+
|
|
29
|
+
## API Calls Consumed (frontend) / Dependencies (backend)
|
|
30
|
+
|
|
31
|
+
Frontend:
|
|
32
|
+
|
|
33
|
+
| Method | URL | Trigger (screen/action) | Payload | Response used for |
|
|
34
|
+
|--------|-----|-------------------------|---------|-------------------|
|
|
35
|
+
|
|
36
|
+
Backend: services/DBs/queues this module calls, with purpose.
|
|
37
|
+
|
|
38
|
+
## Side Effects
|
|
39
|
+
|
|
40
|
+
Emails, notifications, jobs enqueued, events emitted, external API writes — with trigger condition and source ref.
|
|
41
|
+
|
|
42
|
+
## Edge Cases & Gotchas
|
|
43
|
+
|
|
44
|
+
Non-obvious behavior a rebuilder would miss: race handling, retries, timezone logic, legacy quirks, feature flags.
|
|
45
|
+
|
|
46
|
+
## Files Covered
|
|
47
|
+
|
|
48
|
+
Every assigned file, one per line. Required — the audit uses this list.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# SYSTEM — {workspace name}
|
|
2
|
+
|
|
3
|
+
**Purpose:** one paragraph — what the whole system does for whom.
|
|
4
|
+
|
|
5
|
+
## Repo Map
|
|
6
|
+
|
|
7
|
+
| Repo | Kind | Role | Blueprint |
|
|
8
|
+
|------|------|------|-----------|
|
|
9
|
+
|
|
10
|
+
## Cross-Service Flows
|
|
11
|
+
|
|
12
|
+
Trace the 3-6 core user journeys end to end. For each: numbered steps naming screen → endpoint → service → side effects.
|
|
13
|
+
|
|
14
|
+
### Flow: {e.g. Coachee books a session}
|
|
15
|
+
|
|
16
|
+
1. ...
|
|
17
|
+
|
|
18
|
+
## Contract Table
|
|
19
|
+
|
|
20
|
+
Every HTTP call consumed vs the endpoint that exposes it.
|
|
21
|
+
|
|
22
|
+
| Consumer | Method | Path | Exposed by | Status |
|
|
23
|
+
|----------|--------|------|------------|--------|
|
|
24
|
+
| bonum-webapp | POST | /sessions | services--sessions | OK / MISSING / ORPHAN |
|
|
25
|
+
|
|
26
|
+
MISSING = consumed but no documented service exposes it. ORPHAN = exposed but no documented consumer (may be an unmapped client).
|
|
27
|
+
|
|
28
|
+
## Auth Model
|
|
29
|
+
|
|
30
|
+
Identity provider, token flow, how each service validates, role/permission model.
|
|
31
|
+
|
|
32
|
+
## Shared Integrations & Infra
|
|
33
|
+
|
|
34
|
+
External services (calendar, streaming, email...), who uses them, env vars per repo.
|
|
35
|
+
|
|
36
|
+
## Gaps
|
|
37
|
+
|
|
38
|
+
Unresolved items from per-repo `_gaps.md` files plus MISSING/ORPHAN contracts, each with a one-line reason.
|