@anhth2/spec-driven-dev-plugin 0.5.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/ARCHITECTURE.md +243 -0
- package/bin/build.js +230 -0
- package/bin/index.js +311 -0
- package/commands/debug.md +374 -0
- package/commands/debug.tmpl +77 -0
- package/commands/define-product.md +451 -0
- package/commands/define-product.tmpl +154 -0
- package/commands/fix-bug.md +379 -0
- package/commands/fix-bug.tmpl +82 -0
- package/commands/generate-bdd.md +591 -0
- package/commands/generate-bdd.tmpl +294 -0
- package/commands/generate-code.md +395 -0
- package/commands/generate-code.tmpl +98 -0
- package/commands/generate-prd.md +488 -0
- package/commands/generate-prd.tmpl +191 -0
- package/commands/generate-tech-docs.md +362 -0
- package/commands/generate-tech-docs.tmpl +65 -0
- package/commands/generate-tests.md +377 -0
- package/commands/generate-tests.tmpl +80 -0
- package/commands/refine-prd.md +408 -0
- package/commands/refine-prd.tmpl +111 -0
- package/commands/review-code.md +354 -0
- package/commands/review-code.tmpl +57 -0
- package/commands/review-context.md +646 -0
- package/commands/review-context.tmpl +349 -0
- package/commands/review-tech-docs.md +518 -0
- package/commands/review-tech-docs.tmpl +221 -0
- package/commands/run-tests.md +343 -0
- package/commands/run-tests.tmpl +46 -0
- package/commands/setup-ai-first.md +278 -0
- package/commands/setup-ai-first.tmpl +197 -0
- package/commands/smoke-test.md +366 -0
- package/commands/smoke-test.tmpl +69 -0
- package/commands/validate-traces.md +529 -0
- package/commands/validate-traces.tmpl +232 -0
- package/core/FRAMEWORK_VERSION +1 -0
- package/core/commands/debug.md +374 -0
- package/core/commands/define-product.md +451 -0
- package/core/commands/fix-bug.md +379 -0
- package/core/commands/generate-bdd.md +591 -0
- package/core/commands/generate-code.md +395 -0
- package/core/commands/generate-prd.md +488 -0
- package/core/commands/generate-tech-docs.md +362 -0
- package/core/commands/generate-tests.md +377 -0
- package/core/commands/refine-prd.md +408 -0
- package/core/commands/review-code.md +354 -0
- package/core/commands/review-context.md +646 -0
- package/core/commands/review-tech-docs.md +518 -0
- package/core/commands/run-tests.md +343 -0
- package/core/commands/setup-ai-first.md +278 -0
- package/core/commands/smoke-test.md +366 -0
- package/core/commands/validate-traces.md +529 -0
- package/core/hooks/data-guard.js +141 -0
- package/core/hooks/settings.json +18 -0
- package/core/modules/angular/architecture-snippets/component-patterns.md +187 -0
- package/core/modules/angular/module.yaml +6 -0
- package/core/modules/angular/stack-profile.yaml +38 -0
- package/core/modules/context-engineering/architecture-snippets/context-design.md +119 -0
- package/core/modules/context-engineering/module.yaml +9 -0
- package/core/modules/context-engineering/stack-profile.yaml +61 -0
- package/core/modules/dotnet/architecture-snippets/clean-arch.md +160 -0
- package/core/modules/dotnet/module.yaml +6 -0
- package/core/modules/dotnet/stack-profile.yaml +50 -0
- package/core/modules/golang/architecture-snippets/domain-layout.md +283 -0
- package/core/modules/golang/module.yaml +6 -0
- package/core/modules/golang/stack-profile.yaml +40 -0
- package/core/modules/java-spring/architecture-snippets/layered-arch.md +201 -0
- package/core/modules/java-spring/module.yaml +15 -0
- package/core/modules/java-spring/stack-profile.yaml +28 -0
- package/core/modules/nextjs/architecture-snippets/app-router-patterns.md +269 -0
- package/core/modules/nextjs/module.yaml +14 -0
- package/core/modules/nextjs/stack-profile.yaml +74 -0
- package/core/modules/php-laravel/architecture-snippets/service-repository.md +302 -0
- package/core/modules/php-laravel/module.yaml +15 -0
- package/core/modules/php-laravel/stack-profile.yaml +56 -0
- package/core/modules/react/architecture-snippets/hooks-query-patterns.md +254 -0
- package/core/modules/react/module.yaml +14 -0
- package/core/modules/react/stack-profile.yaml +63 -0
- package/core/rules/data-protection.md +80 -0
- package/core/rules/workflow.md +44 -0
- package/core/skills/code/SKILL.md +526 -0
- package/core/skills/debug/SKILL.md +584 -0
- package/core/skills/discovery/SKILL.md +363 -0
- package/core/skills/prd/SKILL.md +456 -0
- package/core/skills/setup-ai-first/SKILL.md +160 -0
- package/core/skills/spec/SKILL.md +361 -0
- package/core/skills/test/SKILL.md +862 -0
- package/core/steps/context-loader.md +163 -0
- package/core/steps/gate.md +81 -0
- package/core/steps/report-footer.md +53 -0
- package/core/steps/spawn-agent.md +123 -0
- package/core/templates/architecture.template.md +113 -0
- package/core/templates/feature.template +259 -0
- package/core/templates/platform-guide.template.md +145 -0
- package/core/templates/prd.template.md +312 -0
- package/core/templates/product-definition.template.md +168 -0
- package/core/templates/project-context.yaml +78 -0
- package/hooks/data-guard.js +141 -0
- package/hooks/settings.json +18 -0
- package/modules/angular/architecture-snippets/component-patterns.md +187 -0
- package/modules/angular/module.yaml +6 -0
- package/modules/angular/stack-profile.yaml +38 -0
- package/modules/context-engineering/architecture-snippets/context-design.md +119 -0
- package/modules/context-engineering/module.yaml +9 -0
- package/modules/context-engineering/stack-profile.yaml +61 -0
- package/modules/dotnet/architecture-snippets/clean-arch.md +160 -0
- package/modules/dotnet/module.yaml +6 -0
- package/modules/dotnet/stack-profile.yaml +50 -0
- package/modules/golang/architecture-snippets/domain-layout.md +283 -0
- package/modules/golang/module.yaml +6 -0
- package/modules/golang/stack-profile.yaml +40 -0
- package/modules/java-spring/architecture-snippets/layered-arch.md +201 -0
- package/modules/java-spring/module.yaml +15 -0
- package/modules/java-spring/stack-profile.yaml +28 -0
- package/modules/nextjs/architecture-snippets/app-router-patterns.md +269 -0
- package/modules/nextjs/module.yaml +14 -0
- package/modules/nextjs/stack-profile.yaml +74 -0
- package/modules/php-laravel/architecture-snippets/service-repository.md +302 -0
- package/modules/php-laravel/module.yaml +15 -0
- package/modules/php-laravel/stack-profile.yaml +56 -0
- package/modules/react/architecture-snippets/hooks-query-patterns.md +254 -0
- package/modules/react/module.yaml +14 -0
- package/modules/react/stack-profile.yaml +63 -0
- package/package.json +42 -0
- package/rules/data-protection.md +80 -0
- package/rules/workflow.md +44 -0
- package/scripts/init.sh +49 -0
- package/scripts/upgrade.sh +94 -0
- package/skills/code/SKILL.md +526 -0
- package/skills/code/SKILL.tmpl +176 -0
- package/skills/debug/SKILL.md +584 -0
- package/skills/debug/SKILL.tmpl +262 -0
- package/skills/discovery/SKILL.md +363 -0
- package/skills/discovery/SKILL.tmpl +147 -0
- package/skills/prd/SKILL.md +456 -0
- package/skills/prd/SKILL.tmpl +188 -0
- package/skills/setup-ai-first/SKILL.md +160 -0
- package/skills/setup-ai-first/SKILL.tmpl +107 -0
- package/skills/spec/SKILL.md +361 -0
- package/skills/spec/SKILL.tmpl +174 -0
- package/skills/test/SKILL.md +862 -0
- package/skills/test/SKILL.tmpl +296 -0
- package/steps/context-loader.md +163 -0
- package/steps/gate.md +81 -0
- package/steps/report-footer.md +53 -0
- package/steps/spawn-agent.md +123 -0
- package/templates/architecture.template.md +113 -0
- package/templates/feature.template +259 -0
- package/templates/platform-guide.template.md +145 -0
- package/templates/prd.template.md +312 -0
- package/templates/product-definition.template.md +168 -0
- package/templates/project-context.yaml +78 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* data-guard.js — Claude Code PreToolUse Hook
|
|
4
|
+
*
|
|
5
|
+
* Blocks AI from reading, writing, or executing commands involving
|
|
6
|
+
* sensitive files (credentials, secrets, private keys, .env, etc.)
|
|
7
|
+
*
|
|
8
|
+
* Install: copy to your project and register in .claude/settings.json
|
|
9
|
+
* (see hooks/settings.json for registration template)
|
|
10
|
+
*
|
|
11
|
+
* Exit codes:
|
|
12
|
+
* 0 = allow the tool call
|
|
13
|
+
* 2 = block the tool call (Claude Code interprets this as a hard block)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const readline = require('readline');
|
|
17
|
+
|
|
18
|
+
// ── Sensitive file patterns ────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
const SENSITIVE_PATH_PATTERNS = [
|
|
21
|
+
// Environment files
|
|
22
|
+
/^\.env$/i,
|
|
23
|
+
/^\.env\./i,
|
|
24
|
+
/\.env$/i,
|
|
25
|
+
|
|
26
|
+
// Secret/credential files
|
|
27
|
+
/secret/i,
|
|
28
|
+
/credential/i,
|
|
29
|
+
/password/i,
|
|
30
|
+
/passwd/i,
|
|
31
|
+
/private[_-]?key/i,
|
|
32
|
+
/api[_-]?key/i,
|
|
33
|
+
/access[_-]?token/i,
|
|
34
|
+
/auth[_-]?token/i,
|
|
35
|
+
|
|
36
|
+
// Crypto keys and certificates
|
|
37
|
+
/\.key$/i,
|
|
38
|
+
/\.pem$/i,
|
|
39
|
+
/\.p12$/i,
|
|
40
|
+
/\.pfx$/i,
|
|
41
|
+
/\.jks$/i,
|
|
42
|
+
/\.keystore$/i,
|
|
43
|
+
|
|
44
|
+
// Framework-specific prod configs
|
|
45
|
+
/application-(prod|production|staging)\.(yml|yaml|properties)$/i,
|
|
46
|
+
/appsettings\.(Production|Staging)\.json$/i,
|
|
47
|
+
/database\.yml$/i,
|
|
48
|
+
/config\/master\.key$/i,
|
|
49
|
+
/storage\/oauth-private\.key$/i,
|
|
50
|
+
|
|
51
|
+
// Secret directories
|
|
52
|
+
/^secrets\//i,
|
|
53
|
+
/\/secrets\//i,
|
|
54
|
+
/^\.secrets\//i,
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const SENSITIVE_BASH_PATTERNS = [
|
|
58
|
+
/\bprintenv\b/i,
|
|
59
|
+
/\benv\b.*\|\s*(grep|awk|sed).*secret/i,
|
|
60
|
+
/cat\s+\.env/i,
|
|
61
|
+
/docker\s+inspect/i,
|
|
62
|
+
/kubectl\s+get\s+secret.*-o\s+yaml/i,
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
function isSensitivePath(filePath) {
|
|
68
|
+
if (!filePath) return false;
|
|
69
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
70
|
+
return SENSITIVE_PATH_PATTERNS.some(pattern => pattern.test(normalized));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isSensitiveCommand(command) {
|
|
74
|
+
if (!command) return false;
|
|
75
|
+
return SENSITIVE_BASH_PATTERNS.some(pattern => pattern.test(command));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function block(reason) {
|
|
79
|
+
console.error(`\n🔒 DATA GUARD — BLOCKED\n${reason}\n`);
|
|
80
|
+
console.error('If you need configuration values, describe what you need');
|
|
81
|
+
console.error('without sharing actual secrets. Use placeholder values in generated code.\n');
|
|
82
|
+
process.exit(2);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── Main ───────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
let rawInput = '';
|
|
88
|
+
|
|
89
|
+
process.stdin.setEncoding('utf8');
|
|
90
|
+
process.stdin.on('data', chunk => { rawInput += chunk; });
|
|
91
|
+
process.stdin.on('end', () => {
|
|
92
|
+
let input;
|
|
93
|
+
try {
|
|
94
|
+
input = JSON.parse(rawInput);
|
|
95
|
+
} catch {
|
|
96
|
+
// Cannot parse input — allow (fail open, not fail closed)
|
|
97
|
+
process.exit(0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const toolName = input.tool_name || '';
|
|
101
|
+
const toolInput = input.tool_input || {};
|
|
102
|
+
|
|
103
|
+
// ── Read tool ─────────────────────────────────────────────────────────
|
|
104
|
+
if (toolName === 'Read') {
|
|
105
|
+
const filePath = toolInput.file_path || '';
|
|
106
|
+
if (isSensitivePath(filePath)) {
|
|
107
|
+
block(`Attempted to READ sensitive file: ${filePath}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Write tool ────────────────────────────────────────────────────────
|
|
112
|
+
if (toolName === 'Write') {
|
|
113
|
+
const filePath = toolInput.file_path || '';
|
|
114
|
+
if (isSensitivePath(filePath)) {
|
|
115
|
+
block(`Attempted to WRITE to sensitive file: ${filePath}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── Edit tool ─────────────────────────────────────────────────────────
|
|
120
|
+
if (toolName === 'Edit') {
|
|
121
|
+
const filePath = toolInput.file_path || '';
|
|
122
|
+
if (isSensitivePath(filePath)) {
|
|
123
|
+
block(`Attempted to EDIT sensitive file: ${filePath}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── Bash tool ─────────────────────────────────────────────────────────
|
|
128
|
+
if (toolName === 'Bash') {
|
|
129
|
+
const command = toolInput.command || '';
|
|
130
|
+
if (isSensitiveCommand(command)) {
|
|
131
|
+
block(`Attempted to execute sensitive command: ${command}`);
|
|
132
|
+
}
|
|
133
|
+
// Also check if the command references a sensitive file path
|
|
134
|
+
if (isSensitivePath(command)) {
|
|
135
|
+
block(`Bash command references a sensitive file path: ${command}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Allow all other tool calls
|
|
140
|
+
process.exit(0);
|
|
141
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Claude Code hook registration template. Copy this content into your project's .claude/settings.json",
|
|
3
|
+
"_docs": "https://docs.anthropic.com/claude/claude-code/hooks",
|
|
4
|
+
|
|
5
|
+
"hooks": {
|
|
6
|
+
"PreToolUse": [
|
|
7
|
+
{
|
|
8
|
+
"matcher": "Read|Write|Edit|Bash",
|
|
9
|
+
"hooks": [
|
|
10
|
+
{
|
|
11
|
+
"type": "command",
|
|
12
|
+
"command": "node .claude/hooks/data-guard.js"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Angular — Component Architecture Patterns
|
|
2
|
+
|
|
3
|
+
## Smart / Container Component Pattern
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// order-list.component.ts — Smart component: manages state, injects services
|
|
7
|
+
import { Component, OnInit, inject } from '@angular/core';
|
|
8
|
+
import { CommonModule } from '@angular/common';
|
|
9
|
+
import { OrderService } from '../services/order.service';
|
|
10
|
+
import { OrderListItemComponent } from './order-list-item.component';
|
|
11
|
+
import { Order } from '../models/order.model';
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'app-order-list',
|
|
15
|
+
standalone: true,
|
|
16
|
+
imports: [CommonModule, OrderListItemComponent],
|
|
17
|
+
template: `
|
|
18
|
+
<div class="order-list">
|
|
19
|
+
<app-order-list-item
|
|
20
|
+
*ngFor="let order of orders"
|
|
21
|
+
[order]="order"
|
|
22
|
+
(cancel)="onCancelOrder($event)"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
`
|
|
26
|
+
})
|
|
27
|
+
export class OrderListComponent implements OnInit {
|
|
28
|
+
private orderService = inject(OrderService);
|
|
29
|
+
orders: Order[] = [];
|
|
30
|
+
|
|
31
|
+
ngOnInit(): void {
|
|
32
|
+
this.orderService.getOrders().subscribe(orders => this.orders = orders);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onCancelOrder(orderId: number): void {
|
|
36
|
+
this.orderService.cancelOrder(orderId).subscribe(() => {
|
|
37
|
+
this.orders = this.orders.filter(o => o.id !== orderId);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Dumb / Presentational Component Pattern
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// order-list-item.component.ts — Dumb component: pure I/O, OnPush, no service injection
|
|
47
|
+
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
|
|
48
|
+
import { Order } from '../models/order.model';
|
|
49
|
+
|
|
50
|
+
@Component({
|
|
51
|
+
selector: 'app-order-list-item',
|
|
52
|
+
standalone: true,
|
|
53
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
54
|
+
template: `
|
|
55
|
+
<div class="order-item">
|
|
56
|
+
<span>{{ order.id }}</span>
|
|
57
|
+
<span>{{ order.status }}</span>
|
|
58
|
+
<button (click)="cancel.emit(order.id)" [disabled]="order.status === 'CANCELLED'">
|
|
59
|
+
Cancel
|
|
60
|
+
</button>
|
|
61
|
+
</div>
|
|
62
|
+
`
|
|
63
|
+
})
|
|
64
|
+
export class OrderListItemComponent {
|
|
65
|
+
@Input({ required: true }) order!: Order;
|
|
66
|
+
@Output() cancel = new EventEmitter<number>();
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Service with HttpClient Pattern
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// order.service.ts
|
|
74
|
+
import { Injectable, inject } from '@angular/core';
|
|
75
|
+
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
76
|
+
import { Observable } from 'rxjs';
|
|
77
|
+
import { Order, CreateOrderRequest, OrderResponse } from '../models/order.model';
|
|
78
|
+
import { environment } from '@env/environment';
|
|
79
|
+
|
|
80
|
+
@Injectable({ providedIn: 'root' })
|
|
81
|
+
export class OrderService {
|
|
82
|
+
private http = inject(HttpClient);
|
|
83
|
+
private baseUrl = `${environment.apiUrl}/v1/orders`;
|
|
84
|
+
|
|
85
|
+
getOrders(customerId?: number): Observable<Order[]> {
|
|
86
|
+
let params = new HttpParams();
|
|
87
|
+
if (customerId) params = params.set('customerId', customerId.toString());
|
|
88
|
+
return this.http.get<Order[]>(this.baseUrl, { params });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getOrder(id: number): Observable<Order> {
|
|
92
|
+
return this.http.get<Order>(`${this.baseUrl}/${id}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
createOrder(request: CreateOrderRequest): Observable<OrderResponse> {
|
|
96
|
+
return this.http.post<OrderResponse>(this.baseUrl, request);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
cancelOrder(id: number): Observable<void> {
|
|
100
|
+
return this.http.patch<void>(`${this.baseUrl}/${id}/cancel`, {});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Signal-Based State Pattern (Angular 17+)
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// order.store.ts — using Angular Signals for state management
|
|
109
|
+
import { Injectable, signal, computed } from '@angular/core';
|
|
110
|
+
import { Order } from '../models/order.model';
|
|
111
|
+
|
|
112
|
+
@Injectable({ providedIn: 'root' })
|
|
113
|
+
export class OrderStore {
|
|
114
|
+
private _orders = signal<Order[]>([]);
|
|
115
|
+
private _loading = signal(false);
|
|
116
|
+
private _error = signal<string | null>(null);
|
|
117
|
+
|
|
118
|
+
// Public readable signals
|
|
119
|
+
readonly orders = this._orders.asReadonly();
|
|
120
|
+
readonly loading = this._loading.asReadonly();
|
|
121
|
+
readonly error = this._error.asReadonly();
|
|
122
|
+
|
|
123
|
+
// Computed signals
|
|
124
|
+
readonly pendingOrders = computed(() =>
|
|
125
|
+
this._orders().filter(o => o.status === 'PENDING')
|
|
126
|
+
);
|
|
127
|
+
readonly orderCount = computed(() => this._orders().length);
|
|
128
|
+
|
|
129
|
+
setOrders(orders: Order[]): void {
|
|
130
|
+
this._orders.set(orders);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
setLoading(loading: boolean): void {
|
|
134
|
+
this._loading.set(loading);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setError(error: string | null): void {
|
|
138
|
+
this._error.set(error);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
removeOrder(id: number): void {
|
|
142
|
+
this._orders.update(orders => orders.filter(o => o.id !== id));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Route Guard Pattern
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// auth.guard.ts
|
|
151
|
+
import { inject } from '@angular/core';
|
|
152
|
+
import { CanActivateFn, Router } from '@angular/router';
|
|
153
|
+
import { AuthService } from '../services/auth.service';
|
|
154
|
+
|
|
155
|
+
export const authGuard: CanActivateFn = (route, state) => {
|
|
156
|
+
const auth = inject(AuthService);
|
|
157
|
+
const router = inject(Router);
|
|
158
|
+
|
|
159
|
+
if (auth.isAuthenticated()) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
return router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } });
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Standalone Component with Lazy Loading
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// app.routes.ts
|
|
170
|
+
import { Routes } from '@angular/router';
|
|
171
|
+
import { authGuard } from './guards/auth.guard';
|
|
172
|
+
|
|
173
|
+
export const APP_ROUTES: Routes = [
|
|
174
|
+
{
|
|
175
|
+
path: 'orders',
|
|
176
|
+
canActivate: [authGuard],
|
|
177
|
+
loadComponent: () =>
|
|
178
|
+
import('./features/orders/order-list.component').then(m => m.OrderListComponent)
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
path: 'orders/:id',
|
|
182
|
+
canActivate: [authGuard],
|
|
183
|
+
loadComponent: () =>
|
|
184
|
+
import('./features/orders/order-detail.component').then(m => m.OrderDetailComponent)
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
build:
|
|
2
|
+
compile: "ng build"
|
|
3
|
+
test: "ng test --watch=false"
|
|
4
|
+
run: "ng serve"
|
|
5
|
+
|
|
6
|
+
architecture:
|
|
7
|
+
style: "Component → Service → HTTP Client → Backend API"
|
|
8
|
+
key_rules:
|
|
9
|
+
- "Smart (container) components manage state and inject services"
|
|
10
|
+
- "Dumb (presentational) components receive data via @Input and emit via @Output"
|
|
11
|
+
- "Business logic lives in services, not in component classes"
|
|
12
|
+
- "Use OnPush change detection for all pure presentational components"
|
|
13
|
+
- "HTTP calls must be in services, never in component files"
|
|
14
|
+
|
|
15
|
+
coding_standards:
|
|
16
|
+
naming:
|
|
17
|
+
components: "PascalCase + Component suffix (e.g., OrderListComponent)"
|
|
18
|
+
services: "PascalCase + Service suffix (e.g., OrderService)"
|
|
19
|
+
pipes: "PascalCase + Pipe suffix (e.g., CurrencyFormatPipe)"
|
|
20
|
+
directives: "PascalCase + Directive suffix (e.g., HighlightDirective)"
|
|
21
|
+
guards: "PascalCase + Guard suffix (e.g., AuthGuard)"
|
|
22
|
+
files:
|
|
23
|
+
component: "{feature}.component.ts / .html / .scss"
|
|
24
|
+
service: "{feature}.service.ts"
|
|
25
|
+
model: "{feature}.model.ts"
|
|
26
|
+
store: "{feature}.store.ts"
|
|
27
|
+
patterns:
|
|
28
|
+
state_management: "NgRx (complex) or Angular Signals (simple/medium)"
|
|
29
|
+
http_error_handling: "HttpInterceptor catches 4xx/5xx globally"
|
|
30
|
+
lazy_loading: "All feature modules must be lazily loaded"
|
|
31
|
+
|
|
32
|
+
testing:
|
|
33
|
+
unit: "Jasmine + Karma or Jest"
|
|
34
|
+
e2e: "Cypress or Playwright"
|
|
35
|
+
patterns:
|
|
36
|
+
- "Use TestBed.configureTestingModule for component tests"
|
|
37
|
+
- "Mock services with jasmine.createSpyObj or jest.fn()"
|
|
38
|
+
- "Test component DOM via DebugElement and By.css selectors"
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Context Engineering — Design Templates and Patterns
|
|
2
|
+
|
|
3
|
+
## System Context Design Template
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
# System Context: {Agent Name}
|
|
7
|
+
|
|
8
|
+
## Role
|
|
9
|
+
You are {role description}. You help {target user} to {primary purpose}.
|
|
10
|
+
|
|
11
|
+
## Scope
|
|
12
|
+
In scope:
|
|
13
|
+
- {capability 1}
|
|
14
|
+
- {capability 2}
|
|
15
|
+
|
|
16
|
+
Out of scope (do not attempt):
|
|
17
|
+
- {excluded capability 1}
|
|
18
|
+
- {excluded capability 2}
|
|
19
|
+
|
|
20
|
+
## Output Format
|
|
21
|
+
Always respond with:
|
|
22
|
+
- {format requirement 1, e.g., "structured YAML when producing artifacts"}
|
|
23
|
+
- {format requirement 2, e.g., "numbered steps for procedural instructions"}
|
|
24
|
+
- {format requirement 3, e.g., "a CHECKPOINT before any destructive action"}
|
|
25
|
+
|
|
26
|
+
## Constraints
|
|
27
|
+
- {constraint 1, e.g., "Never make changes without explicit user confirmation"}
|
|
28
|
+
- {constraint 2, e.g., "Always cite source files when referencing code"}
|
|
29
|
+
|
|
30
|
+
## Tools Available
|
|
31
|
+
- {tool name}: {what it does and when to use it}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Context Layering: Persistent vs Ephemeral
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌─────────────────────────────────────────────────┐
|
|
38
|
+
│ PERSISTENT (system prompt — stable, pre-loaded) │
|
|
39
|
+
│ - Role and persona │
|
|
40
|
+
│ - Output format requirements │
|
|
41
|
+
│ - Constraint rules │
|
|
42
|
+
│ - Domain knowledge (project context) │
|
|
43
|
+
└────────────────────┬────────────────────────────┘
|
|
44
|
+
│ passed once at session start
|
|
45
|
+
┌────────────────────▼────────────────────────────┐
|
|
46
|
+
│ SESSION (loaded once per task) │
|
|
47
|
+
│ - Project-context.yaml │
|
|
48
|
+
│ - CLAUDE.md │
|
|
49
|
+
│ - Business dictionary │
|
|
50
|
+
└────────────────────┬────────────────────────────┘
|
|
51
|
+
│ loaded on demand
|
|
52
|
+
┌────────────────────▼────────────────────────────┐
|
|
53
|
+
│ EPHEMERAL (per-turn, discarded after use) │
|
|
54
|
+
│ - Tool results │
|
|
55
|
+
│ - File contents read mid-task │
|
|
56
|
+
│ - User clarification answers │
|
|
57
|
+
└─────────────────────────────────────────────────┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Context Handoff Between Agents
|
|
61
|
+
|
|
62
|
+
When passing work from one agent to another, include a structured handoff payload:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# Agent Handoff Payload
|
|
66
|
+
handoff_from: "{source agent name}"
|
|
67
|
+
handoff_to: "{target agent name}"
|
|
68
|
+
task_id: "{unique task identifier}"
|
|
69
|
+
status: "partial_complete" # pending | partial_complete | blocked | ready_for_review
|
|
70
|
+
|
|
71
|
+
# What was accomplished
|
|
72
|
+
completed:
|
|
73
|
+
- "{step 1 done}"
|
|
74
|
+
- "{step 2 done}"
|
|
75
|
+
|
|
76
|
+
# What the next agent must do
|
|
77
|
+
pending:
|
|
78
|
+
- "{step 3 to do}"
|
|
79
|
+
- "{step 4 to do}"
|
|
80
|
+
|
|
81
|
+
# Decisions made (so next agent doesn't re-litigate)
|
|
82
|
+
decisions:
|
|
83
|
+
- decision: "{what was decided}"
|
|
84
|
+
rationale: "{why}"
|
|
85
|
+
|
|
86
|
+
# Artifacts produced (file paths)
|
|
87
|
+
artifacts:
|
|
88
|
+
- path: "{file path}"
|
|
89
|
+
type: "{type: spec | code | test | report}"
|
|
90
|
+
status: "{draft | approved | final}"
|
|
91
|
+
|
|
92
|
+
# Context the next agent needs immediately
|
|
93
|
+
context_snapshot:
|
|
94
|
+
project_name: "{name}"
|
|
95
|
+
domain: "{domain}"
|
|
96
|
+
uc_id: "{UC-ID}"
|
|
97
|
+
tech_stack: "{stack}"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Context Compression Pattern
|
|
101
|
+
|
|
102
|
+
When conversation history grows large, compress before the next turn:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
CONTEXT SUMMARY (replaces N previous turns):
|
|
106
|
+
Task: {what we are doing}
|
|
107
|
+
Progress: {what has been completed so far}
|
|
108
|
+
Current state: {where we are now}
|
|
109
|
+
Key decisions: {decisions that must not be reversed}
|
|
110
|
+
Pending: {what still needs to be done}
|
|
111
|
+
Files produced: {list of artifact paths}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Compression rules:
|
|
115
|
+
1. Keep all decisions and their rationale.
|
|
116
|
+
2. Keep all file paths that were created.
|
|
117
|
+
3. Drop intermediate reasoning that led to a confirmed decision.
|
|
118
|
+
4. Keep any user corrections or explicit preferences.
|
|
119
|
+
5. Keep any open questions that are still unresolved.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
name: "Context Engineering"
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: "AI context design, prompt engineering, and system context workflows"
|
|
4
|
+
stack_type: "ai-first"
|
|
5
|
+
use_cases:
|
|
6
|
+
- "Designing AI system contexts"
|
|
7
|
+
- "Reverse engineering existing prompts"
|
|
8
|
+
- "Context window optimization"
|
|
9
|
+
- "Multi-agent coordination"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
context_types:
|
|
2
|
+
system:
|
|
3
|
+
description: "Persistent instruction context that defines agent behavior and constraints"
|
|
4
|
+
lifetime: "entire session"
|
|
5
|
+
examples:
|
|
6
|
+
- "Role and persona definition"
|
|
7
|
+
- "Output format requirements"
|
|
8
|
+
- "Capability constraints and safety boundaries"
|
|
9
|
+
user:
|
|
10
|
+
description: "Per-turn input from the human, including instructions and data"
|
|
11
|
+
lifetime: "current turn"
|
|
12
|
+
tool:
|
|
13
|
+
description: "Results returned from tool calls (function outputs, search results)"
|
|
14
|
+
lifetime: "current turn or until referenced"
|
|
15
|
+
memory:
|
|
16
|
+
description: "Persistent state stored and retrieved across turns or sessions"
|
|
17
|
+
lifetime: "configurable — session, project, or long-term"
|
|
18
|
+
|
|
19
|
+
context_optimization:
|
|
20
|
+
rules:
|
|
21
|
+
- "Front-load the most decision-relevant context (primacy effect)"
|
|
22
|
+
- "Remove redundant instructions — each rule stated once"
|
|
23
|
+
- "Separate stable context (system prompt) from dynamic context (user message)"
|
|
24
|
+
- "Use structured formats (YAML/JSON/Markdown headers) for scannable context"
|
|
25
|
+
- "Compress historical context before adding new turns (rolling summary)"
|
|
26
|
+
- "Reference external documents by path rather than inlining large content"
|
|
27
|
+
token_budget_targets:
|
|
28
|
+
system_prompt: "under 2000 tokens for most use cases"
|
|
29
|
+
context_window_reserve: "20% of max window for model output"
|
|
30
|
+
|
|
31
|
+
evaluation_criteria:
|
|
32
|
+
clarity:
|
|
33
|
+
description: "Is each instruction unambiguous and actionable?"
|
|
34
|
+
test: "Would two different agents interpret this identically?"
|
|
35
|
+
completeness:
|
|
36
|
+
description: "Does context include all information the agent needs?"
|
|
37
|
+
test: "Can the agent complete the task without asking for clarification?"
|
|
38
|
+
relevance:
|
|
39
|
+
description: "Is every sentence load-bearing for the task?"
|
|
40
|
+
test: "Would removing this sentence change agent behavior?"
|
|
41
|
+
consistency:
|
|
42
|
+
description: "Are there no contradictory instructions?"
|
|
43
|
+
test: "Can all rules be simultaneously satisfied?"
|
|
44
|
+
|
|
45
|
+
common_patterns:
|
|
46
|
+
rag:
|
|
47
|
+
name: "Retrieval-Augmented Generation"
|
|
48
|
+
use_when: "Agent needs knowledge beyond training cutoff or domain-specific facts"
|
|
49
|
+
structure: "System: role + instructions | User: query | Tool: retrieved chunks | User: synthesize"
|
|
50
|
+
chain_of_thought:
|
|
51
|
+
name: "Chain of Thought"
|
|
52
|
+
use_when: "Complex reasoning tasks requiring intermediate steps"
|
|
53
|
+
structure: "Include 'think step by step' or explicit reasoning scaffold in system prompt"
|
|
54
|
+
few_shot:
|
|
55
|
+
name: "Few-Shot Examples"
|
|
56
|
+
use_when: "Output format or classification must match specific patterns"
|
|
57
|
+
structure: "Provide 2-5 input/output pairs before the actual task"
|
|
58
|
+
multi_agent:
|
|
59
|
+
name: "Multi-Agent Coordination"
|
|
60
|
+
use_when: "Task can be parallelized or requires specialist sub-agents"
|
|
61
|
+
structure: "Orchestrator context + worker contexts + handoff format definition"
|