nexus-dev-toolkit 3.0.0__py3-none-any.whl
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.
- nexus_cli.py +292 -0
- nexus_dev_toolkit-3.0.0.dist-info/METADATA +170 -0
- nexus_dev_toolkit-3.0.0.dist-info/RECORD +21 -0
- nexus_dev_toolkit-3.0.0.dist-info/WHEEL +5 -0
- nexus_dev_toolkit-3.0.0.dist-info/entry_points.txt +3 -0
- nexus_dev_toolkit-3.0.0.dist-info/licenses/LICENSE +21 -0
- nexus_dev_toolkit-3.0.0.dist-info/top_level.txt +3 -0
- nexus_server.py +16 -0
- tools/__init__.py +0 -0
- tools/epav/__init__.py +14 -0
- tools/epav/arch_ingest.py +124 -0
- tools/epav/package_resolver.py +271 -0
- tools/epav/project_rules.py +208 -0
- tools/epav/skills/__init__.py +0 -0
- tools/epav/skills/apply.md +41 -0
- tools/epav/skills/epav.md +46 -0
- tools/epav/skills/evaluate.md +42 -0
- tools/epav/skills/plan.md +46 -0
- tools/epav/skills/scaffold.md +249 -0
- tools/epav/skills/validate.md +57 -0
- tools/epav/task_loader.py +140 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# /scaffold
|
|
2
|
+
|
|
3
|
+
**Day 0 — Production Scaffold** (one-time project setup)
|
|
4
|
+
|
|
5
|
+
Generates a complete production-grade scaffold from the architecture document and Figma export.
|
|
6
|
+
Output: infrastructure + design system + UI shell + AGENTS.md + knowledge/.
|
|
7
|
+
|
|
8
|
+
**Goal: structure and standards, not live integrations.**
|
|
9
|
+
Day 0 prepares developers to follow golden paths and best practices from the very start.
|
|
10
|
+
Real auth providers, live databases, and external service integrations are Day 1.
|
|
11
|
+
|
|
12
|
+
- No business logic. No API wiring. No placeholder pages.
|
|
13
|
+
- **Auth = mock only** — login form redirects to dashboard, no real provider calls (no Supabase Auth, no NextAuth, no OAuth). Real auth is wired in Day 1.
|
|
14
|
+
- **Data = mock only** — all components use local mock data, no live DB queries.
|
|
15
|
+
- **No external service dependency** — the project must build and run without any credentials or services configured.
|
|
16
|
+
- The install + dev command must work out of the box (e.g. `npm install && npm run dev` for Next.js, `flutter pub get && flutter run` for Flutter).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
Before running /scaffold:
|
|
23
|
+
1. Architecture document must be in `docs/arch-docs/`
|
|
24
|
+
2. Figma export ZIP must be available
|
|
25
|
+
3. Run: `ingest_architecture_doc` MCP tool on `docs/arch-docs/`
|
|
26
|
+
4. Run: `ingest_figma_zip` MCP tool on the Figma ZIP
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## EVALUATE — Understand the Architecture and Design
|
|
31
|
+
|
|
32
|
+
Load `docs/arch-docs/` (ARCH doc + ADRs) and the Figma export. Then walk through:
|
|
33
|
+
|
|
34
|
+
**Architecture:**
|
|
35
|
+
1. The stack decisions and why they were made
|
|
36
|
+
2. The data model — tables, relationships, indexes
|
|
37
|
+
3. What infrastructure is needed from the start
|
|
38
|
+
4. The middleware stack and auth flow
|
|
39
|
+
5. Error response format and error handling strategy
|
|
40
|
+
6. Security rules and constraints
|
|
41
|
+
|
|
42
|
+
**Design:**
|
|
43
|
+
7. Design tokens (colors, typography, spacing, radii, shadows)
|
|
44
|
+
8. Component inventory (every component, variants, states)
|
|
45
|
+
9. Layout patterns (grid, breakpoints, responsive behavior)
|
|
46
|
+
10. Iconography (style, sizes, library)
|
|
47
|
+
|
|
48
|
+
**Design token conversion (before writing any design file):**
|
|
49
|
+
Figma exports colors in oklch or hex — never copy them raw. Convert to the target stack's native format:
|
|
50
|
+
- Web (Tailwind v4): `hsl()` — never oklch, hex, or rgb
|
|
51
|
+
- Flutter: `Color(0xFF...)` or generated `color_theme.dart`
|
|
52
|
+
- React Native: hex strings in a `colors.ts` theme file
|
|
53
|
+
|
|
54
|
+
Do NOT generate code yet. Produce an EVALUATE SUMMARY covering all 10 points.
|
|
55
|
+
Stop and wait for confirmation before proceeding to PLAN.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## PLAN — Boilerplate + UI Shell + Project Rules
|
|
60
|
+
|
|
61
|
+
Based on the architecture document and Figma design, plan four things:
|
|
62
|
+
|
|
63
|
+
**1. INFRASTRUCTURE BOILERPLATE**
|
|
64
|
+
- Project structure — every directory, annotated
|
|
65
|
+
- Database schema — from the architecture doc's data model
|
|
66
|
+
- Environment variables — complete list, documented
|
|
67
|
+
- Auth flow — as specified in the architecture
|
|
68
|
+
- Error handling — using the format from the architecture
|
|
69
|
+
|
|
70
|
+
**2. UI SHELL (from Figma)**
|
|
71
|
+
- Design system config (tailwind.config.ts, globals.css, CSS custom properties, font loading)
|
|
72
|
+
- Component architecture (name, path, props interface, variants, composition, accessibility)
|
|
73
|
+
- Page layouts (every page from the Figma, structured with placeholder data)
|
|
74
|
+
- Build order (component dependency chain)
|
|
75
|
+
|
|
76
|
+
**3. AGENTS.md (cross-tool project rules)**
|
|
77
|
+
- Project description and stack summary
|
|
78
|
+
- Backend and frontend coding standards
|
|
79
|
+
- Security rules, git conventions, quality gates
|
|
80
|
+
|
|
81
|
+
**4. KNOWLEDGE DIRECTORY STRUCTURE**
|
|
82
|
+
- `knowledge/rules/coding-standards.md`
|
|
83
|
+
- `knowledge/prompts/dev/` (initial prompt templates)
|
|
84
|
+
- `knowledge/patterns/` (implement-and-test chain)
|
|
85
|
+
- Design system spec saved to `knowledge/`
|
|
86
|
+
|
|
87
|
+
Output as a blueprint. No code yet.
|
|
88
|
+
Stop and wait for `/apply` approval before proceeding.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## APPLY — Generate the Complete Boilerplate
|
|
93
|
+
|
|
94
|
+
Plan approved. Generate everything in one scaffold.
|
|
95
|
+
|
|
96
|
+
**MANDATORY FIRST STEP — call `resolve_package_versions` before writing any file.**
|
|
97
|
+
|
|
98
|
+
`resolve_package_versions` runs the real package manager in a temp directory and returns exact pinned versions from the lock file. Use those exact versions in the manifest — no guessing, no ranges, no AI memory.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Step 1 — call resolve_package_versions with all deps + stack hint from arch doc
|
|
102
|
+
packages: ["next@^16", "react@^19", "@supabase/supabase-js@^2", ...]
|
|
103
|
+
stack_hint: "Next.js 16 TypeScript" / "Flutter 3" / "Go" / etc.
|
|
104
|
+
→ returns: { "versions": { "next": "16.2.9", "react": "19.2.7", ... } }
|
|
105
|
+
|
|
106
|
+
Step 2 — write the package manifest with EXACT versions from Step 1
|
|
107
|
+
npm: package.json — "next": "16.2.9" (no ^ or ~)
|
|
108
|
+
Flutter: pubspec.yaml — exact version constraints
|
|
109
|
+
Go: go.mod — exact module versions
|
|
110
|
+
Rust: Cargo.toml — exact versions
|
|
111
|
+
|
|
112
|
+
Step 3 — run the package manager to produce the lock file
|
|
113
|
+
npm install → package-lock.json
|
|
114
|
+
flutter pub get → pubspec.lock
|
|
115
|
+
go mod tidy → go.sum
|
|
116
|
+
cargo build → Cargo.lock
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
NEVER write "latest" in any manifest.
|
|
120
|
+
NEVER write semver ranges (^ or ~) in the final manifest.
|
|
121
|
+
NEVER write patch versions from AI memory — training data is always stale.
|
|
122
|
+
|
|
123
|
+
**1. Infrastructure:**
|
|
124
|
+
- `.gitignore` — node_modules, .env*, build outputs, OS files
|
|
125
|
+
- `.env.example` — all variables documented, no real secrets
|
|
126
|
+
- Initial migration — exact schema from arch doc
|
|
127
|
+
- Auth middleware — as specified
|
|
128
|
+
- Error handler — consistent format from arch doc
|
|
129
|
+
- Health-check endpoint
|
|
130
|
+
- Seed script — idempotent test data
|
|
131
|
+
- Linter + formatter config (stack-appropriate: ESLint + Prettier for JS/TS; gofmt + golangci-lint for Go; clippy for Rust; dart format for Flutter)
|
|
132
|
+
- Pre-commit hooks (stack-appropriate):
|
|
133
|
+
- **npm:** husky + lint-staged + commitlint
|
|
134
|
+
- `package.json` must have `"prepare": "husky"` in scripts
|
|
135
|
+
- Write `.husky/pre-commit` with `npx lint-staged`, then `chmod +x .husky/pre-commit`
|
|
136
|
+
- Write `.lintstagedrc.json` (lint + format on staged files)
|
|
137
|
+
- Write `.commitlintrc.json` with `@commitlint/config-conventional`
|
|
138
|
+
- CI pipeline must set `HUSKY=0` env var — husky fails in CI without a git repo
|
|
139
|
+
- **Python:** pre-commit framework with `.pre-commit-config.yaml`
|
|
140
|
+
- **Go / Rust / Java:** git hooks via Makefile or pre-commit framework
|
|
141
|
+
- README with local setup instructions
|
|
142
|
+
- CI pipeline config (GitHub Actions or equivalent: lint, typecheck, test, db push)
|
|
143
|
+
|
|
144
|
+
**2. UI shell (matching Figma exactly):**
|
|
145
|
+
- Design system config (tailwind.config.ts, globals.css — tokens from Figma)
|
|
146
|
+
- All components with TypeScript props and ALL visual states:
|
|
147
|
+
(default, hover, focus, disabled, loading, empty, error)
|
|
148
|
+
- All page layouts responsive to Figma breakpoints
|
|
149
|
+
- Semantic HTML + ARIA attributes throughout
|
|
150
|
+
- Placeholder/mock data — NOT real API calls
|
|
151
|
+
- Prop interfaces defined so Day 1 can wire real data without changing the component
|
|
152
|
+
|
|
153
|
+
**3. AGENTS.md at project root**
|
|
154
|
+
|
|
155
|
+
**4. knowledge/ directory with initial content**
|
|
156
|
+
|
|
157
|
+
**Package requirements:**
|
|
158
|
+
- Exact versions from `resolve_package_versions` — not from memory, not ranges
|
|
159
|
+
- NEVER write "latest" — it is not a version
|
|
160
|
+
- NEVER write patch versions from AI memory
|
|
161
|
+
- Run the package manager after writing the manifest to produce the lock file
|
|
162
|
+
- No beta, canary, or RC packages
|
|
163
|
+
- No deprecated packages or APIs
|
|
164
|
+
|
|
165
|
+
**Production-grade standards:**
|
|
166
|
+
- No placeholder pages or unused dependencies
|
|
167
|
+
- Auth protecting all routes that need it
|
|
168
|
+
- Consistent error response format throughout
|
|
169
|
+
- Proper logging setup (not console.log)
|
|
170
|
+
- Environment-based configuration (dev/staging/prod)
|
|
171
|
+
- Security headers configured (next.config.ts for Next.js, equivalent for other stacks)
|
|
172
|
+
- Database connection pooling (use pooler URL, not direct)
|
|
173
|
+
|
|
174
|
+
**Next.js 16 specifics:**
|
|
175
|
+
- Route proxy file is `proxy.ts` not `middleware.ts` — export function `proxy`, not `middleware`
|
|
176
|
+
- `tsconfig.json` must use `"jsx": "react-jsx"` not `"jsx": "preserve"`
|
|
177
|
+
|
|
178
|
+
**Do NOT implement:**
|
|
179
|
+
- Real auth provider integration (Supabase Auth, NextAuth, OAuth, etc.)
|
|
180
|
+
- Live database queries or mutations
|
|
181
|
+
- External service calls (email, storage, payment, etc.)
|
|
182
|
+
- API endpoints or business logic beyond health check
|
|
183
|
+
- Data fetching, form submissions, or backend interactions
|
|
184
|
+
- Dev tasks from the CSV — that is Day 1
|
|
185
|
+
|
|
186
|
+
**Mock auth pattern:**
|
|
187
|
+
The login page accepts any input and sets a session cookie (preferred over localStorage — cookies are readable server-side for route guarding). No credentials checked.
|
|
188
|
+
- Cookie holds the user's mock role (e.g. `mock-role=admin`), 8h expiry
|
|
189
|
+
- Route guard (middleware/proxy) reads the cookie and redirects unauthenticated requests to login
|
|
190
|
+
- Server components read the cookie to get the current session (no Context provider needed)
|
|
191
|
+
- All role-gating uses the mock role value — no JWT, no OAuth token
|
|
192
|
+
Real auth provider replaces the cookie on Day 1.
|
|
193
|
+
|
|
194
|
+
Output as complete files. The install + dev command must work (e.g. `npm install && npm run dev` for Next.js, `flutter pub get && flutter run` for Flutter).
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## VALIDATE — Validate Infrastructure + Design Fidelity
|
|
199
|
+
|
|
200
|
+
**MANDATORY FIRST STEP — run the build. VALIDATE is not started until this passes.**
|
|
201
|
+
|
|
202
|
+
Use the build command for the stack prescribed in the arch doc:
|
|
203
|
+
|
|
204
|
+
| Stack | Build command |
|
|
205
|
+
|---|---|
|
|
206
|
+
| Next.js | `npm run build` |
|
|
207
|
+
| Vite / React | `npm run build` |
|
|
208
|
+
| Flutter | `flutter build apk --debug` |
|
|
209
|
+
| Go | `go build ./...` |
|
|
210
|
+
| Rust | `cargo build` |
|
|
211
|
+
| Java / Spring | `mvn package -DskipTests` |
|
|
212
|
+
|
|
213
|
+
If the build fails, fix ALL errors before running any other checks. Do not proceed to the checklist until the build exits with code 0. A failed build is an automatic [BLOCKER] that overrides everything else.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
Review everything against the architecture doc AND Figma.
|
|
218
|
+
|
|
219
|
+
**Packages:**
|
|
220
|
+
1. Are all dependencies on stable versions (no beta/canary/RC)?
|
|
221
|
+
2. Any deprecated packages or APIs in use?
|
|
222
|
+
3. Are versions pinned exactly in the lock file (package-lock.json / pubspec.lock / go.sum / Cargo.lock)?
|
|
223
|
+
4. Any known security vulnerabilities? (npm audit / flutter pub audit / cargo audit / etc.)
|
|
224
|
+
|
|
225
|
+
**Infrastructure:**
|
|
226
|
+
5. Does the project structure match the architecture?
|
|
227
|
+
6. Does the schema match the data model?
|
|
228
|
+
7. Are all env vars from the architecture doc present?
|
|
229
|
+
8. Is logging production-grade (not console.log)?
|
|
230
|
+
9. Are security headers and CORS configured?
|
|
231
|
+
10. Is database connection pooling set up?
|
|
232
|
+
|
|
233
|
+
**UI fidelity:**
|
|
234
|
+
11. Do components match the Figma design?
|
|
235
|
+
12. Responsive at 320px, 768px, 1024px, 1440px?
|
|
236
|
+
13. All visual states render with placeholder data?
|
|
237
|
+
14. Accessibility — keyboard nav, WCAG AA contrast?
|
|
238
|
+
15. Prop interfaces typed for Day 1 wiring?
|
|
239
|
+
16. No business logic or API calls in components?
|
|
240
|
+
|
|
241
|
+
**AGENTS.md + knowledge directory:**
|
|
242
|
+
17. Coding standards match the architecture?
|
|
243
|
+
18. Design system spec saved to knowledge/?
|
|
244
|
+
|
|
245
|
+
**Git hygiene:**
|
|
246
|
+
19. Pre-commit hooks configured and working? (husky executable + lint-staged for npm; equivalent for other stacks)
|
|
247
|
+
|
|
248
|
+
Classify every issue: [BLOCKER] / [FIX NOW] / [BACKLOG]
|
|
249
|
+
Fix every [BLOCKER] and [FIX NOW] before calling Day 0 complete.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# /validate
|
|
2
|
+
|
|
3
|
+
**VALIDATE** — Step 4 of the E→P→A→V cycle. Verify the implementation before calling it done.
|
|
4
|
+
|
|
5
|
+
## Prerequisite
|
|
6
|
+
|
|
7
|
+
APPLY must be complete.
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
### 1 — graphify blast radius check
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
graphify query "<what we just built>"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Check: does anything that references the changed files now behave unexpectedly? Flag any community boundary crossings that weren't in the plan.
|
|
18
|
+
|
|
19
|
+
### 2 — Check against acceptance criteria
|
|
20
|
+
|
|
21
|
+
Load the acceptance criteria from the CSV task (or EVALUATE summary). For each criterion:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
[ ] <criterion> — PASS / FAIL / PARTIAL
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3 — Classify all issues found
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
[BLOCKER] — prevents merge, must fix now
|
|
31
|
+
[FIX NOW] — significant issue, fix before moving to next task
|
|
32
|
+
[BACKLOG] — minor, log to knowledge/retros/ and defer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 4 — Fix all BLOCKERs and FIX NOWs before continuing
|
|
36
|
+
|
|
37
|
+
Do not move to the next task until the implementation passes all acceptance criteria.
|
|
38
|
+
|
|
39
|
+
### 5 — If a pattern was discovered, contribute it back
|
|
40
|
+
|
|
41
|
+
If APPLY revealed a better approach or a non-obvious constraint:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Append to knowledge/patterns/ or knowledge/rules/coding-standards.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 6 — When clean
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
VALIDATE COMPLETE
|
|
51
|
+
─────────────────
|
|
52
|
+
Criteria passed: N/N
|
|
53
|
+
Issues fixed: <list>
|
|
54
|
+
Backlog items: <list added to knowledge/retros/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> "Task complete. Ready for the next `/evaluate`."
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
_TASK_FIELDS = ["task_id", "user_story", "description", "acceptance_criteria", "dependencies"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _find_csv(hint: str) -> Path | None:
|
|
15
|
+
"""Locate a CSV task file from a path hint or by scanning docs/dev-tasks/."""
|
|
16
|
+
p = Path(hint)
|
|
17
|
+
if p.exists() and p.suffix == ".csv":
|
|
18
|
+
return p
|
|
19
|
+
dev_tasks = Path("docs/dev-tasks")
|
|
20
|
+
if dev_tasks.exists():
|
|
21
|
+
candidates = sorted(dev_tasks.rglob("*.csv"))
|
|
22
|
+
if hint:
|
|
23
|
+
matched = [c for c in candidates if hint.lower() in c.name.lower()]
|
|
24
|
+
if matched:
|
|
25
|
+
return matched[0]
|
|
26
|
+
if candidates:
|
|
27
|
+
return candidates[0]
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _run_graphify_query(description: str) -> str | None:
|
|
32
|
+
"""Run graphify query if a graph exists. Returns output or None."""
|
|
33
|
+
if not Path("graphify-out/graph.json").exists():
|
|
34
|
+
return None
|
|
35
|
+
try:
|
|
36
|
+
result = subprocess.run(
|
|
37
|
+
["graphify", "query", description[:200]],
|
|
38
|
+
capture_output=True, text=True, timeout=30,
|
|
39
|
+
)
|
|
40
|
+
return result.stdout.strip() if result.returncode == 0 else None
|
|
41
|
+
except Exception as e:
|
|
42
|
+
logger.warning("graphify query failed: %s", e)
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def register_task_loader_tool(mcp: FastMCP) -> None:
|
|
47
|
+
|
|
48
|
+
@mcp.tool()
|
|
49
|
+
async def load_task(
|
|
50
|
+
csv_path: str = "",
|
|
51
|
+
task_id: str = "",
|
|
52
|
+
row_index: int = 0,
|
|
53
|
+
) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Load a dev task from a CSV file and structure it for the EVALUATE step.
|
|
56
|
+
|
|
57
|
+
Reads a task CSV (one row per task with fields: task_id, user_story,
|
|
58
|
+
description, acceptance_criteria, dependencies). Optionally runs a
|
|
59
|
+
graphify query on the task description to surface blast radius context.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
csv_path: Path to the CSV file, or a name fragment to search in
|
|
63
|
+
docs/dev-tasks/. If empty, uses the first CSV found there.
|
|
64
|
+
task_id: Match a specific task_id value in the CSV. Takes priority
|
|
65
|
+
over row_index.
|
|
66
|
+
row_index: Zero-based row index to load if task_id is not provided.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
JSON with structured task context ready for /evaluate, including
|
|
70
|
+
graphify blast radius if a graph exists.
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
csv_file = _find_csv(csv_path)
|
|
74
|
+
if not csv_file:
|
|
75
|
+
return json.dumps({
|
|
76
|
+
"error": "No CSV task file found. Provide csv_path or create docs/dev-tasks/ "
|
|
77
|
+
"with your task CSVs."
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
rows: list[dict] = []
|
|
81
|
+
with csv_file.open(encoding="utf-8-sig") as f:
|
|
82
|
+
reader = csv.DictReader(f)
|
|
83
|
+
rows = list(reader)
|
|
84
|
+
|
|
85
|
+
if not rows:
|
|
86
|
+
return json.dumps({"error": f"CSV is empty: {csv_file}"})
|
|
87
|
+
|
|
88
|
+
# Find the target row
|
|
89
|
+
task: dict | None = None
|
|
90
|
+
if task_id:
|
|
91
|
+
task = next(
|
|
92
|
+
(r for r in rows if r.get("task_id", "").strip() == task_id.strip()),
|
|
93
|
+
None,
|
|
94
|
+
)
|
|
95
|
+
if not task:
|
|
96
|
+
return json.dumps({
|
|
97
|
+
"error": f"task_id '{task_id}' not found in {csv_file}",
|
|
98
|
+
"available_ids": [r.get("task_id", "") for r in rows[:20]],
|
|
99
|
+
})
|
|
100
|
+
else:
|
|
101
|
+
if row_index >= len(rows):
|
|
102
|
+
return json.dumps({
|
|
103
|
+
"error": f"row_index {row_index} out of range (CSV has {len(rows)} rows)"
|
|
104
|
+
})
|
|
105
|
+
task = rows[row_index]
|
|
106
|
+
|
|
107
|
+
# Extract standard EPAV fields (graceful if columns differ)
|
|
108
|
+
context = {f: task.get(f, "").strip() for f in _TASK_FIELDS}
|
|
109
|
+
context["_csv_file"] = str(csv_file)
|
|
110
|
+
context["_all_fields"] = dict(task)
|
|
111
|
+
|
|
112
|
+
# Graphify blast radius
|
|
113
|
+
description = context.get("description") or context.get("user_story", "")
|
|
114
|
+
blast_radius = _run_graphify_query(description)
|
|
115
|
+
if blast_radius:
|
|
116
|
+
context["blast_radius"] = blast_radius
|
|
117
|
+
|
|
118
|
+
# Human-readable EVALUATE block
|
|
119
|
+
evaluate_block = [
|
|
120
|
+
"TASK CONTEXT (ready for /evaluate)",
|
|
121
|
+
"─" * 40,
|
|
122
|
+
f"Task ID: {context.get('task_id', '(none)')}",
|
|
123
|
+
f"User story: {context.get('user_story', '(none)')}",
|
|
124
|
+
"",
|
|
125
|
+
f"Description:\n{context.get('description', '(none)')}",
|
|
126
|
+
"",
|
|
127
|
+
f"Acceptance criteria:\n{context.get('acceptance_criteria', '(none)')}",
|
|
128
|
+
"",
|
|
129
|
+
f"Dependencies: {context.get('dependencies', 'none')}",
|
|
130
|
+
]
|
|
131
|
+
if blast_radius:
|
|
132
|
+
evaluate_block += ["", "Graphify blast radius:", blast_radius[:800]]
|
|
133
|
+
|
|
134
|
+
context["evaluate_block"] = "\n".join(evaluate_block)
|
|
135
|
+
|
|
136
|
+
return json.dumps(context, indent=2)
|
|
137
|
+
|
|
138
|
+
except Exception as e:
|
|
139
|
+
logger.exception("Unexpected error in load_task")
|
|
140
|
+
return json.dumps({"error": f"Unexpected error: {e}"})
|