@howlil/ez-agents 3.4.2 → 3.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/README.md +77 -2
- package/agents/ez-observer-agent.md +260 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-scrum-master-agent.md +242 -0
- package/agents/ez-tech-lead-agent.md +267 -0
- package/bin/install.js +3221 -3272
- package/commands/ez/arch-review.md +102 -0
- package/commands/ez/execute-phase.md +11 -0
- package/commands/ez/export-session.md +79 -0
- package/commands/ez/gather-requirements.md +117 -0
- package/commands/ez/git-workflow.md +72 -0
- package/commands/ez/hotfix.md +120 -0
- package/commands/ez/import-session.md +82 -0
- package/commands/ez/list-sessions.md +96 -0
- package/commands/ez/package-manager.md +316 -0
- package/commands/ez/plan-phase.md +9 -1
- package/commands/ez/preflight.md +79 -0
- package/commands/ez/progress.md +13 -1
- package/commands/ez/release.md +153 -0
- package/commands/ez/resume.md +107 -0
- package/commands/ez/standup.md +85 -0
- package/ez-agents/bin/ez-tools.cjs +1095 -716
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +321 -203
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/index.cjs +46 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/logger.cjs +124 -154
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/metrics-tracker.cjs +406 -0
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/release-validator.cjs +614 -0
- package/ez-agents/bin/lib/safe-exec.cjs +128 -214
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/planning-config.md +140 -0
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/release-checklist.md +133 -0
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/workflows/arch-review.md +54 -0
- package/ez-agents/workflows/autonomous.md +844 -743
- package/ez-agents/workflows/execute-phase.md +45 -0
- package/ez-agents/workflows/export-session.md +255 -0
- package/ez-agents/workflows/gather-requirements.md +206 -0
- package/ez-agents/workflows/help.md +92 -0
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/import-session.md +303 -0
- package/ez-agents/workflows/new-milestone.md +713 -384
- package/ez-agents/workflows/new-project.md +1107 -1113
- package/ez-agents/workflows/plan-phase.md +22 -0
- package/ez-agents/workflows/progress.md +15 -25
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/standup.md +64 -0
- package/package.json +9 -2
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* URL Fetch Service
|
|
5
|
+
*
|
|
6
|
+
* Provides secure URL fetching with HTTPS validation and user confirmation.
|
|
7
|
+
* Only HTTPS URLs are allowed. HTTP, file, data, javascript, and vbscript protocols are blocked.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { URL } = require('url');
|
|
11
|
+
const { URLFetchError } = require('./context-errors.cjs');
|
|
12
|
+
|
|
13
|
+
const DEFAULT_TIMEOUT = 30000; // 30 seconds
|
|
14
|
+
const BLOCKED_PROTOCOLS = ['http:', 'file:', 'data:', 'javascript:', 'vbscript:'];
|
|
15
|
+
|
|
16
|
+
class URLValidator {
|
|
17
|
+
/**
|
|
18
|
+
* Validate a URL string
|
|
19
|
+
* @param {string} urlString - The URL to validate
|
|
20
|
+
* @returns {{valid: boolean, error?: string}} - Validation result
|
|
21
|
+
*/
|
|
22
|
+
static validate(urlString) {
|
|
23
|
+
if (!urlString || typeof urlString !== 'string') {
|
|
24
|
+
return { valid: false, error: 'URL is required' };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const url = new URL(urlString);
|
|
29
|
+
|
|
30
|
+
// Check protocol
|
|
31
|
+
if (url.protocol !== 'https:') {
|
|
32
|
+
if (BLOCKED_PROTOCOLS.includes(url.protocol)) {
|
|
33
|
+
return {
|
|
34
|
+
valid: false,
|
|
35
|
+
error: `Protocol '${url.protocol}' is not allowed. Only HTTPS is permitted.`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
valid: false,
|
|
40
|
+
error: `Invalid protocol '${url.protocol}'. Only HTTPS is allowed.`
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check hostname exists
|
|
45
|
+
if (!url.hostname || url.hostname.trim() === '') {
|
|
46
|
+
return { valid: false, error: 'Invalid URL: missing hostname' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Reject localhost URLs
|
|
50
|
+
if (url.hostname === 'localhost' ||
|
|
51
|
+
url.hostname === '127.0.0.1' ||
|
|
52
|
+
url.hostname === '::1' ||
|
|
53
|
+
url.hostname.endsWith('.localhost')) {
|
|
54
|
+
return {
|
|
55
|
+
valid: false,
|
|
56
|
+
error: 'Localhost URLs are not allowed. Use a publicly accessible HTTPS URL.'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { valid: true };
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return {
|
|
63
|
+
valid: false,
|
|
64
|
+
error: `Invalid URL format: ${err.message}`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class URLFetchService {
|
|
71
|
+
/**
|
|
72
|
+
* Create a new URLFetchService instance
|
|
73
|
+
* @param {number} timeout - Request timeout in milliseconds (default: 30000)
|
|
74
|
+
*/
|
|
75
|
+
constructor(timeout = DEFAULT_TIMEOUT) {
|
|
76
|
+
this.timeout = timeout;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Validate a URL
|
|
81
|
+
* @param {string} urlString - The URL to validate
|
|
82
|
+
* @returns {{valid: boolean, error?: string}} - Validation result
|
|
83
|
+
*/
|
|
84
|
+
validateUrl(urlString) {
|
|
85
|
+
return URLValidator.validate(urlString);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Fetch content from a URL
|
|
90
|
+
* @param {string} url - The URL to fetch
|
|
91
|
+
* @returns {{content: string, contentType: string}} - Fetched content
|
|
92
|
+
* @throws {URLFetchError} - On fetch errors
|
|
93
|
+
*/
|
|
94
|
+
async fetchUrl(url) {
|
|
95
|
+
// Validate URL first
|
|
96
|
+
const validation = this.validateUrl(url);
|
|
97
|
+
if (!validation.valid) {
|
|
98
|
+
throw new URLFetchError(url, validation.error);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
// Create abort controller for timeout
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
105
|
+
|
|
106
|
+
const response = await fetch(url, {
|
|
107
|
+
headers: {
|
|
108
|
+
'User-Agent': 'ez-agents/1.0'
|
|
109
|
+
},
|
|
110
|
+
signal: controller.signal,
|
|
111
|
+
redirect: 'follow'
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
clearTimeout(timeoutId);
|
|
115
|
+
|
|
116
|
+
// Check for HTTP errors
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new URLFetchError(
|
|
119
|
+
url,
|
|
120
|
+
`HTTP ${response.status}: ${response.statusText}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Get content type
|
|
125
|
+
const contentType = response.headers.get('content-type') || 'text/plain';
|
|
126
|
+
|
|
127
|
+
// Get content
|
|
128
|
+
const content = await response.text();
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
content,
|
|
132
|
+
contentType
|
|
133
|
+
};
|
|
134
|
+
} catch (err) {
|
|
135
|
+
if (err.name === 'AbortError') {
|
|
136
|
+
throw new URLFetchError(url, `Request timeout after ${this.timeout}ms`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (err.name === 'URLFetchError') {
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
throw new URLFetchError(url, `Network error: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Prompt user for confirmation before fetching a URL
|
|
149
|
+
* @param {string} url - The URL to fetch
|
|
150
|
+
* @returns {Promise<boolean>} - True if user confirmed
|
|
151
|
+
*/
|
|
152
|
+
static async confirmUrlFetch(url) {
|
|
153
|
+
const readline = require('readline');
|
|
154
|
+
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
const rl = readline.createInterface({
|
|
157
|
+
input: process.stdin,
|
|
158
|
+
output: process.stdout
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
rl.question(`Fetch ${url}? (y/n): `, (answer) => {
|
|
162
|
+
rl.close();
|
|
163
|
+
resolve(answer.toLowerCase() === 'y');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = URLFetchService;
|
|
170
|
+
module.exports.URLValidator = URLValidator;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Metrics Schema Reference
|
|
2
|
+
|
|
3
|
+
Schema for `.planning/metrics.json` — the EZ Agents success metrics store.
|
|
4
|
+
|
|
5
|
+
## Full Schema
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"schema_version": "1.0",
|
|
10
|
+
"project": "project-name",
|
|
11
|
+
"updated": "2026-03-19T00:00:00Z",
|
|
12
|
+
|
|
13
|
+
"phase_metrics": [
|
|
14
|
+
{
|
|
15
|
+
"phase": 18,
|
|
16
|
+
"phase_name": "session-memory",
|
|
17
|
+
"plans_total": 4,
|
|
18
|
+
"plans_completed": 4,
|
|
19
|
+
"velocity_min": 24,
|
|
20
|
+
"defect_density": 0.12,
|
|
21
|
+
"bdd_pass_rate": 0.84,
|
|
22
|
+
"bdd_must_passing": 8,
|
|
23
|
+
"bdd_must_total": 9,
|
|
24
|
+
"deviation_count": 2,
|
|
25
|
+
"completed_at": "2026-03-19T00:00:00Z"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
|
|
29
|
+
"project_metrics": {
|
|
30
|
+
"requirements_coverage_pct": 78,
|
|
31
|
+
"test_coverage_pct": 74,
|
|
32
|
+
"bdd_scenarios_total": 60,
|
|
33
|
+
"bdd_scenarios_passing": 45,
|
|
34
|
+
"bdd_scenarios_must": 25,
|
|
35
|
+
"bdd_scenarios_must_passing": 24
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
"agent_metrics": {
|
|
39
|
+
"total_token_cost_usd": 18.40,
|
|
40
|
+
"avg_cost_per_plan": 0.27,
|
|
41
|
+
"deviation_rate": 0.15,
|
|
42
|
+
"avg_plans_per_phase": 3.2,
|
|
43
|
+
"avg_velocity_min_per_plan": 22
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"business_metrics": {
|
|
47
|
+
"time_to_first_ship_days": 95,
|
|
48
|
+
"hotfixes_deployed": 0,
|
|
49
|
+
"milestones_shipped": 1,
|
|
50
|
+
"current_tier": "medium",
|
|
51
|
+
"phases_total": 29,
|
|
52
|
+
"phases_completed": 18
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Field Definitions
|
|
58
|
+
|
|
59
|
+
### phase_metrics[]
|
|
60
|
+
|
|
61
|
+
| Field | Type | Source | Description |
|
|
62
|
+
|-------|------|--------|-------------|
|
|
63
|
+
| `phase` | int | ez-executor | Phase number |
|
|
64
|
+
| `plans_total` | int | ez-executor | Plans in phase |
|
|
65
|
+
| `plans_completed` | int | ez-executor | Plans with SUMMARY.md |
|
|
66
|
+
| `velocity_min` | int | ez-executor | Minutes from first to last commit in phase |
|
|
67
|
+
| `defect_density` | float | ez-executor | Deviations / tasks executed |
|
|
68
|
+
| `bdd_pass_rate` | float | ez-verifier | @must scenarios passing / total @must |
|
|
69
|
+
| `deviation_count` | int | ez-executor | Auto-fix deviations logged |
|
|
70
|
+
|
|
71
|
+
### project_metrics
|
|
72
|
+
|
|
73
|
+
| Field | Type | Source | Description |
|
|
74
|
+
|-------|------|--------|-------------|
|
|
75
|
+
| `requirements_coverage_pct` | int | ez-executor | % of REQUIREMENTS.md checked off |
|
|
76
|
+
| `test_coverage_pct` | int | ez-verifier | From coverage tool output |
|
|
77
|
+
| `bdd_scenarios_passing` | int | ez-verifier | Scenarios with green status |
|
|
78
|
+
|
|
79
|
+
### agent_metrics
|
|
80
|
+
|
|
81
|
+
| Field | Type | Source | Description |
|
|
82
|
+
|-------|------|--------|-------------|
|
|
83
|
+
| `total_token_cost_usd` | float | metrics-tracker | Accumulated from state.record-metric |
|
|
84
|
+
| `avg_cost_per_plan` | float | metrics-tracker | total / plans_completed |
|
|
85
|
+
| `deviation_rate` | float | metrics-tracker | total_deviations / total_tasks |
|
|
86
|
+
|
|
87
|
+
### business_metrics
|
|
88
|
+
|
|
89
|
+
| Field | Type | Source | Description |
|
|
90
|
+
|-------|------|--------|-------------|
|
|
91
|
+
| `time_to_first_ship_days` | int | ez-release-agent | Days from project init to first release |
|
|
92
|
+
| `hotfixes_deployed` | int | ez-release-agent | Hotfixes tagged and pushed |
|
|
93
|
+
| `current_tier` | string | tier-manager | mvp / medium / enterprise |
|
|
94
|
+
|
|
95
|
+
## Capture Points
|
|
96
|
+
|
|
97
|
+
| Metric | When Captured | Who Captures |
|
|
98
|
+
|--------|---------------|--------------|
|
|
99
|
+
| velocity_min | After SUMMARY.md created | ez-executor (state record-metric) |
|
|
100
|
+
| deviation_count | During execution | ez-executor (per deviation Rule 1-3) |
|
|
101
|
+
| defect_density | After plan completes | ez-executor (computed) |
|
|
102
|
+
| bdd_pass_rate | After VERIFICATION.md | ez-verifier (metrics record-bdd) |
|
|
103
|
+
| test_coverage_pct | After verification | ez-verifier (from coverage tool) |
|
|
104
|
+
| requirements_coverage_pct | After mark-complete | ez-executor (computed from REQUIREMENTS.md) |
|
|
105
|
+
| total_token_cost_usd | Ongoing | ez-executor (from state.record-metric cost field) |
|
|
106
|
+
| hotfixes_deployed | After hotfix tag | ez-release-agent |
|
|
107
|
+
|
|
108
|
+
## Dashboard Output
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
/ez:stats → enhanced dashboard
|
|
112
|
+
|
|
113
|
+
PROGRESS: Phase 18/29 (62%) | Requirements 78% | BDD 80%
|
|
114
|
+
VELOCITY: 22 min/plan avg | Trend: ↑ IMPROVING
|
|
115
|
+
QUALITY: Coverage 74% | Defect density 0.12 | Deviation 15%
|
|
116
|
+
COSTS: $18.40 total | $0.27/plan | Est. remaining: ~$3.00
|
|
117
|
+
RELEASE: Tier: Medium | Hotfixes: 0 | Blockers: 0
|
|
118
|
+
```
|
|
@@ -197,4 +197,144 @@ Squash merge is recommended — keeps main branch history clean while preserving
|
|
|
197
197
|
|
|
198
198
|
</branching_strategy_behavior>
|
|
199
199
|
|
|
200
|
+
|
|
201
|
+
<smart_orchestration_config>
|
|
202
|
+
|
|
203
|
+
**`smart_orchestration` block:**
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
"smart_orchestration": {
|
|
207
|
+
"enabled": true,
|
|
208
|
+
"show_auto_prefix": true,
|
|
209
|
+
"auto_invoke": {
|
|
210
|
+
"preflight": ["progress", "execute-phase"],
|
|
211
|
+
"arch_review": ["execute-phase"],
|
|
212
|
+
"standup": []
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
| Option | Default | Description |
|
|
218
|
+
|--------|---------|-------------|
|
|
219
|
+
| `enabled` | `true` | Master toggle for smart orchestration auto-invocations |
|
|
220
|
+
| `show_auto_prefix` | `true` | Prefix auto-invoked agent output with `[AUTO]` label |
|
|
221
|
+
| `auto_invoke.preflight` | `["progress", "execute-phase"]` | Commands that silently run health check before executing |
|
|
222
|
+
| `auto_invoke.arch_review` | `["execute-phase"]` | Commands that auto-spawn tech lead review when `agent_discussion` enabled |
|
|
223
|
+
| `auto_invoke.standup` | `[]` | Commands that auto-generate standup before running |
|
|
224
|
+
|
|
225
|
+
**Disabling per-invocation:** Pass `--no-auto` flag to any command to skip smart orchestration for that run.
|
|
226
|
+
|
|
227
|
+
</smart_orchestration_config>
|
|
228
|
+
|
|
229
|
+
<agent_discussion_config>
|
|
230
|
+
|
|
231
|
+
**`agent_discussion` block:**
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
"agent_discussion": {
|
|
235
|
+
"enabled": false,
|
|
236
|
+
"pre_flight_observer": false,
|
|
237
|
+
"tech_lead_review": false,
|
|
238
|
+
"scrum_master_standup": false,
|
|
239
|
+
"cost_warning": true
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Option | Default | Description |
|
|
244
|
+
|--------|---------|-------------|
|
|
245
|
+
| `enabled` | `false` | Master toggle for optional discussion agents |
|
|
246
|
+
| `pre_flight_observer` | `false` | Spawn observer agent before execution to surface risks |
|
|
247
|
+
| `tech_lead_review` | `false` | Auto-spawn tech lead review after `/ez:plan-phase` completes |
|
|
248
|
+
| `scrum_master_standup` | `false` | Auto-generate standup report at session start |
|
|
249
|
+
| `cost_warning` | `true` | Warn before spawning expensive agents (Opus-class) |
|
|
250
|
+
|
|
251
|
+
**Enable via `/ez:settings`:** The settings workflow provides a guided UI for toggling these options. Avoid manual JSON edits.
|
|
252
|
+
|
|
253
|
+
</agent_discussion_config>
|
|
254
|
+
|
|
255
|
+
<sessions_config>
|
|
256
|
+
|
|
257
|
+
**`sessions` block:**
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
"sessions": {
|
|
261
|
+
"retention_policy": "keep_last_10",
|
|
262
|
+
"auto_compress_threshold": 50,
|
|
263
|
+
"chain_navigation_enabled": true
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
| Option | Default | Description |
|
|
268
|
+
|--------|---------|-------------|
|
|
269
|
+
| `retention_policy` | `"keep_last_10"` | How many sessions to retain. Options: `"keep_all"`, `"keep_last_N"`, `"keep_days_N"` |
|
|
270
|
+
| `auto_compress_threshold` | `50` | Compress session memory when token count exceeds this (in thousands) |
|
|
271
|
+
| `chain_navigation_enabled` | `true` | Enable `--previous`/`--next`/`--chain` flags in `/ez:resume` |
|
|
272
|
+
|
|
273
|
+
**Session files location:** `.planning/sessions/` — each session is a JSON file. Use `/ez:export-session` and `/ez:import-session` for cross-model handoffs.
|
|
274
|
+
|
|
275
|
+
</sessions_config>
|
|
276
|
+
|
|
277
|
+
<release_tiers_config>
|
|
278
|
+
|
|
279
|
+
**`release.tiers` block:**
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
"release": {
|
|
283
|
+
"tier": "mvp",
|
|
284
|
+
"tiers": {
|
|
285
|
+
"mvp": {
|
|
286
|
+
"coverage_threshold": 0,
|
|
287
|
+
"checklist_items": ["build_passes", "no_blockers"],
|
|
288
|
+
"git_strategy": "direct_to_main"
|
|
289
|
+
},
|
|
290
|
+
"medium": {
|
|
291
|
+
"coverage_threshold": 60,
|
|
292
|
+
"checklist_items": ["build_passes", "no_blockers", "tests_pass", "security_scan"],
|
|
293
|
+
"git_strategy": "pr_required"
|
|
294
|
+
},
|
|
295
|
+
"enterprise": {
|
|
296
|
+
"coverage_threshold": 80,
|
|
297
|
+
"checklist_items": ["build_passes", "no_blockers", "tests_pass", "security_scan", "coverage_gate", "changelog_updated", "rollback_plan"],
|
|
298
|
+
"git_strategy": "gitflow"
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
| Tier | Coverage | Git Strategy | Checklist |
|
|
305
|
+
|------|----------|--------------|-----------|
|
|
306
|
+
| `mvp` | None | Direct to main | Build + no blockers |
|
|
307
|
+
| `medium` | 60% | PR required | Build + tests + security scan |
|
|
308
|
+
| `enterprise` | 80% | GitFlow (main + develop) | Full gates including rollback plan |
|
|
309
|
+
|
|
310
|
+
**Hotfix behavior by tier:** MVP hotfixes merge directly; Medium requires PR; Enterprise merges to main AND syncs to develop. See `/ez:hotfix` documentation.
|
|
311
|
+
|
|
312
|
+
**Set tier:** `node "$HOME/.claude/ez-agents/bin/ez-tools.cjs" config-set release.tier enterprise`
|
|
313
|
+
|
|
314
|
+
</release_tiers_config>
|
|
315
|
+
|
|
316
|
+
<package_manager_config>
|
|
317
|
+
|
|
318
|
+
**`packageManager` block:**
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
"packageManager": {
|
|
322
|
+
"default": "npm",
|
|
323
|
+
"autoDetect": true,
|
|
324
|
+
"respectLockfile": true
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
| Option | Default | Description |
|
|
329
|
+
|--------|---------|-------------|
|
|
330
|
+
| `default` | `"npm"` | Fallback package manager when auto-detection fails. Options: `"npm"`, `"yarn"`, `"pnpm"`, `"bun"` |
|
|
331
|
+
| `autoDetect` | `true` | Detect package manager from lock file presence (`yarn.lock`, `pnpm-lock.yaml`, `bun.lockb`) |
|
|
332
|
+
| `respectLockfile` | `true` | Use `--frozen-lockfile` / `--ci` flags during install to prevent lock file mutations |
|
|
333
|
+
|
|
334
|
+
**Auto-detection order:** `bun.lockb` → bun, `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm, fallback to `default`.
|
|
335
|
+
|
|
336
|
+
**Set explicitly:** `node "$HOME/.claude/ez-agents/bin/ez-tools.cjs" config-set packageManager.default pnpm`
|
|
337
|
+
|
|
338
|
+
</package_manager_config>
|
|
339
|
+
|
|
200
340
|
</planning_config>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Tier Strategy Reference
|
|
2
|
+
|
|
3
|
+
Decision reference for git branching and release strategy per tier.
|
|
4
|
+
|
|
5
|
+
## Quick Decision Matrix
|
|
6
|
+
|
|
7
|
+
| Question | MVP | Medium | Enterprise |
|
|
8
|
+
|----------|-----|--------|------------|
|
|
9
|
+
| Git strategy | Trunk (tag main) | GitHub Flow | GitFlow |
|
|
10
|
+
| Release branch | None | `release/vX.Y.Z` | `release/vX.Y.Z` from develop |
|
|
11
|
+
| Hotfix to develop? | No | No | Yes |
|
|
12
|
+
| PR required? | No | Yes (optional) | Yes (required) |
|
|
13
|
+
| Coverage gate | 60% | 80% | 95% |
|
|
14
|
+
| Checklist items | 6 | 18 | 30 |
|
|
15
|
+
| MoSCoW scope | @must | @must + @should | All |
|
|
16
|
+
| Rollback window | 30 min | 15 min | 5 min |
|
|
17
|
+
|
|
18
|
+
## When to Use Each Tier
|
|
19
|
+
|
|
20
|
+
**MVP** — You need to ship NOW
|
|
21
|
+
- First public release
|
|
22
|
+
- Early access / beta
|
|
23
|
+
- Founder-driven sales demo
|
|
24
|
+
- Internal tool, no SLA
|
|
25
|
+
|
|
26
|
+
**Medium** — Real users, real consequences
|
|
27
|
+
- General availability
|
|
28
|
+
- Paying customers
|
|
29
|
+
- Public-facing product
|
|
30
|
+
- Team of 2-10 developers
|
|
31
|
+
|
|
32
|
+
**Enterprise** — Compliance matters
|
|
33
|
+
- Fortune 500 customers
|
|
34
|
+
- Regulated industry (finance, health, legal)
|
|
35
|
+
- SOC2 / GDPR required
|
|
36
|
+
- 24/7 SLA commitment
|
|
37
|
+
|
|
38
|
+
## Tier Promotion Path
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Initial release → MVP v1.0.0
|
|
42
|
+
↓ (enough users to need reliability)
|
|
43
|
+
GA release → Medium v1.5.0
|
|
44
|
+
↓ (enterprise deal signed)
|
|
45
|
+
Enterprise → v2.0.0
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Each promotion is additive — enterprise features are behind feature flags in the codebase from day one. Promotion just enables the flags and runs the stricter checklist.
|
|
49
|
+
|
|
50
|
+
## Feature Flag Convention
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// In code: guard enterprise/medium features
|
|
54
|
+
const ENABLE_SHOULD_FEATURES = process.env.ENABLE_SHOULD_FEATURES === 'true';
|
|
55
|
+
const ENABLE_COULD_FEATURES = process.env.ENABLE_COULD_FEATURES === 'true';
|
|
56
|
+
|
|
57
|
+
// MVP deploy: both = false (no overhead)
|
|
58
|
+
// Medium deploy: SHOULD = true
|
|
59
|
+
// Enterprise: SHOULD = true, COULD = true
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## GitFlow (Enterprise) Branch Layout
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
main ← production releases (tagged)
|
|
66
|
+
develop ← integration branch
|
|
67
|
+
feature/* ← new features
|
|
68
|
+
fix/* ← bug fixes
|
|
69
|
+
release/vX.Y.Z ← release preparation (from develop → main)
|
|
70
|
+
hotfix/* ← emergency production fixes (from main → main + develop)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## GitHub Flow (Medium) Branch Layout
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
main ← production (deploy on merge)
|
|
77
|
+
feature/* ← all work branches
|
|
78
|
+
release/vX.Y.Z ← optional: release prep branch
|
|
79
|
+
hotfix/* ← emergency fixes
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Trunk-Based (MVP) Branch Layout
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
main ← production + development
|
|
86
|
+
task/* ← short-lived feature branches (optional)
|
|
87
|
+
← hotfix directly if needed
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Config Location
|
|
91
|
+
|
|
92
|
+
Tier is stored in `.planning/config.json`:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"release": {
|
|
97
|
+
"tier": "mvp",
|
|
98
|
+
"tiers": { ... }
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Update with: `node ez-tools.cjs tier-manager save-tier medium`
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# BDD Feature File Template
|
|
2
|
+
|
|
3
|
+
Use this template when creating `.feature` files for a phase.
|
|
4
|
+
|
|
5
|
+
Replace `{placeholders}` with actual content.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
```gherkin
|
|
10
|
+
# specs/features/{domain}/{feature-name}.feature
|
|
11
|
+
#
|
|
12
|
+
# Feature: {feature-name}
|
|
13
|
+
# Phase: {phase-number} — {phase-name}
|
|
14
|
+
# MoSCoW: @must | @should | @could | @wont
|
|
15
|
+
# Tier: @mvp | @medium | @enterprise
|
|
16
|
+
#
|
|
17
|
+
# Requirements: {REQ-IDs this feature satisfies}
|
|
18
|
+
|
|
19
|
+
Feature: {Feature Name}
|
|
20
|
+
As a {user role}
|
|
21
|
+
I want to {action/capability}
|
|
22
|
+
So that {benefit/value delivered}
|
|
23
|
+
|
|
24
|
+
# Background sets up shared preconditions for all scenarios in this Feature.
|
|
25
|
+
# Remove if no shared setup needed.
|
|
26
|
+
Background:
|
|
27
|
+
Given {shared precondition 1}
|
|
28
|
+
And {shared precondition 2}
|
|
29
|
+
|
|
30
|
+
# ─────────────────────────────────────────────
|
|
31
|
+
# MUST — Required for MVP (phase gate)
|
|
32
|
+
# ─────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
@must @mvp
|
|
35
|
+
Scenario: {Happy path — primary success case}
|
|
36
|
+
Given {initial context / system state}
|
|
37
|
+
When {user performs action}
|
|
38
|
+
Then {expected outcome}
|
|
39
|
+
And {additional assertion}
|
|
40
|
+
|
|
41
|
+
@must @mvp
|
|
42
|
+
Scenario: {Primary error case}
|
|
43
|
+
Given {initial context}
|
|
44
|
+
When {user performs invalid action}
|
|
45
|
+
Then {expected error response}
|
|
46
|
+
And {system remains in valid state}
|
|
47
|
+
|
|
48
|
+
# ─────────────────────────────────────────────
|
|
49
|
+
# SHOULD — Target for medium tier release
|
|
50
|
+
# ─────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
@should @medium
|
|
53
|
+
Scenario: {Secondary success case or edge case}
|
|
54
|
+
Given {context}
|
|
55
|
+
When {action}
|
|
56
|
+
Then {outcome}
|
|
57
|
+
|
|
58
|
+
@should @medium
|
|
59
|
+
Scenario: {Error recovery or retry flow}
|
|
60
|
+
Given {context where partial failure occurred}
|
|
61
|
+
When {user attempts recovery}
|
|
62
|
+
Then {system handles gracefully}
|
|
63
|
+
|
|
64
|
+
# ─────────────────────────────────────────────
|
|
65
|
+
# COULD — Nice-to-have for enterprise tier
|
|
66
|
+
# ─────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
@could @enterprise
|
|
69
|
+
Scenario: {Advanced or compliance feature}
|
|
70
|
+
Given {enterprise context}
|
|
71
|
+
When {action}
|
|
72
|
+
Then {enterprise-specific outcome}
|
|
73
|
+
|
|
74
|
+
# ─────────────────────────────────────────────
|
|
75
|
+
# WONT — Explicitly deferred (document reasons)
|
|
76
|
+
# ─────────────────────────────────────────────
|
|
77
|
+
# @wont — SSO integration: deferred to Phase XX, depends on identity provider decision
|
|
78
|
+
# @wont — Biometric auth: deferred — mobile-only feature, out of scope for web
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Scenario Writing Guide
|
|
84
|
+
|
|
85
|
+
### Given (Precondition)
|
|
86
|
+
Sets up the world before the action. Should be:
|
|
87
|
+
- Specific: "Given a user exists with email test@example.com" not "Given a user exists"
|
|
88
|
+
- Minimal: Only include context relevant to this scenario
|
|
89
|
+
- Reusable: Use Background for context shared by all scenarios
|
|
90
|
+
|
|
91
|
+
```gherkin
|
|
92
|
+
# Good
|
|
93
|
+
Given a registered user with email "alice@example.com" exists
|
|
94
|
+
And the user's account is in "active" status
|
|
95
|
+
|
|
96
|
+
# Bad (too vague)
|
|
97
|
+
Given there is a user
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### When (Action)
|
|
101
|
+
The single event being tested. Rules:
|
|
102
|
+
- One action per scenario (split if multiple)
|
|
103
|
+
- Active voice: "When I submit the form" not "When the form is submitted"
|
|
104
|
+
- From user's perspective
|
|
105
|
+
|
|
106
|
+
```gherkin
|
|
107
|
+
# Good
|
|
108
|
+
When I submit the login form with email "alice@example.com" and password "secret123"
|
|
109
|
+
|
|
110
|
+
# Bad (multiple actions)
|
|
111
|
+
When I fill in the form and click submit and wait for response
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Then (Outcome)
|
|
115
|
+
Observable, verifiable result. Must be:
|
|
116
|
+
- Testable: Can be automated
|
|
117
|
+
- Specific: Exact values, not "something happens"
|
|
118
|
+
- From user's perspective
|
|
119
|
+
|
|
120
|
+
```gherkin
|
|
121
|
+
# Good
|
|
122
|
+
Then I am redirected to "/dashboard"
|
|
123
|
+
And the page title contains "Welcome, Alice"
|
|
124
|
+
And a session cookie named "ez_session" is present
|
|
125
|
+
|
|
126
|
+
# Bad (subjective)
|
|
127
|
+
Then it works correctly
|
|
128
|
+
And the user is happy
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### And / But
|
|
132
|
+
- `And` — continues the clause type (Given+And, When+And, Then+And)
|
|
133
|
+
- `But` — negative assertion ("But I should not see...")
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## MoSCoW Quick Reference
|
|
138
|
+
|
|
139
|
+
| Tag | When to Use | Tier |
|
|
140
|
+
|-----|-------------|------|
|
|
141
|
+
| `@must` | System is broken/unusable without it | `@mvp` |
|
|
142
|
+
| `@should` | Important but workaround exists | `@medium` |
|
|
143
|
+
| `@could` | Enhances experience but not critical | `@enterprise` |
|
|
144
|
+
| `@wont` | Explicitly out of scope (document why) | — |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## File Naming Convention
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
specs/
|
|
152
|
+
features/
|
|
153
|
+
{domain}/
|
|
154
|
+
{feature-name}.feature # e.g., auth/login.feature
|
|
155
|
+
{feature-name}.feature # e.g., auth/registration.feature
|
|
156
|
+
{domain2}/
|
|
157
|
+
{feature-name}.feature
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Domain examples: `auth`, `payments`, `dashboard`, `onboarding`, `settings`, `api`
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## INVEST Checklist
|
|
165
|
+
|
|
166
|
+
Before finalizing a Feature, verify all scenarios as a group:
|
|
167
|
+
|
|
168
|
+
- [ ] **Independent**: Feature can be developed without dependency on other features in this file
|
|
169
|
+
- [ ] **Negotiable**: Implementation details (not described in Then) are flexible
|
|
170
|
+
- [ ] **Valuable**: The Feature statement explains clear user value
|
|
171
|
+
- [ ] **Estimable**: A developer can estimate effort from these scenarios
|
|
172
|
+
- [ ] **Small**: All @must scenarios fit in one phase (split if more than ~8 must scenarios)
|
|
173
|
+
- [ ] **Testable**: Every Then clause can be automated
|