@planu/cli 5.3.63 → 5.3.65
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/CHANGELOG.md +35 -0
- package/dist/.planu-build.json +1 -1
- package/dist/cli/commands/create.js +3 -16
- package/dist/cli/commands/dashboard.js +2 -16
- package/dist/cli/commands/init.js +2 -16
- package/dist/cli/commands/spec.js +5 -36
- package/dist/cli/commands/status.js +5 -28
- package/dist/cli/formatter.d.ts +7 -1
- package/dist/cli/formatter.js +49 -6
- package/dist/engine/cascade-hooks/hooks/implementing-kickoff.hook.js +38 -6
- package/dist/engine/dor-dod/index.d.ts +1 -1
- package/dist/engine/dor-dod/index.js +1 -1
- package/dist/engine/dor-dod/plan.d.ts +1 -0
- package/dist/engine/dor-dod/plan.js +2 -0
- package/dist/engine/evidence-gates/artifact-reader.js +1 -0
- package/dist/engine/evidence-gates/evidence-skeletons.js +1 -0
- package/dist/engine/execution-plan/plan-utils.d.ts +2 -6
- package/dist/engine/execution-plan/plan-utils.js +71 -37
- package/dist/engine/handoff-artifacts/implementation-review-reader.d.ts +4 -0
- package/dist/engine/handoff-artifacts/implementation-review-reader.js +72 -0
- package/dist/engine/validator/dor-dod.d.ts +2 -2
- package/dist/engine/validator/dor-dod.js +5 -4
- package/dist/storage/knowledge-store/knowledge.js +31 -1
- package/dist/tools/challenge-spec/agent-challenge-scenarios.js +30 -9
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-a.d.ts +2 -4
- package/dist/tools/challenge-spec/resilience-challenge-scenarios-a.js +24 -24
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +1 -1
- package/dist/tools/challenge-spec/scenarios-failure.js +1 -2
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +3 -0
- package/dist/tools/challenge-spec/scenarios-utils.js +16 -0
- package/dist/tools/challenge-spec-helpers.d.ts +1 -1
- package/dist/tools/challenge-spec-helpers.js +5 -2
- package/dist/tools/challenge-spec.js +5 -2
- package/dist/tools/create-spec.js +18 -0
- package/dist/tools/generate-execution-plan.js +160 -54
- package/dist/tools/update-status/dod-gates.js +46 -64
- package/dist/tools/update-status/side-effects.d.ts +4 -0
- package/dist/tools/update-status/side-effects.js +45 -4
- package/dist/tools/validate.js +8 -4
- package/dist/transports/transport-factory.js +13 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/evidence-gates.d.ts +2 -0
- package/dist/types/execution.d.ts +5 -0
- package/dist/types/handoff-artifacts.d.ts +19 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
- package/planu-plugin.json +1 -1
- package/scripts/lib/portable-paths.mjs +1 -0
- package/dist/engine/execution-plan/phases-b.d.ts +0 -4
- package/dist/engine/execution-plan/phases-b.js +0 -88
- package/dist/engine/execution-plan/phases.d.ts +0 -7
- package/dist/engine/execution-plan/phases.js +0 -216
|
@@ -146,4 +146,23 @@ export interface ArtifactPayloadMap {
|
|
|
146
146
|
}
|
|
147
147
|
export type ArtifactPayload<K extends ArtifactKind> = ArtifactPayloadMap[K];
|
|
148
148
|
import type { MinimalImplementationReport } from './minimal-implementation-gate.js';
|
|
149
|
+
export type ImplementationReviewRejectionReason = 'missing' | 'unreadable' | 'schema_invalid' | 'stub_body' | 'wrong_agent_or_kind' | 'not_approved' | 'self_review' | 'actor_unreadable' | 'wrong_spec';
|
|
150
|
+
export interface VerifiedImplementationReviewOk {
|
|
151
|
+
ok: true;
|
|
152
|
+
review: ImplementationReviewV1;
|
|
153
|
+
implementingActor: string | null;
|
|
154
|
+
}
|
|
155
|
+
export interface VerifiedImplementationReviewErr {
|
|
156
|
+
ok: false;
|
|
157
|
+
reason: ImplementationReviewRejectionReason;
|
|
158
|
+
review?: ImplementationReviewV1;
|
|
159
|
+
implementingActor?: string;
|
|
160
|
+
errors?: {
|
|
161
|
+
code: string;
|
|
162
|
+
path: string;
|
|
163
|
+
message: string;
|
|
164
|
+
}[];
|
|
165
|
+
readError?: string;
|
|
166
|
+
}
|
|
167
|
+
export type VerifiedImplementationReviewResult = VerifiedImplementationReviewOk | VerifiedImplementationReviewErr;
|
|
149
168
|
//# sourceMappingURL=handoff-artifacts.d.ts.map
|
package/dist/types/index.d.ts
CHANGED
|
@@ -291,4 +291,5 @@ export * from './host-tool-filter.js';
|
|
|
291
291
|
export * from './reconcile.js';
|
|
292
292
|
export * from './release-pipeline.js';
|
|
293
293
|
export * from './network-policy.js';
|
|
294
|
+
export type { VerifiedImplementationReviewResult, VerifiedImplementationReviewOk, VerifiedImplementationReviewErr, ImplementationReviewRejectionReason, } from './handoff-artifacts.js';
|
|
294
295
|
//# sourceMappingURL=index.d.ts.map
|
package/package.json
CHANGED
package/planu-plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dev.planu.cli",
|
|
3
3
|
"displayName": "Planu — Spec Driven Development",
|
|
4
4
|
"description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
|
|
5
|
-
"version": "5.3.
|
|
5
|
+
"version": "5.3.65",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": ["npx", "@planu/cli@latest"],
|
|
8
8
|
"packageName": "@planu/cli",
|
|
@@ -47,6 +47,7 @@ export function portablePathPatterns({
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export function redactPortablePaths(text, options = {}) {
|
|
50
|
+
if (typeof text !== 'string') return text;
|
|
50
51
|
return portablePathPatterns(options).reduce(
|
|
51
52
|
(redacted, { pattern, replacement }) => redacted.replace(pattern, replacement),
|
|
52
53
|
text,
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { Spec, ProjectKnowledge, ExecutionStep } from '../../types/index.js';
|
|
2
|
-
export declare function generateTestingPhase(spec: Spec, knowledge: ProjectKnowledge, startOrder: number): ExecutionStep[];
|
|
3
|
-
export declare function generateIntegrationPhase(_spec: Spec, knowledge: ProjectKnowledge, startOrder: number): ExecutionStep[];
|
|
4
|
-
//# sourceMappingURL=phases-b.d.ts.map
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// engine/execution-plan/phases-b.ts — Execution phase generators (part B)
|
|
2
|
-
// SRP: testing and integration phase generators.
|
|
3
|
-
// OCP: extend without modifying the dispatcher in generate-execution-plan.ts.
|
|
4
|
-
export function generateTestingPhase(spec, knowledge, startOrder) {
|
|
5
|
-
const steps = [];
|
|
6
|
-
let order = startOrder;
|
|
7
|
-
steps.push({
|
|
8
|
-
order: order++,
|
|
9
|
-
title: 'Write unit tests',
|
|
10
|
-
description: 'Test business logic, validators, and utilities in isolation',
|
|
11
|
-
files: [`tests/unit/${spec.slug}.test.ts`],
|
|
12
|
-
dependsOn: [startOrder - 1],
|
|
13
|
-
verification: `All unit tests pass: ${knowledge.testCommand ?? 'npm test'}`,
|
|
14
|
-
estimatedMinutes: 30,
|
|
15
|
-
canRollback: true,
|
|
16
|
-
});
|
|
17
|
-
if (spec.scope !== 'trivial') {
|
|
18
|
-
steps.push({
|
|
19
|
-
order: order++,
|
|
20
|
-
title: 'Write integration tests',
|
|
21
|
-
description: 'Test API endpoints and data layer together',
|
|
22
|
-
files: [`tests/integration/${spec.slug}.test.ts`],
|
|
23
|
-
dependsOn: [startOrder],
|
|
24
|
-
verification: 'Integration tests pass against test database',
|
|
25
|
-
estimatedMinutes: 30,
|
|
26
|
-
canRollback: true,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
if (spec.target === 'frontend' || spec.target === 'fullstack') {
|
|
30
|
-
steps.push({
|
|
31
|
-
order: order,
|
|
32
|
-
title: 'Write E2E tests',
|
|
33
|
-
description: 'Test critical user flows end-to-end (Playwright/Cypress)',
|
|
34
|
-
files: [`tests/e2e/${spec.slug}.spec.ts`],
|
|
35
|
-
dependsOn: [startOrder],
|
|
36
|
-
verification: 'E2E tests pass in headless browser',
|
|
37
|
-
estimatedMinutes: 30,
|
|
38
|
-
canRollback: true,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
return steps;
|
|
42
|
-
}
|
|
43
|
-
export function generateIntegrationPhase(_spec, knowledge, startOrder) {
|
|
44
|
-
const steps = [];
|
|
45
|
-
let order = startOrder;
|
|
46
|
-
steps.push({
|
|
47
|
-
order: order++,
|
|
48
|
-
title: 'Run linting and formatting',
|
|
49
|
-
description: 'Ensure code passes all lint rules and is properly formatted',
|
|
50
|
-
files: [],
|
|
51
|
-
dependsOn: [startOrder - 1],
|
|
52
|
-
verification: `Lint passes: ${knowledge.linting.detectedLinters[0]?.tool ?? 'eslint'} runs clean`,
|
|
53
|
-
estimatedMinutes: 10,
|
|
54
|
-
canRollback: true,
|
|
55
|
-
});
|
|
56
|
-
steps.push({
|
|
57
|
-
order: order++,
|
|
58
|
-
title: 'Update documentation',
|
|
59
|
-
description: 'Update README, API docs, and changelog if applicable',
|
|
60
|
-
files: [],
|
|
61
|
-
dependsOn: [startOrder],
|
|
62
|
-
verification: 'Documentation reflects the new changes',
|
|
63
|
-
estimatedMinutes: 15,
|
|
64
|
-
canRollback: true,
|
|
65
|
-
});
|
|
66
|
-
steps.push({
|
|
67
|
-
order: order++,
|
|
68
|
-
title: 'Full build and test suite',
|
|
69
|
-
description: 'Run complete build and all test suites to catch regressions',
|
|
70
|
-
files: [],
|
|
71
|
-
dependsOn: [order - 2, order - 1],
|
|
72
|
-
verification: `Full build succeeds: ${knowledge.buildCommand ?? 'npm run build'} && ${knowledge.testCommand ?? 'npm test'}`,
|
|
73
|
-
estimatedMinutes: 10,
|
|
74
|
-
canRollback: true,
|
|
75
|
-
});
|
|
76
|
-
steps.push({
|
|
77
|
-
order: order++,
|
|
78
|
-
title: 'Create pull request',
|
|
79
|
-
description: 'Push branch and create PR with spec reference and summary',
|
|
80
|
-
files: [],
|
|
81
|
-
dependsOn: [order - 2],
|
|
82
|
-
verification: 'PR created with passing CI checks',
|
|
83
|
-
estimatedMinutes: 10,
|
|
84
|
-
canRollback: true,
|
|
85
|
-
});
|
|
86
|
-
return steps;
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=phases-b.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Spec, ProjectKnowledge, ExecutionStep } from '../../types/index.js';
|
|
2
|
-
export { generateTestingPhase, generateIntegrationPhase } from './phases-b.js';
|
|
3
|
-
export declare function generateSetupPhase(spec: Spec, knowledge: ProjectKnowledge, startOrder: number): ExecutionStep[];
|
|
4
|
-
export declare function generateDataLayerPhase(spec: Spec, knowledge: ProjectKnowledge, content: string, startOrder: number): ExecutionStep[];
|
|
5
|
-
export declare function generateBusinessLogicPhase(spec: Spec, knowledge: ProjectKnowledge, content: string, startOrder: number): ExecutionStep[];
|
|
6
|
-
export declare function generateUIPhase(spec: Spec, knowledge: ProjectKnowledge, content: string, startOrder: number): ExecutionStep[];
|
|
7
|
-
//# sourceMappingURL=phases.d.ts.map
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { technologyValue } from '../technology-registry.js';
|
|
2
|
-
import { inferDataLayerFiles, inferServiceFiles, inferApiFiles, inferPageFiles, inferComponentFiles, } from './plan-utils.js';
|
|
3
|
-
export { generateTestingPhase, generateIntegrationPhase } from './phases-b.js';
|
|
4
|
-
export function generateSetupPhase(spec, knowledge, startOrder) {
|
|
5
|
-
const steps = [];
|
|
6
|
-
let order = startOrder;
|
|
7
|
-
steps.push({
|
|
8
|
-
order: order++,
|
|
9
|
-
title: 'Create feature branch',
|
|
10
|
-
description: `Create branch from main: ${spec.gitBranch || `feature/${spec.slug}`}`,
|
|
11
|
-
files: [],
|
|
12
|
-
dependsOn: [],
|
|
13
|
-
verification: `Branch exists and is checked out: git branch --show-current`,
|
|
14
|
-
estimatedMinutes: 2,
|
|
15
|
-
canRollback: true,
|
|
16
|
-
});
|
|
17
|
-
if (knowledge.language === technologyValue('technology-typescript-969545') ||
|
|
18
|
-
knowledge.language === 'javascript') {
|
|
19
|
-
steps.push({
|
|
20
|
-
order: order++,
|
|
21
|
-
title: 'Define types and interfaces',
|
|
22
|
-
description: 'Create TypeScript interfaces for the new entities and API contracts',
|
|
23
|
-
files: [`src/types/${spec.slug}.ts`],
|
|
24
|
-
dependsOn: [startOrder],
|
|
25
|
-
verification: 'TypeScript compiles without errors: npm run build',
|
|
26
|
-
estimatedMinutes: 15,
|
|
27
|
-
canRollback: true,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
if (spec.scope === 'cross-module' || spec.scope === 'architectural') {
|
|
31
|
-
steps.push({
|
|
32
|
-
order: order,
|
|
33
|
-
title: 'Update project configuration',
|
|
34
|
-
description: 'Add new configuration entries, feature flags, or environment variables',
|
|
35
|
-
files: ['.env.example'],
|
|
36
|
-
dependsOn: [startOrder],
|
|
37
|
-
verification: 'Configuration values are documented and have defaults',
|
|
38
|
-
estimatedMinutes: 10,
|
|
39
|
-
canRollback: true,
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return steps;
|
|
43
|
-
}
|
|
44
|
-
export function generateDataLayerPhase(spec, knowledge, content, startOrder) {
|
|
45
|
-
const steps = [];
|
|
46
|
-
let order = startOrder;
|
|
47
|
-
const lower = content.toLowerCase();
|
|
48
|
-
if (lower.includes('table') ||
|
|
49
|
-
lower.includes('schema') ||
|
|
50
|
-
lower.includes('model') ||
|
|
51
|
-
lower.includes('entity') ||
|
|
52
|
-
lower.includes('migration') ||
|
|
53
|
-
knowledge.database !== 'unknown') {
|
|
54
|
-
steps.push({
|
|
55
|
-
order: order++,
|
|
56
|
-
title: 'Create database migration',
|
|
57
|
-
description: `Create migration for new tables/columns in ${knowledge.database}`,
|
|
58
|
-
files: [`migrations/${spec.slug}.sql`],
|
|
59
|
-
dependsOn: [startOrder - 1],
|
|
60
|
-
verification: 'Migration runs successfully: apply and rollback both work',
|
|
61
|
-
estimatedMinutes: 20,
|
|
62
|
-
canRollback: true,
|
|
63
|
-
});
|
|
64
|
-
steps.push({
|
|
65
|
-
order: order++,
|
|
66
|
-
title: 'Run migration on development database',
|
|
67
|
-
description: 'Apply migration and verify schema changes',
|
|
68
|
-
files: [],
|
|
69
|
-
dependsOn: [order - 2],
|
|
70
|
-
verification: 'Database schema matches expected state',
|
|
71
|
-
estimatedMinutes: 5,
|
|
72
|
-
canRollback: true,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
const lastStep = steps[steps.length - 1];
|
|
76
|
-
steps.push({
|
|
77
|
-
order: order++,
|
|
78
|
-
title: 'Implement data access layer',
|
|
79
|
-
description: 'Create repository/model functions for CRUD operations',
|
|
80
|
-
files: inferDataLayerFiles(spec, knowledge),
|
|
81
|
-
dependsOn: lastStep ? [lastStep.order] : [startOrder - 1],
|
|
82
|
-
verification: 'Data access functions compile. Write unit tests for basic CRUD.',
|
|
83
|
-
estimatedMinutes: 30,
|
|
84
|
-
canRollback: true,
|
|
85
|
-
});
|
|
86
|
-
if (lower.includes('seed') || lower.includes('fixture') || lower.includes('sample data')) {
|
|
87
|
-
steps.push({
|
|
88
|
-
order: order++,
|
|
89
|
-
title: 'Create seed data',
|
|
90
|
-
description: 'Add seed/fixture data for development and testing',
|
|
91
|
-
files: [`seeds/${spec.slug}.ts`],
|
|
92
|
-
dependsOn: [order - 2],
|
|
93
|
-
verification: 'Seed command runs without errors',
|
|
94
|
-
estimatedMinutes: 15,
|
|
95
|
-
canRollback: true,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return steps;
|
|
99
|
-
}
|
|
100
|
-
export function generateBusinessLogicPhase(spec, knowledge, content, startOrder) {
|
|
101
|
-
const steps = [];
|
|
102
|
-
let order = startOrder;
|
|
103
|
-
const lower = content.toLowerCase();
|
|
104
|
-
steps.push({
|
|
105
|
-
order: order++,
|
|
106
|
-
title: 'Implement business logic',
|
|
107
|
-
description: 'Create service/use-case functions with core domain logic',
|
|
108
|
-
files: inferServiceFiles(spec, knowledge),
|
|
109
|
-
dependsOn: [startOrder - 1],
|
|
110
|
-
verification: 'Business logic functions pass unit tests with valid and invalid inputs',
|
|
111
|
-
estimatedMinutes: 45,
|
|
112
|
-
canRollback: true,
|
|
113
|
-
});
|
|
114
|
-
if (lower.includes('validat') || lower.includes('input') || lower.includes('form')) {
|
|
115
|
-
steps.push({
|
|
116
|
-
order: order++,
|
|
117
|
-
title: 'Implement input validation',
|
|
118
|
-
description: 'Add validation schemas for all inputs (Zod/Joi/class-validator)',
|
|
119
|
-
files: [`src/validators/${spec.slug}.ts`],
|
|
120
|
-
dependsOn: [startOrder],
|
|
121
|
-
verification: 'Validation rejects invalid inputs with clear error messages',
|
|
122
|
-
estimatedMinutes: 20,
|
|
123
|
-
canRollback: true,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (lower.includes('api') ||
|
|
127
|
-
lower.includes('endpoint') ||
|
|
128
|
-
lower.includes('route') ||
|
|
129
|
-
spec.target === 'backend' ||
|
|
130
|
-
spec.target === 'fullstack') {
|
|
131
|
-
steps.push({
|
|
132
|
-
order: order++,
|
|
133
|
-
title: 'Create API endpoints',
|
|
134
|
-
description: 'Implement REST/GraphQL/tRPC endpoints with request handling',
|
|
135
|
-
files: inferApiFiles(spec, knowledge),
|
|
136
|
-
dependsOn: [startOrder],
|
|
137
|
-
verification: 'Endpoints respond correctly: test with curl or HTTP client',
|
|
138
|
-
estimatedMinutes: 30,
|
|
139
|
-
canRollback: true,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
steps.push({
|
|
143
|
-
order: order++,
|
|
144
|
-
title: 'Add error handling',
|
|
145
|
-
description: 'Implement structured error handling, logging, and error responses',
|
|
146
|
-
files: [],
|
|
147
|
-
dependsOn: [order - 2],
|
|
148
|
-
verification: 'Error cases return proper status codes and error messages',
|
|
149
|
-
estimatedMinutes: 15,
|
|
150
|
-
canRollback: true,
|
|
151
|
-
});
|
|
152
|
-
return steps;
|
|
153
|
-
}
|
|
154
|
-
export function generateUIPhase(spec, knowledge, content, startOrder) {
|
|
155
|
-
const steps = [];
|
|
156
|
-
let order = startOrder;
|
|
157
|
-
const lower = content.toLowerCase();
|
|
158
|
-
const framework = knowledge.framework ?? technologyValue('technology-react-275976');
|
|
159
|
-
steps.push({
|
|
160
|
-
order: order++,
|
|
161
|
-
title: 'Create page layout and routing',
|
|
162
|
-
description: `Set up page structure and routes in ${framework}`,
|
|
163
|
-
files: inferPageFiles(spec, knowledge),
|
|
164
|
-
dependsOn: [startOrder - 1],
|
|
165
|
-
verification: 'Page renders without errors. Route is accessible.',
|
|
166
|
-
estimatedMinutes: 20,
|
|
167
|
-
canRollback: true,
|
|
168
|
-
});
|
|
169
|
-
steps.push({
|
|
170
|
-
order: order++,
|
|
171
|
-
title: 'Build UI components',
|
|
172
|
-
description: 'Implement reusable components (forms, lists, cards, etc.)',
|
|
173
|
-
files: inferComponentFiles(spec, knowledge),
|
|
174
|
-
dependsOn: [startOrder],
|
|
175
|
-
verification: 'Components render correctly with mock data',
|
|
176
|
-
estimatedMinutes: 45,
|
|
177
|
-
canRollback: true,
|
|
178
|
-
});
|
|
179
|
-
steps.push({
|
|
180
|
-
order: order++,
|
|
181
|
-
title: 'Connect data fetching',
|
|
182
|
-
description: 'Wire components to API, add loading and error states',
|
|
183
|
-
files: [],
|
|
184
|
-
dependsOn: [order - 2, order - 1],
|
|
185
|
-
verification: 'Data loads from API. Loading spinners show. Errors display correctly.',
|
|
186
|
-
estimatedMinutes: 30,
|
|
187
|
-
canRollback: true,
|
|
188
|
-
});
|
|
189
|
-
if (lower.includes('form') ||
|
|
190
|
-
lower.includes('create') ||
|
|
191
|
-
lower.includes('edit') ||
|
|
192
|
-
lower.includes('input')) {
|
|
193
|
-
steps.push({
|
|
194
|
-
order: order++,
|
|
195
|
-
title: 'Implement form handling and validation',
|
|
196
|
-
description: 'Add form state management, client-side validation, and submission',
|
|
197
|
-
files: [],
|
|
198
|
-
dependsOn: [order - 2],
|
|
199
|
-
verification: 'Form submits successfully. Validation errors show inline. Submit button disables during submission.',
|
|
200
|
-
estimatedMinutes: 25,
|
|
201
|
-
canRollback: true,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
steps.push({
|
|
205
|
-
order: order++,
|
|
206
|
-
title: 'Add responsive design and accessibility',
|
|
207
|
-
description: 'Ensure UI works on mobile, tablet, and desktop. Add ARIA labels.',
|
|
208
|
-
files: [],
|
|
209
|
-
dependsOn: [order - 2],
|
|
210
|
-
verification: 'UI passes basic responsive checks. No accessibility violations on axe/Lighthouse.',
|
|
211
|
-
estimatedMinutes: 20,
|
|
212
|
-
canRollback: true,
|
|
213
|
-
});
|
|
214
|
-
return steps;
|
|
215
|
-
}
|
|
216
|
-
//# sourceMappingURL=phases.js.map
|