spec-gen-cli 1.2.6 → 1.2.8
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 +175 -55
- package/dist/api/analyze.d.ts.map +1 -1
- package/dist/api/analyze.js +6 -1
- package/dist/api/analyze.js.map +1 -1
- package/dist/api/audit.d.ts +10 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +117 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/generate.d.ts.map +1 -1
- package/dist/api/generate.js +10 -1
- package/dist/api/generate.js.map +1 -1
- package/dist/api/index.d.ts +3 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/run.d.ts.map +1 -1
- package/dist/api/run.js +5 -1
- package/dist/api/run.js.map +1 -1
- package/dist/api/types.d.ts +15 -4
- package/dist/api/types.d.ts.map +1 -1
- package/dist/cli/commands/analyze.d.ts +3 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -1
- package/dist/cli/commands/analyze.js +112 -17
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/audit.d.ts +9 -0
- package/dist/cli/commands/audit.d.ts.map +1 -0
- package/dist/cli/commands/audit.js +98 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/drift.d.ts.map +1 -1
- package/dist/cli/commands/drift.js +8 -10
- package/dist/cli/commands/drift.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +15 -37
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts +102 -2
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +134 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +9 -47
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/setup.d.ts +17 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +201 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +7 -8
- package/dist/cli/commands/verify.js.map +1 -1
- package/dist/cli/index.js +14 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +14 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/analyzer/ai-config-generator.d.ts +54 -0
- package/dist/core/analyzer/ai-config-generator.d.ts.map +1 -0
- package/dist/core/analyzer/ai-config-generator.js +85 -0
- package/dist/core/analyzer/ai-config-generator.js.map +1 -0
- package/dist/core/analyzer/artifact-generator.d.ts +27 -2
- package/dist/core/analyzer/artifact-generator.d.ts.map +1 -1
- package/dist/core/analyzer/artifact-generator.js +86 -8
- package/dist/core/analyzer/artifact-generator.js.map +1 -1
- package/dist/core/analyzer/codebase-digest.d.ts.map +1 -1
- package/dist/core/analyzer/codebase-digest.js +12 -11
- package/dist/core/analyzer/codebase-digest.js.map +1 -1
- package/dist/core/analyzer/env-extractor.d.ts +33 -0
- package/dist/core/analyzer/env-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/env-extractor.js +196 -0
- package/dist/core/analyzer/env-extractor.js.map +1 -0
- package/dist/core/analyzer/http-route-parser.d.ts +36 -1
- package/dist/core/analyzer/http-route-parser.d.ts.map +1 -1
- package/dist/core/analyzer/http-route-parser.js +276 -0
- package/dist/core/analyzer/http-route-parser.js.map +1 -1
- package/dist/core/analyzer/middleware-extractor.d.ts +29 -0
- package/dist/core/analyzer/middleware-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/middleware-extractor.js +195 -0
- package/dist/core/analyzer/middleware-extractor.js.map +1 -0
- package/dist/core/analyzer/schema-extractor.d.ts +41 -0
- package/dist/core/analyzer/schema-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/schema-extractor.js +229 -0
- package/dist/core/analyzer/schema-extractor.js.map +1 -0
- package/dist/core/analyzer/spec-snapshot-generator.d.ts +17 -0
- package/dist/core/analyzer/spec-snapshot-generator.d.ts.map +1 -0
- package/dist/core/analyzer/spec-snapshot-generator.js +201 -0
- package/dist/core/analyzer/spec-snapshot-generator.js.map +1 -0
- package/dist/core/analyzer/ui-component-extractor.d.ts +43 -0
- package/dist/core/analyzer/ui-component-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/ui-component-extractor.js +245 -0
- package/dist/core/analyzer/ui-component-extractor.js.map +1 -0
- package/dist/core/generator/openspec-format-generator.d.ts.map +1 -1
- package/dist/core/generator/openspec-format-generator.js +8 -0
- package/dist/core/generator/openspec-format-generator.js.map +1 -1
- package/dist/core/generator/spec-pipeline.d.ts +9 -0
- package/dist/core/generator/spec-pipeline.d.ts.map +1 -1
- package/dist/core/generator/spec-pipeline.js +94 -2
- package/dist/core/generator/spec-pipeline.js.map +1 -1
- package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -1
- package/dist/core/generator/stages/stage1-survey.js +43 -0
- package/dist/core/generator/stages/stage1-survey.js.map +1 -1
- package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -1
- package/dist/core/generator/stages/stage2-entities.js +6 -2
- package/dist/core/generator/stages/stage2-entities.js.map +1 -1
- package/dist/core/generator/stages/stage3-services.d.ts.map +1 -1
- package/dist/core/generator/stages/stage3-services.js +9 -2
- package/dist/core/generator/stages/stage3-services.js.map +1 -1
- package/dist/core/generator/stages/stage4-api.d.ts.map +1 -1
- package/dist/core/generator/stages/stage4-api.js +6 -2
- package/dist/core/generator/stages/stage4-api.js.map +1 -1
- package/dist/core/services/llm-service.d.ts +26 -10
- package/dist/core/services/llm-service.d.ts.map +1 -1
- package/dist/core/services/llm-service.js +171 -16
- package/dist/core/services/llm-service.js.map +1 -1
- package/dist/core/services/mcp-handlers/analysis.d.ts +32 -1
- package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -1
- package/dist/core/services/mcp-handlers/analysis.js +185 -2
- package/dist/core/services/mcp-handlers/analysis.js.map +1 -1
- package/dist/core/verifier/verification-engine.d.ts +67 -6
- package/dist/core/verifier/verification-engine.d.ts.map +1 -1
- package/dist/core/verifier/verification-engine.js +316 -90
- package/dist/core/verifier/verification-engine.js.map +1 -1
- package/dist/types/index.d.ts +70 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/pipeline.d.ts +9 -0
- package/dist/types/pipeline.d.ts.map +1 -1
- package/dist/utils/command-helpers.d.ts +30 -0
- package/dist/utils/command-helpers.d.ts.map +1 -1
- package/dist/utils/command-helpers.js +69 -1
- package/dist/utils/command-helpers.js.map +1 -1
- package/examples/bmad/README.md +113 -0
- package/examples/bmad/agents/architect.md +226 -0
- package/examples/bmad/agents/dev-brownfield.md +69 -0
- package/examples/bmad/setup/architect.customize.yaml +14 -0
- package/examples/bmad/tasks/implement-story.md +254 -0
- package/examples/bmad/tasks/onboarding.md +169 -0
- package/examples/bmad/tasks/refactor.md +178 -0
- package/examples/bmad/tasks/sprint-planning.md +168 -0
- package/examples/bmad/templates/story.md +108 -0
- package/examples/cline-workflows/spec-gen-analyze-codebase.md +100 -0
- package/examples/cline-workflows/spec-gen-check-spec-drift.md +102 -0
- package/examples/cline-workflows/spec-gen-execute-refactor.md +194 -0
- package/examples/cline-workflows/spec-gen-implement-feature.md +238 -0
- package/examples/cline-workflows/spec-gen-plan-refactor.md +255 -0
- package/examples/cline-workflows/spec-gen-refactor-codebase.md +16 -0
- package/examples/drift-demo/openspec/config.yaml +14 -0
- package/examples/drift-demo/openspec/specs/architecture/spec.md +30 -0
- package/examples/drift-demo/openspec/specs/auth/spec.md +71 -0
- package/examples/drift-demo/openspec/specs/database/spec.md +33 -0
- package/examples/drift-demo/openspec/specs/overview/spec.md +20 -0
- package/examples/drift-demo/openspec/specs/projects/spec.md +55 -0
- package/examples/drift-demo/openspec/specs/tasks/spec.md +78 -0
- package/examples/drift-demo/package.json +21 -0
- package/examples/drift-demo/src/auth/auth-middleware.ts +30 -0
- package/examples/drift-demo/src/auth/auth-routes.ts +29 -0
- package/examples/drift-demo/src/auth/auth-service.ts +45 -0
- package/examples/drift-demo/src/database/connection.ts +27 -0
- package/examples/drift-demo/src/index.ts +16 -0
- package/examples/drift-demo/src/projects/project-model.ts +15 -0
- package/examples/drift-demo/src/projects/project-service.ts +34 -0
- package/examples/drift-demo/src/tasks/task-model.ts +37 -0
- package/examples/drift-demo/src/tasks/task-routes.ts +53 -0
- package/examples/drift-demo/src/tasks/task-service.ts +60 -0
- package/examples/drift-demo/src/utils/validation.ts +11 -0
- package/examples/drift-demo/tests/auth.test.ts +4 -0
- package/examples/drift-demo/tests/tasks.test.ts +4 -0
- package/examples/drift-demo/tsconfig.json +10 -0
- package/examples/drift-test/run-drift-test.sh +1087 -0
- package/examples/gsd/README.md +119 -0
- package/examples/gsd/commands/gsd/spec-gen-drift.md +111 -0
- package/examples/gsd/commands/gsd/spec-gen-orient.md +191 -0
- package/examples/mistral-vibe/README.md +101 -0
- package/examples/mistral-vibe/antipatterns-template.md +18 -0
- package/examples/mistral-vibe/skills/spec-gen-analyze-codebase/SKILL.md +123 -0
- package/examples/mistral-vibe/skills/spec-gen-brainstorm/SKILL.md +379 -0
- package/examples/mistral-vibe/skills/spec-gen-debug/SKILL.md +320 -0
- package/examples/mistral-vibe/skills/spec-gen-execute-refactor/SKILL.md +210 -0
- package/examples/mistral-vibe/skills/spec-gen-generate/SKILL.md +245 -0
- package/examples/mistral-vibe/skills/spec-gen-implement-story/SKILL.md +274 -0
- package/examples/mistral-vibe/skills/spec-gen-plan-refactor/SKILL.md +251 -0
- package/examples/openspec-analysis/README.md +59 -0
- package/examples/openspec-analysis/SUMMARY.md +72 -0
- package/examples/openspec-analysis/config.json +16 -0
- package/examples/openspec-analysis/dependencies.mermaid +35 -0
- package/examples/openspec-analysis/dependency-graph.json +12116 -0
- package/examples/openspec-analysis/llm-context.json +119 -0
- package/examples/openspec-analysis/repo-structure.json +871 -0
- package/examples/openspec-cli/README.md +67 -0
- package/examples/openspec-cli/openspec/config.yaml +26 -0
- package/examples/openspec-cli/openspec/specs/architecture/spec.md +178 -0
- package/examples/openspec-cli/openspec/specs/artifact-graph/spec.md +143 -0
- package/examples/openspec-cli/openspec/specs/cli/spec.md +138 -0
- package/examples/openspec-cli/openspec/specs/overview/spec.md +60 -0
- package/examples/openspec-cli/openspec/specs/parsing/spec.md +123 -0
- package/examples/openspec-cli/openspec/specs/validation/spec.md +108 -0
- package/examples/spec-kit/README.md +104 -0
- package/examples/spec-kit/commands/drift.md +87 -0
- package/examples/spec-kit/commands/orient.md +138 -0
- package/examples/spec-kit/extension.yml +54 -0
- package/package.json +3 -6
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# spec-gen: Plan Refactor
|
|
2
|
+
|
|
3
|
+
Identify the highest-priority refactoring target using static analysis, assess
|
|
4
|
+
its blast radius, and produce a detailed written plan — saved to
|
|
5
|
+
`.spec-gen/refactor-plan.md` — that `/spec-gen-execute-refactor` can follow
|
|
6
|
+
step by step without losing context.
|
|
7
|
+
|
|
8
|
+
This workflow makes **no code changes**. It only reads and writes the plan file.
|
|
9
|
+
|
|
10
|
+
## Step 1: Confirm the project directory
|
|
11
|
+
|
|
12
|
+
Ask the user which project to analyse, or confirm the current workspace root.
|
|
13
|
+
|
|
14
|
+
<ask_followup_question>
|
|
15
|
+
<question>Which project directory should I plan the refactor for?</question>
|
|
16
|
+
<options>["Current workspace root", "Enter a different path"]</options>
|
|
17
|
+
</ask_followup_question>
|
|
18
|
+
|
|
19
|
+
## Step 2: Run static analysis
|
|
20
|
+
|
|
21
|
+
Analyse the project. If analysis already ran recently, skip unless the user
|
|
22
|
+
requests a fresh run.
|
|
23
|
+
|
|
24
|
+
<use_mcp_tool>
|
|
25
|
+
<server_name>spec-gen</server_name>
|
|
26
|
+
<tool_name>analyze_codebase</tool_name>
|
|
27
|
+
<arguments>{"directory": "$DIRECTORY"}</arguments>
|
|
28
|
+
</use_mcp_tool>
|
|
29
|
+
|
|
30
|
+
## Step 3: Get the full refactoring report
|
|
31
|
+
|
|
32
|
+
Retrieve the prioritised list of functions with structural issues.
|
|
33
|
+
|
|
34
|
+
<use_mcp_tool>
|
|
35
|
+
<server_name>spec-gen</server_name>
|
|
36
|
+
<tool_name>get_refactor_report</tool_name>
|
|
37
|
+
<arguments>{"directory": "$DIRECTORY"}</arguments>
|
|
38
|
+
</use_mcp_tool>
|
|
39
|
+
|
|
40
|
+
Present the top 5 candidates in a table: function, file, issues, priority score.
|
|
41
|
+
|
|
42
|
+
## Step 3b: Check for duplicate code (optional enrichment)
|
|
43
|
+
|
|
44
|
+
Call `get_duplicate_report` to surface clones that overlap with the top candidates.
|
|
45
|
+
If the target function (or any callee) appears in a clone group, note it in the plan:
|
|
46
|
+
consolidated duplicates reduce blast radius before extracting logic.
|
|
47
|
+
|
|
48
|
+
<use_mcp_tool>
|
|
49
|
+
<server_name>spec-gen</server_name>
|
|
50
|
+
<tool_name>get_duplicate_report</tool_name>
|
|
51
|
+
<arguments>{"directory": "$DIRECTORY"}</arguments>
|
|
52
|
+
</use_mcp_tool>
|
|
53
|
+
|
|
54
|
+
If a top candidate appears in a clone group, prepend a **Deduplication note** to the plan:
|
|
55
|
+
> "⚠️ `<function>` has N near-clones. Consolidate them first to reduce the blast radius
|
|
56
|
+
> of this refactor."
|
|
57
|
+
|
|
58
|
+
Before asking the user to pick a target, **check test coverage for the files
|
|
59
|
+
containing the top candidates**. Detect the coverage tool from the project
|
|
60
|
+
(look for `package.json` scripts, `pytest.ini`, `Cargo.toml`, `go.mod`, etc.)
|
|
61
|
+
and run it scoped to those files only:
|
|
62
|
+
|
|
63
|
+
- Node.js → `npm test -- --coverage --collectCoverageFrom="<files>"`
|
|
64
|
+
- Python → `pytest --cov=<module> --cov-report=term-missing`
|
|
65
|
+
- Rust → `cargo tarpaulin --include-files <files>`
|
|
66
|
+
- Go → `go test -cover ./...` (filter relevant packages)
|
|
67
|
+
|
|
68
|
+
For each candidate file, present a compact coverage badge:
|
|
69
|
+
|
|
70
|
+
| Function | File | Priority | Coverage |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| ... | ... | ... | 72% ✅ / 35% ⚠️ / 0% 🚫 |
|
|
73
|
+
|
|
74
|
+
Apply these thresholds to annotate each row:
|
|
75
|
+
|
|
76
|
+
| Coverage | Badge | Meaning |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| ≥ 70% lines | ✅ | Safe to refactor |
|
|
79
|
+
| 40–69% lines | ⚠️ | Write characterisation tests first |
|
|
80
|
+
| < 40% lines | 🛑 | Strongly discouraged — recommend tests first |
|
|
81
|
+
| 0% (no tests) | 🚫 | Blocked — propose a test harness before proceeding |
|
|
82
|
+
|
|
83
|
+
If **all top candidates are below 40%**, tell the user:
|
|
84
|
+
> "Every high-priority target has insufficient test coverage (< 40%). Refactoring
|
|
85
|
+
> without tests risks introducing silent regressions. I recommend writing a
|
|
86
|
+
> minimal test harness for at least one target before proceeding. Would you like
|
|
87
|
+
> me to suggest test cases based on the function signatures?"
|
|
88
|
+
|
|
89
|
+
Then ask the user which one to tackle first, or pick the top one by default.
|
|
90
|
+
Prefer candidates with higher coverage when scores are otherwise close.
|
|
91
|
+
|
|
92
|
+
## Step 4: Assess impact
|
|
93
|
+
|
|
94
|
+
For the chosen function, get the full impact analysis.
|
|
95
|
+
|
|
96
|
+
<use_mcp_tool>
|
|
97
|
+
<server_name>spec-gen</server_name>
|
|
98
|
+
<tool_name>analyze_impact</tool_name>
|
|
99
|
+
<arguments>{"directory": "$DIRECTORY", "symbol": "$FUNCTION_NAME"}</arguments>
|
|
100
|
+
</use_mcp_tool>
|
|
101
|
+
|
|
102
|
+
Note:
|
|
103
|
+
- Risk score (0–100) and what it means
|
|
104
|
+
- Recommended strategy (extract / split / facade / delegate)
|
|
105
|
+
- Upstream callers and downstream callees (keep the top 5 of each for the plan)
|
|
106
|
+
|
|
107
|
+
## Step 5: Visualise the call neighbourhood
|
|
108
|
+
|
|
109
|
+
Render the subgraph to map callers and callees precisely.
|
|
110
|
+
|
|
111
|
+
<use_mcp_tool>
|
|
112
|
+
<server_name>spec-gen</server_name>
|
|
113
|
+
<tool_name>get_subgraph</tool_name>
|
|
114
|
+
<arguments>{"directory": "$DIRECTORY", "functionName": "$FUNCTION_NAME", "direction": "both", "format": "mermaid"}</arguments>
|
|
115
|
+
</use_mcp_tool>
|
|
116
|
+
|
|
117
|
+
Show the Mermaid diagram to the user.
|
|
118
|
+
|
|
119
|
+
## Step 6: Find safe entry points
|
|
120
|
+
|
|
121
|
+
Identify low-risk leaf functions that can be extracted first (bottom-up).
|
|
122
|
+
|
|
123
|
+
<use_mcp_tool>
|
|
124
|
+
<server_name>spec-gen</server_name>
|
|
125
|
+
<tool_name>get_low_risk_refactor_candidates</tool_name>
|
|
126
|
+
<arguments>{"directory": "$DIRECTORY", "filePattern": "$TARGET_FILE", "limit": 5}</arguments>
|
|
127
|
+
</use_mcp_tool>
|
|
128
|
+
|
|
129
|
+
Cross-reference with the subgraph from Step 5: a candidate is a good first
|
|
130
|
+
extraction if it already appears as a callee of the target function.
|
|
131
|
+
|
|
132
|
+
## Step 6b: Find insertion points for extracted helpers
|
|
133
|
+
|
|
134
|
+
Before designing the change sequence, identify where extracted functions should land.
|
|
135
|
+
This avoids creating helpers in the wrong file or layer.
|
|
136
|
+
|
|
137
|
+
<use_mcp_tool>
|
|
138
|
+
<server_name>spec-gen</server_name>
|
|
139
|
+
<tool_name>suggest_insertion_points</tool_name>
|
|
140
|
+
<arguments>{"directory": "$DIRECTORY", "query": "extract helper from $FUNCTION_NAME", "limit": 5}</arguments>
|
|
141
|
+
</use_mcp_tool>
|
|
142
|
+
|
|
143
|
+
For each candidate returned, note its role (entry_point / orchestrator / hub / utility / internal)
|
|
144
|
+
and the suggested strategy. Cross-reference with the subgraph from Step 5: prefer candidates
|
|
145
|
+
that already call into — or are called by — the target function.
|
|
146
|
+
|
|
147
|
+
## Step 7: Design the change sequence
|
|
148
|
+
|
|
149
|
+
Based on the recommended strategy from Step 4, design an ordered sequence of
|
|
150
|
+
atomic changes. Each change must specify:
|
|
151
|
+
|
|
152
|
+
- **What**: the exact block of logic to move (line range or description)
|
|
153
|
+
- **New name**: the function or method name to give it
|
|
154
|
+
- **Target file**: the file where it will live after the move
|
|
155
|
+
- If the logic belongs to an existing module: name that file
|
|
156
|
+
- If no suitable module exists: propose a new file path (e.g.
|
|
157
|
+
`src/services/validation.ts`) and justify the choice
|
|
158
|
+
- **Target class** (if applicable): the class or namespace to place it in
|
|
159
|
+
- **Callers to update**: list every call site that will need updating
|
|
160
|
+
|
|
161
|
+
For each strategy, apply these rules:
|
|
162
|
+
|
|
163
|
+
- **split**: decompose the function into N sub-functions; each sub-function
|
|
164
|
+
stays in the same file unless it clearly belongs elsewhere
|
|
165
|
+
- **extract**: pull out a helper; place it in the nearest cohesive module or
|
|
166
|
+
create a new file if none exists
|
|
167
|
+
- **facade**: keep the original signature, delegate body to smaller functions;
|
|
168
|
+
create a private companion module if the file would exceed 300 lines
|
|
169
|
+
- **delegate**: move ownership logic to callers; update each caller file listed
|
|
170
|
+
in the upstream chain
|
|
171
|
+
|
|
172
|
+
Present the full change sequence to the user for review and ask for confirmation
|
|
173
|
+
before writing the plan file.
|
|
174
|
+
|
|
175
|
+
## Step 8: Write the plan file
|
|
176
|
+
|
|
177
|
+
Create `.spec-gen/refactor-plan.md` in the project directory with the following
|
|
178
|
+
structure (fill every section — leave nothing as "TBD"):
|
|
179
|
+
|
|
180
|
+
```markdown
|
|
181
|
+
# Refactor Plan
|
|
182
|
+
|
|
183
|
+
Generated: <ISO date>
|
|
184
|
+
Workflow: /spec-gen-plan-refactor → /spec-gen-execute-refactor
|
|
185
|
+
|
|
186
|
+
## Target
|
|
187
|
+
|
|
188
|
+
- **Function**: <name>
|
|
189
|
+
- **File**: <relative path>
|
|
190
|
+
- **Lines**: <start>–<end> (read the file to confirm)
|
|
191
|
+
- **Risk score**: <0–100>
|
|
192
|
+
- **Strategy**: <extract | split | facade | delegate>
|
|
193
|
+
- **Priority score before refactor**: <value>
|
|
194
|
+
|
|
195
|
+
## Why
|
|
196
|
+
|
|
197
|
+
- <issue 1 from refactor report>
|
|
198
|
+
- <issue 2>
|
|
199
|
+
- ...
|
|
200
|
+
|
|
201
|
+
## Callers (upstream — must not break)
|
|
202
|
+
|
|
203
|
+
| Caller | File |
|
|
204
|
+
|---|---|
|
|
205
|
+
| <name> | <path> |
|
|
206
|
+
|
|
207
|
+
## Callees (downstream — candidates for extraction)
|
|
208
|
+
|
|
209
|
+
| Callee | File |
|
|
210
|
+
|---|---|
|
|
211
|
+
| <name> | <path> |
|
|
212
|
+
|
|
213
|
+
## Coverage baseline
|
|
214
|
+
|
|
215
|
+
- **File**: <target file>
|
|
216
|
+
- **Coverage**: <X>% lines, <Y>% branches
|
|
217
|
+
- **Status**: ✅ safe / ⚠️ caution / 🛑 discouraged
|
|
218
|
+
- **Test command**: <exact command to run>
|
|
219
|
+
|
|
220
|
+
## Change sequence
|
|
221
|
+
|
|
222
|
+
Apply in order. Do not skip ahead. Run tests after each step.
|
|
223
|
+
|
|
224
|
+
### Change 1 — <short label>
|
|
225
|
+
|
|
226
|
+
- **What**: extract lines <start>–<end> (logic: <one-line description>)
|
|
227
|
+
- **New function name**: `<name>`
|
|
228
|
+
- **Target file**: `<path>` (<new file | existing file — reason>)
|
|
229
|
+
- **Target class**: `<ClassName>` or none
|
|
230
|
+
- **Call sites to update**: <list each file:line>
|
|
231
|
+
- **Expected diff**: +<N> lines in <new/existing file>, -<M> lines in <source file>
|
|
232
|
+
|
|
233
|
+
### Change 2 — <short label>
|
|
234
|
+
|
|
235
|
+
...
|
|
236
|
+
|
|
237
|
+
## Acceptance criteria
|
|
238
|
+
|
|
239
|
+
- Priority score drops below <target score> in `get_refactor_report`
|
|
240
|
+
- Function exits the top-5 list
|
|
241
|
+
- Full test suite passes (green)
|
|
242
|
+
- `git diff --stat` shows only the expected files
|
|
243
|
+
|
|
244
|
+
## Restore point
|
|
245
|
+
|
|
246
|
+
Run before starting execute:
|
|
247
|
+
```bash
|
|
248
|
+
git log --oneline -1
|
|
249
|
+
```
|
|
250
|
+
Note the hash here: <to be filled by execute workflow>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Once the file is written, tell the user:
|
|
254
|
+
> "Plan written to `.spec-gen/refactor-plan.md`. Review it, then run
|
|
255
|
+
> `/spec-gen-execute-refactor` to apply the changes."
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# spec-gen: Refactor Codebase (redirected)
|
|
2
|
+
|
|
3
|
+
This workflow has been split into two focused workflows for better reliability
|
|
4
|
+
with limited models:
|
|
5
|
+
|
|
6
|
+
- **`/spec-gen-plan-refactor`** — static analysis, impact assessment, and
|
|
7
|
+
written plan saved to `.spec-gen/refactor-plan.md` (no code changes)
|
|
8
|
+
- **`/spec-gen-execute-refactor`** — reads the plan and applies changes
|
|
9
|
+
incrementally, with tests after each step
|
|
10
|
+
|
|
11
|
+
Tell the user:
|
|
12
|
+
> "The `/spec-gen-refactor-codebase` workflow has been split. Please use:
|
|
13
|
+
> 1. `/spec-gen-plan-refactor` to analyse the codebase and write a plan
|
|
14
|
+
> 2. `/spec-gen-execute-refactor` to apply the plan
|
|
15
|
+
>
|
|
16
|
+
> This two-step approach is more reliable, especially with smaller models."
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
schema: spec-driven
|
|
2
|
+
context: |
|
|
3
|
+
TaskFlow — a task management REST API built with Express.js and PostgreSQL.
|
|
4
|
+
|
|
5
|
+
Tech stack: TypeScript, Express.js, PostgreSQL, JWT auth, bcrypt
|
|
6
|
+
Architecture: Layered (routes → services → database)
|
|
7
|
+
|
|
8
|
+
spec-gen:
|
|
9
|
+
generatedAt: "2025-06-15T00:00:00.000Z"
|
|
10
|
+
domains:
|
|
11
|
+
- auth
|
|
12
|
+
- tasks
|
|
13
|
+
- projects
|
|
14
|
+
- database
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Architecture Specification
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Describes the overall system architecture and how components interact.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
### Requirement: LayeredArchitecture
|
|
12
|
+
|
|
13
|
+
The system SHALL follow a three-layer architecture:
|
|
14
|
+
1. **Routes** (Express routers) handle HTTP concerns
|
|
15
|
+
2. **Services** contain business logic
|
|
16
|
+
3. **Database** handles persistence
|
|
17
|
+
|
|
18
|
+
### Requirement: EntryPoint
|
|
19
|
+
|
|
20
|
+
The system SHALL expose a single entry point (`src/index.ts`) that mounts all route
|
|
21
|
+
modules and starts an Express server on PORT (default 3000).
|
|
22
|
+
|
|
23
|
+
### Requirement: HealthEndpoint
|
|
24
|
+
|
|
25
|
+
The system SHALL expose a public GET /health endpoint returning `{ "status": "ok" }`.
|
|
26
|
+
|
|
27
|
+
## Technical Notes
|
|
28
|
+
|
|
29
|
+
- **Implementation**: `src/index.ts`
|
|
30
|
+
- **Dependencies**: express
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Auth Specification
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
> Source files: src/auth/auth-service.ts, src/auth/auth-middleware.ts, src/auth/auth-routes.ts
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Handles user authentication (login, registration, JWT management) and request-level
|
|
9
|
+
authorization via middleware.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
### Requirement: UserLogin
|
|
14
|
+
|
|
15
|
+
The system SHALL authenticate users by email and password, returning a signed JWT on success.
|
|
16
|
+
|
|
17
|
+
#### Scenario: SuccessfulLogin
|
|
18
|
+
- **GIVEN** a registered user with email "alice@test.com" and a valid password
|
|
19
|
+
- **WHEN** POST /api/auth/login is called with those credentials
|
|
20
|
+
- **THEN** the system returns a JWT token, expiry time, and userId with status 200
|
|
21
|
+
|
|
22
|
+
#### Scenario: InvalidCredentials
|
|
23
|
+
- **GIVEN** an incorrect password
|
|
24
|
+
- **WHEN** POST /api/auth/login is called
|
|
25
|
+
- **THEN** the system returns status 401 with error "Invalid credentials"
|
|
26
|
+
|
|
27
|
+
#### Scenario: MissingFields
|
|
28
|
+
- **GIVEN** a request body without email or password
|
|
29
|
+
- **WHEN** POST /api/auth/login is called
|
|
30
|
+
- **THEN** the system returns status 400 with error "Email and password required"
|
|
31
|
+
|
|
32
|
+
### Requirement: UserRegistration
|
|
33
|
+
|
|
34
|
+
The system SHALL register new users with email, password, and name, hashing the password with bcrypt (cost factor 12).
|
|
35
|
+
|
|
36
|
+
#### Scenario: SuccessfulRegistration
|
|
37
|
+
- **GIVEN** a unique email "bob@test.com"
|
|
38
|
+
- **WHEN** POST /api/auth/register is called
|
|
39
|
+
- **THEN** the system creates the user and returns a JWT with status 201
|
|
40
|
+
|
|
41
|
+
#### Scenario: DuplicateEmail
|
|
42
|
+
- **GIVEN** an email that already exists
|
|
43
|
+
- **WHEN** POST /api/auth/register is called
|
|
44
|
+
- **THEN** the system returns status 409 with error "Email already registered"
|
|
45
|
+
|
|
46
|
+
### Requirement: JWTTokenManagement
|
|
47
|
+
|
|
48
|
+
The system SHALL sign tokens with a configurable secret (JWT_SECRET env var, defaulting to "dev-secret") and 24-hour expiry.
|
|
49
|
+
|
|
50
|
+
### Requirement: RequestAuthorization
|
|
51
|
+
|
|
52
|
+
The system SHALL protect routes via `requireAuth` middleware that validates Bearer tokens and injects `userId` and `userRole` into the request.
|
|
53
|
+
|
|
54
|
+
#### Scenario: MissingToken
|
|
55
|
+
- **GIVEN** a request without an Authorization header
|
|
56
|
+
- **WHEN** the request reaches a protected route
|
|
57
|
+
- **THEN** the system returns status 401 with error "Missing authorization header"
|
|
58
|
+
|
|
59
|
+
#### Scenario: ExpiredToken
|
|
60
|
+
- **GIVEN** a request with an expired JWT
|
|
61
|
+
- **WHEN** the request reaches a protected route
|
|
62
|
+
- **THEN** the system returns status 401 with error "Invalid or expired token"
|
|
63
|
+
|
|
64
|
+
### Requirement: RoleBasedAccess
|
|
65
|
+
|
|
66
|
+
The system SHALL support role-based access control via `requireRole` middleware that checks `userRole` against a required role.
|
|
67
|
+
|
|
68
|
+
## Technical Notes
|
|
69
|
+
|
|
70
|
+
- **Implementation**: `src/auth/auth-service.ts`, `src/auth/auth-middleware.ts`, `src/auth/auth-routes.ts`
|
|
71
|
+
- **Dependencies**: jsonwebtoken, bcrypt
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Database Specification
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
> Source files: src/database/connection.ts
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Manages PostgreSQL connection pooling and provides a health check endpoint.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
### Requirement: ConnectionPooling
|
|
13
|
+
|
|
14
|
+
The system SHALL maintain a PostgreSQL connection pool with max 20 connections and 30-second idle timeout.
|
|
15
|
+
|
|
16
|
+
### Requirement: HealthCheck
|
|
17
|
+
|
|
18
|
+
The system SHALL expose a health check function that verifies database connectivity by executing `SELECT 1`.
|
|
19
|
+
|
|
20
|
+
#### Scenario: HealthyDatabase
|
|
21
|
+
- **GIVEN** a running PostgreSQL instance
|
|
22
|
+
- **WHEN** healthCheck is called
|
|
23
|
+
- **THEN** the function returns true
|
|
24
|
+
|
|
25
|
+
#### Scenario: UnhealthyDatabase
|
|
26
|
+
- **GIVEN** a down PostgreSQL instance
|
|
27
|
+
- **WHEN** healthCheck is called
|
|
28
|
+
- **THEN** the function returns false
|
|
29
|
+
|
|
30
|
+
## Technical Notes
|
|
31
|
+
|
|
32
|
+
- **Implementation**: `src/database/connection.ts`
|
|
33
|
+
- **Dependencies**: pg (node-postgres)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# System Overview
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
TaskFlow is a task management REST API that enables teams to organize work into
|
|
8
|
+
projects and tasks with role-based access control and real-time status tracking.
|
|
9
|
+
|
|
10
|
+
## Domains
|
|
11
|
+
|
|
12
|
+
- **auth**: Authentication (login, registration, JWT tokens) and authorization (role-based middleware)
|
|
13
|
+
- **tasks**: Task CRUD operations, status transitions, filtering, and assignment
|
|
14
|
+
- **projects**: Project management, membership, and archival
|
|
15
|
+
- **database**: PostgreSQL connection pooling and health checks
|
|
16
|
+
|
|
17
|
+
## API Surface
|
|
18
|
+
|
|
19
|
+
All endpoints live under `/api/` and require Bearer token authentication except
|
|
20
|
+
`/api/auth/login`, `/api/auth/register`, and `/health`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Projects Specification
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
> Source files: src/projects/project-model.ts, src/projects/project-service.ts
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Manages projects that group tasks together, including membership and archival.
|
|
9
|
+
|
|
10
|
+
## Entities
|
|
11
|
+
|
|
12
|
+
### Project
|
|
13
|
+
|
|
14
|
+
| Property | Type | Description |
|
|
15
|
+
|----------|------|-------------|
|
|
16
|
+
| id | string | Unique project identifier (format: proj_{timestamp}) |
|
|
17
|
+
| name | string | Project name (required, trimmed) |
|
|
18
|
+
| description | string | Description (defaults to "") |
|
|
19
|
+
| ownerId | string | User who created the project |
|
|
20
|
+
| members | string[] | User IDs with access (owner is auto-added) |
|
|
21
|
+
| isArchived | boolean | Whether the project is archived |
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
### Requirement: ProjectCreation
|
|
26
|
+
|
|
27
|
+
The system SHALL create projects with a required name, auto-adding the creator as owner and first member.
|
|
28
|
+
|
|
29
|
+
#### Scenario: ValidCreation
|
|
30
|
+
- **GIVEN** a valid project name
|
|
31
|
+
- **WHEN** createProject is called
|
|
32
|
+
- **THEN** the system creates the project with the creator as owner and member
|
|
33
|
+
|
|
34
|
+
### Requirement: ProjectMembership
|
|
35
|
+
|
|
36
|
+
The system SHALL allow adding members to a project, preventing duplicate membership.
|
|
37
|
+
|
|
38
|
+
#### Scenario: DuplicateMember
|
|
39
|
+
- **GIVEN** a user who is already a member
|
|
40
|
+
- **WHEN** addMember is called
|
|
41
|
+
- **THEN** the system throws "User is already a member"
|
|
42
|
+
|
|
43
|
+
### Requirement: ProjectArchival
|
|
44
|
+
|
|
45
|
+
The system SHALL allow only the project owner to archive a project.
|
|
46
|
+
|
|
47
|
+
#### Scenario: NonOwnerArchival
|
|
48
|
+
- **GIVEN** a user who is not the project owner
|
|
49
|
+
- **WHEN** archiveProject is called
|
|
50
|
+
- **THEN** the system throws "Only the owner can archive a project"
|
|
51
|
+
|
|
52
|
+
## Technical Notes
|
|
53
|
+
|
|
54
|
+
- **Implementation**: `src/projects/project-model.ts`, `src/projects/project-service.ts`
|
|
55
|
+
- **Dependencies**: auth domain
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Tasks Specification
|
|
2
|
+
|
|
3
|
+
> Generated by spec-gen v1.0.0 on 2025-06-15
|
|
4
|
+
> Source files: src/tasks/task-model.ts, src/tasks/task-service.ts, src/tasks/task-routes.ts
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Manages the full lifecycle of tasks: creation, retrieval, updates (including status
|
|
9
|
+
transitions), deletion, and filtered listing within projects.
|
|
10
|
+
|
|
11
|
+
## Entities
|
|
12
|
+
|
|
13
|
+
### Task
|
|
14
|
+
|
|
15
|
+
| Property | Type | Description |
|
|
16
|
+
|----------|------|-------------|
|
|
17
|
+
| id | string | Unique task identifier (format: task_{timestamp}) |
|
|
18
|
+
| title | string | Task title (required, trimmed) |
|
|
19
|
+
| description | string | Detailed description (defaults to "") |
|
|
20
|
+
| status | TaskStatus | One of: todo, in_progress, done, cancelled |
|
|
21
|
+
| priority | TaskPriority | One of: low, medium, high, urgent |
|
|
22
|
+
| assigneeId | string \| null | User ID of assignee |
|
|
23
|
+
| projectId | string | Parent project ID (required) |
|
|
24
|
+
| createdBy | string | User ID of creator |
|
|
25
|
+
| dueDate | Date \| null | Optional due date |
|
|
26
|
+
| tags | string[] | User-defined tags |
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
### Requirement: TaskCreation
|
|
31
|
+
|
|
32
|
+
The system SHALL create tasks with a required title and projectId, defaulting status to "todo" and priority to "medium".
|
|
33
|
+
|
|
34
|
+
#### Scenario: ValidCreation
|
|
35
|
+
- **GIVEN** a valid title and projectId
|
|
36
|
+
- **WHEN** POST /api/tasks is called
|
|
37
|
+
- **THEN** the system creates the task with default status "todo" and returns it with status 201
|
|
38
|
+
|
|
39
|
+
#### Scenario: MissingTitle
|
|
40
|
+
- **GIVEN** a request body without a title
|
|
41
|
+
- **WHEN** POST /api/tasks is called
|
|
42
|
+
- **THEN** the system returns status 400 with error "Task title is required"
|
|
43
|
+
|
|
44
|
+
### Requirement: TaskStatusTransitions
|
|
45
|
+
|
|
46
|
+
The system SHALL enforce valid status transitions:
|
|
47
|
+
- todo → in_progress, cancelled
|
|
48
|
+
- in_progress → done, todo, cancelled
|
|
49
|
+
- done → todo
|
|
50
|
+
- cancelled → todo
|
|
51
|
+
|
|
52
|
+
#### Scenario: ValidTransition
|
|
53
|
+
- **GIVEN** a task with status "todo"
|
|
54
|
+
- **WHEN** the status is updated to "in_progress"
|
|
55
|
+
- **THEN** the transition succeeds
|
|
56
|
+
|
|
57
|
+
#### Scenario: InvalidTransition
|
|
58
|
+
- **GIVEN** a task with status "todo"
|
|
59
|
+
- **WHEN** the status is updated to "done"
|
|
60
|
+
- **THEN** the system throws "Cannot transition from todo to done"
|
|
61
|
+
|
|
62
|
+
### Requirement: TaskCRUD
|
|
63
|
+
|
|
64
|
+
The system SHALL support Get, Update (PATCH), Delete, and List operations for tasks. All task routes require authentication.
|
|
65
|
+
|
|
66
|
+
#### Scenario: TaskNotFound
|
|
67
|
+
- **GIVEN** a non-existent task ID
|
|
68
|
+
- **WHEN** GET /api/tasks/:id is called
|
|
69
|
+
- **THEN** the system returns status 404
|
|
70
|
+
|
|
71
|
+
### Requirement: TaskFiltering
|
|
72
|
+
|
|
73
|
+
The system SHALL support filtering tasks by projectId (required), status, and assigneeId via query parameters.
|
|
74
|
+
|
|
75
|
+
## Technical Notes
|
|
76
|
+
|
|
77
|
+
- **Implementation**: `src/tasks/task-model.ts`, `src/tasks/task-service.ts`, `src/tasks/task-routes.ts`
|
|
78
|
+
- **Dependencies**: auth domain (requireAuth middleware)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "taskflow-api",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Task management REST API — brownfield Express.js app",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "ts-node src/index.ts",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "vitest run"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"express": "^4.18.2",
|
|
13
|
+
"jsonwebtoken": "^9.0.0",
|
|
14
|
+
"bcrypt": "^5.1.0",
|
|
15
|
+
"pg": "^8.11.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.3.0",
|
|
19
|
+
"vitest": "^1.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import { AuthService } from './auth-service.js';
|
|
3
|
+
|
|
4
|
+
const authService = new AuthService();
|
|
5
|
+
|
|
6
|
+
export function requireAuth(req: Request, res: Response, next: NextFunction) {
|
|
7
|
+
const header = req.headers.authorization;
|
|
8
|
+
if (!header?.startsWith('Bearer ')) {
|
|
9
|
+
return res.status(401).json({ error: 'Missing authorization header' });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const token = header.slice(7);
|
|
13
|
+
const payload = authService.verifyToken(token);
|
|
14
|
+
if (!payload) {
|
|
15
|
+
return res.status(401).json({ error: 'Invalid or expired token' });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
(req as any).userId = payload.userId;
|
|
19
|
+
(req as any).userRole = payload.role;
|
|
20
|
+
next();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function requireRole(role: string) {
|
|
24
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
25
|
+
if ((req as any).userRole !== role) {
|
|
26
|
+
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
27
|
+
}
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { AuthService } from './auth-service.js';
|
|
3
|
+
|
|
4
|
+
const router = Router();
|
|
5
|
+
const authService = new AuthService();
|
|
6
|
+
|
|
7
|
+
router.post('/login', async (req, res) => {
|
|
8
|
+
try {
|
|
9
|
+
const { email, password } = req.body;
|
|
10
|
+
if (!email || !password) return res.status(400).json({ error: 'Email and password required' });
|
|
11
|
+
const result = await authService.login(email, password);
|
|
12
|
+
res.json(result);
|
|
13
|
+
} catch (err: any) {
|
|
14
|
+
res.status(401).json({ error: err.message });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
router.post('/register', async (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
const { email, password, name } = req.body;
|
|
21
|
+
if (!email || !password || !name) return res.status(400).json({ error: 'All fields required' });
|
|
22
|
+
const result = await authService.register(email, password, name);
|
|
23
|
+
res.status(201).json(result);
|
|
24
|
+
} catch (err: any) {
|
|
25
|
+
res.status(409).json({ error: err.message });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export { router as authRouter };
|