@kody-ade/kody-engine-lite 0.1.101 → 0.1.103

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 CHANGED
@@ -154,7 +154,7 @@ kody-engine-lite rerun --issue-number 42 --from verify
154
154
 
155
155
  ## Documentation
156
156
 
157
- **Understand Kody:** [About](docs/ABOUT.md) · [Features](docs/FEATURES.md) · [Pipeline](docs/PIPELINE.md) · [Comparison](docs/COMPARISON.md)
157
+ **Understand Kody:** [About](docs/ABOUT.md) · [Tech Stack](docs/TECH-STACK.md) · [Features](docs/FEATURES.md) · [Pipeline](docs/PIPELINE.md) · [Comparison](docs/COMPARISON.md)
158
158
 
159
159
  **Set up & use:** [CLI](docs/CLI.md) · [Configuration](docs/CONFIGURATION.md) · [Bootstrap](docs/BOOTSTRAP.md) · [LiteLLM](docs/LITELLM.md)
160
160
 
package/dist/bin/cli.js CHANGED
@@ -1546,6 +1546,11 @@ ${prompt}` : prompt;
1546
1546
  }
1547
1547
  if (isMcpEnabledForStage(stageName, config.mcp) && taskHasUI(taskDir)) {
1548
1548
  assembled = assembled + "\n\n" + getBrowserToolGuidance(stageName, taskDir);
1549
+ const qaGuidePath = path5.join(projectDir, ".kody", "qa-guide.md");
1550
+ if (fs5.existsSync(qaGuidePath)) {
1551
+ const qaGuide = fs5.readFileSync(qaGuidePath, "utf-8").trim();
1552
+ assembled = assembled + "\n\n" + qaGuide;
1553
+ }
1549
1554
  }
1550
1555
  return assembled;
1551
1556
  }
@@ -1769,7 +1774,7 @@ async function executeAgentStage(ctx, def) {
1769
1774
  description: plainText.slice(0, 500),
1770
1775
  scope: [],
1771
1776
  risk_level: "low",
1772
- hasUI: false,
1777
+ hasUI: true,
1773
1778
  questions: []
1774
1779
  }, null, 2);
1775
1780
  fs6.writeFileSync(outputPath, fallback);
@@ -4532,12 +4537,7 @@ function detectMcpConfig(cwd, pm, pkg) {
4532
4537
  const defaultPort = isNext ? 3e3 : isVite ? 5173 : 3e3;
4533
4538
  const mcp = {
4534
4539
  enabled: true,
4535
- servers: {
4536
- playwright: {
4537
- command: "npx",
4538
- args: ["@playwright/mcp@latest"]
4539
- }
4540
- },
4540
+ servers: {},
4541
4541
  stages: ["build", "review"]
4542
4542
  };
4543
4543
  if (hasDevScript) {
@@ -5034,6 +5034,23 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
5034
5034
  }
5035
5035
  }
5036
5036
  console.log(` \u2713 Generated ${stepCount} step files in .kody/steps/`);
5037
+ console.log("\n\u2500\u2500 QA Guide \u2500\u2500");
5038
+ const qaGuidePath = path21.join(cwd, ".kody", "qa-guide.md");
5039
+ if (!fs22.existsSync(qaGuidePath) || opts.force) {
5040
+ const discovery = discoverQaContext(cwd);
5041
+ if (discovery.routes.length > 0) {
5042
+ const qaGuide = generateQaGuide(discovery);
5043
+ fs22.writeFileSync(qaGuidePath, qaGuide);
5044
+ console.log(` \u2713 .kody/qa-guide.md (${discovery.routes.length} routes, ${discovery.roles.length} roles)`);
5045
+ if (discovery.loginPage) console.log(` \u2713 Login page detected: ${discovery.loginPage}`);
5046
+ if (discovery.adminPath) console.log(` \u2713 Admin panel detected: ${discovery.adminPath}`);
5047
+ console.log(" \u2139 Add QA_ADMIN_EMAIL, QA_ADMIN_PASSWORD, QA_USER_EMAIL, QA_USER_PASSWORD as GitHub secrets");
5048
+ } else {
5049
+ console.log(" \u25CB No routes detected \u2014 skipping QA guide");
5050
+ }
5051
+ } else {
5052
+ console.log(" \u25CB .kody/qa-guide.md already exists (use --force to regenerate)");
5053
+ }
5037
5054
  console.log("\n\u2500\u2500 Labels \u2500\u2500");
5038
5055
  try {
5039
5056
  let repoSlug = "";
@@ -5111,6 +5128,7 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
5111
5128
  const filesToCommit = [
5112
5129
  ".kody/memory/architecture.md",
5113
5130
  ".kody/memory/conventions.md",
5131
+ ".kody/qa-guide.md",
5114
5132
  ...installedSkillPaths
5115
5133
  ].filter((f) => fs22.existsSync(path21.join(cwd, f)));
5116
5134
  if (fs22.existsSync(path21.join(cwd, "skills-lock.json"))) {
@@ -5224,6 +5242,178 @@ Create it manually.`, cwd);
5224
5242
  console.log(" \u2713 Project bootstrap complete!");
5225
5243
  console.log(" Kody now has project-specific memory and customized step files.\n");
5226
5244
  }
5245
+ function discoverQaContext(cwd) {
5246
+ const result = {
5247
+ routes: [],
5248
+ authFiles: [],
5249
+ loginPage: null,
5250
+ adminPath: null,
5251
+ roles: [],
5252
+ devCommand: "",
5253
+ devPort: 3e3
5254
+ };
5255
+ try {
5256
+ const pkg = JSON.parse(fs22.readFileSync(path21.join(cwd, "package.json"), "utf-8"));
5257
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
5258
+ const pm = fs22.existsSync(path21.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : fs22.existsSync(path21.join(cwd, "yarn.lock")) ? "yarn" : "npm";
5259
+ if (pkg.scripts?.dev) result.devCommand = `${pm} dev`;
5260
+ if (allDeps.next || allDeps.nuxt) result.devPort = 3e3;
5261
+ else if (allDeps.vite) result.devPort = 5173;
5262
+ } catch {
5263
+ }
5264
+ const appDirs = ["src/app", "app"];
5265
+ for (const appDir of appDirs) {
5266
+ const fullAppDir = path21.join(cwd, appDir);
5267
+ if (!fs22.existsSync(fullAppDir)) continue;
5268
+ scanRoutes(fullAppDir, appDir, "", result);
5269
+ break;
5270
+ }
5271
+ const authPatterns = ["middleware.ts", "middleware.js", "src/middleware.ts", "src/middleware.js"];
5272
+ for (const p of authPatterns) {
5273
+ if (fs22.existsSync(path21.join(cwd, p))) result.authFiles.push(p);
5274
+ }
5275
+ const authConfigGlobs = [
5276
+ "src/app/api/auth",
5277
+ "src/auth",
5278
+ "src/lib/auth",
5279
+ "auth.config.ts",
5280
+ "auth.ts",
5281
+ "src/app/api/oauth"
5282
+ ];
5283
+ for (const g of authConfigGlobs) {
5284
+ if (fs22.existsSync(path21.join(cwd, g))) result.authFiles.push(g);
5285
+ }
5286
+ try {
5287
+ const rolePaths = [
5288
+ "src/types",
5289
+ "src/lib",
5290
+ "src/utils",
5291
+ "src/constants",
5292
+ "src/access",
5293
+ "src/collections"
5294
+ ];
5295
+ for (const rp of rolePaths) {
5296
+ const dir = path21.join(cwd, rp);
5297
+ if (!fs22.existsSync(dir)) continue;
5298
+ const files = fs22.readdirSync(dir).filter((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
5299
+ for (const f of files) {
5300
+ try {
5301
+ const content = fs22.readFileSync(path21.join(dir, f), "utf-8").slice(0, 5e3);
5302
+ const roleMatches = content.match(/(?:role|Role|ROLE)\s*[=:]\s*['"](\w+)['"]/g);
5303
+ if (roleMatches) {
5304
+ for (const m of roleMatches) {
5305
+ const val = m.match(/['"](\w+)['"]/);
5306
+ if (val && !result.roles.includes(val[1])) result.roles.push(val[1]);
5307
+ }
5308
+ }
5309
+ const enumMatch = content.match(/(?:enum|type)\s+\w*[Rr]ole\w*\s*[={]([^}]+)/s);
5310
+ if (enumMatch) {
5311
+ const vals = enumMatch[1].match(/['"](\w+)['"]/g);
5312
+ if (vals) {
5313
+ for (const v of vals) {
5314
+ const clean = v.replace(/['"]/g, "");
5315
+ if (!result.roles.includes(clean)) result.roles.push(clean);
5316
+ }
5317
+ }
5318
+ }
5319
+ } catch {
5320
+ }
5321
+ }
5322
+ }
5323
+ } catch {
5324
+ }
5325
+ return result;
5326
+ }
5327
+ function scanRoutes(dir, baseDir, prefix, result) {
5328
+ let entries;
5329
+ try {
5330
+ entries = fs22.readdirSync(dir, { withFileTypes: true });
5331
+ } catch {
5332
+ return;
5333
+ }
5334
+ const hasPage = entries.some((e) => e.isFile() && /^page\.(tsx?|jsx?)$/.test(e.name));
5335
+ if (hasPage) {
5336
+ const routePath = prefix || "/";
5337
+ const group = prefix.startsWith("/admin") ? "admin" : prefix.includes("/login") ? "auth" : prefix.includes("/signup") ? "auth" : prefix.includes("/api") ? "api" : "frontend";
5338
+ result.routes.push({ path: routePath, group });
5339
+ if (prefix.includes("/login")) result.loginPage = routePath;
5340
+ if (prefix.startsWith("/admin") && !result.adminPath) result.adminPath = prefix;
5341
+ }
5342
+ for (const entry of entries) {
5343
+ if (!entry.isDirectory()) continue;
5344
+ if (entry.name === "node_modules" || entry.name === ".next") continue;
5345
+ let segment = entry.name;
5346
+ if (segment.startsWith("(") && segment.endsWith(")")) {
5347
+ scanRoutes(path21.join(dir, entry.name), baseDir, prefix, result);
5348
+ continue;
5349
+ }
5350
+ if (segment.startsWith("[") && segment.endsWith("]")) {
5351
+ segment = `:${segment.slice(1, -1)}`;
5352
+ }
5353
+ if (segment.startsWith("[[") && segment.endsWith("]]")) {
5354
+ segment = `:${segment.slice(2, -2)}?`;
5355
+ }
5356
+ scanRoutes(path21.join(dir, entry.name), baseDir, `${prefix}/${segment}`, result);
5357
+ }
5358
+ }
5359
+ function generateQaGuide(discovery) {
5360
+ const lines = ["# QA Guide", "", "## Authentication", ""];
5361
+ if (discovery.loginPage) {
5362
+ lines.push(`- Login page: \`${discovery.loginPage}\``);
5363
+ }
5364
+ lines.push(
5365
+ "",
5366
+ "### Test Accounts",
5367
+ "<!-- Fill in your test/preview environment credentials below -->",
5368
+ "| Role | Email | Password |",
5369
+ "|------|-------|----------|",
5370
+ "| Admin | admin@example.com | CHANGE_ME |",
5371
+ "| User | user@example.com | CHANGE_ME |",
5372
+ "",
5373
+ "### Login Steps",
5374
+ `1. Navigate to \`${discovery.loginPage ?? "/login"}\``,
5375
+ "2. Enter credentials from the test accounts table above",
5376
+ "3. Submit the login form",
5377
+ "4. Verify redirect to dashboard or home page"
5378
+ );
5379
+ if (discovery.authFiles.length > 0) {
5380
+ lines.push("", "### Auth Files");
5381
+ for (const f of discovery.authFiles) {
5382
+ lines.push(`- \`${f}\``);
5383
+ }
5384
+ }
5385
+ if (discovery.roles.length > 0) {
5386
+ lines.push("", "## Roles", "");
5387
+ for (const role of discovery.roles) {
5388
+ lines.push(`- \`${role}\``);
5389
+ }
5390
+ }
5391
+ lines.push("", "## Key Pages", "");
5392
+ const groups = {};
5393
+ for (const route of discovery.routes) {
5394
+ if (!groups[route.group]) groups[route.group] = [];
5395
+ groups[route.group].push(route.path);
5396
+ }
5397
+ for (const [group, routes] of Object.entries(groups)) {
5398
+ lines.push(`### ${group.charAt(0).toUpperCase() + group.slice(1)}`);
5399
+ const sorted = routes.sort();
5400
+ for (const r of sorted.slice(0, 20)) {
5401
+ lines.push(`- \`${r}\``);
5402
+ }
5403
+ if (sorted.length > 20) {
5404
+ lines.push(`- ... and ${sorted.length - 20} more`);
5405
+ }
5406
+ lines.push("");
5407
+ }
5408
+ lines.push(
5409
+ "## Dev Server",
5410
+ "",
5411
+ `- Command: \`${discovery.devCommand || "pnpm dev"}\``,
5412
+ `- URL: \`http://localhost:${discovery.devPort}\``,
5413
+ ""
5414
+ );
5415
+ return lines.join("\n");
5416
+ }
5227
5417
  function detectArchitectureBasic(cwd) {
5228
5418
  const detected = [];
5229
5419
  const pkgPath = path21.join(cwd, "package.json");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine-lite",
3
- "version": "0.1.101",
3
+ "version": "0.1.103",
4
4
  "description": "Autonomous SDLC pipeline: Kody orchestration + Claude Code + LiteLLM",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -5,19 +5,23 @@ mode: primary
5
5
  tools: [read, write, edit, bash, glob, grep]
6
6
  ---
7
7
 
8
- You are a review-fix agent. The code review found issues that need fixing.
8
+ You are a review-fix agent following the Superpowers Executing Plans methodology.
9
9
 
10
- RULES:
10
+ The code review found issues that need fixing. Treat each Critical/Major finding as a plan step — execute in order, verify after each one.
11
+
12
+ RULES (Superpowers Executing Plans discipline):
11
13
  1. Fix ONLY Critical and Major issues (ignore Minor findings)
12
14
  2. Use Edit for surgical changes — do NOT rewrite entire files
13
15
  3. Run tests after EACH fix to verify nothing breaks
14
- 4. If a fix introduces new issues, revert and try a different approach
15
- 5. Do NOT commit or push — the orchestrator handles git
16
+ 4. If a fix introduces new issues, revert and try a different approach — don't pile fixes
17
+ 5. Document any deviations from the expected fix
18
+ 6. Do NOT commit or push — the orchestrator handles git
16
19
 
17
- Read the review findings carefully. For each Critical/Major finding:
20
+ For each Critical/Major finding:
18
21
  1. Read the affected file to understand full context
19
- 2. Make the minimal change to fix the issue
20
- 3. Run tests to verify the fix
21
- 4. Move to the next finding
22
+ 2. Understand the root cause don't just patch the symptom
23
+ 3. Make the minimal change to fix the issue
24
+ 4. Run tests to verify the fix
25
+ 5. Move to the next finding
22
26
 
23
27
  {{TASK_CONTEXT}}
@@ -7,7 +7,15 @@ tools: [read, glob, grep]
7
7
 
8
8
  You are a task classification agent following the Superpowers Brainstorming methodology.
9
9
 
10
- Before classifying, examine the codebase to understand the project structure, existing patterns, and affected files. Use Read, Glob, and Grep to explore.
10
+ ## MANDATORY: Explore Before Classifying
11
+
12
+ Before classifying, you MUST explore the project context:
13
+ 1. **Examine the codebase** — Use Read, Glob, and Grep to understand project structure, existing patterns, and affected files.
14
+ 2. **Find existing solutions** — Search for how similar problems are already solved in this codebase. If a pattern exists, the task should reuse it.
15
+ 3. **Challenge assumptions** — Does the task description assume an approach? Are there simpler alternatives? Apply YAGNI ruthlessly.
16
+ 4. **Identify ambiguity** — Could the requirements be interpreted two ways? Are there missing edge case decisions?
17
+
18
+ ## Output
11
19
 
12
20
  Output ONLY valid JSON. No markdown fences. No explanation. No extra text before or after the JSON.
13
21
 
@@ -19,6 +27,7 @@ Required JSON format:
19
27
  "scope": ["list", "of", "exact/file/paths", "affected"],
20
28
  "risk_level": "low | medium | high",
21
29
  "hasUI": true,
30
+ "existing_patterns": ["list of existing patterns found that the implementation should reuse"],
22
31
  "questions": []
23
32
  }
24
33
 
@@ -31,9 +40,17 @@ Risk level heuristics:
31
40
  - medium: multiple files, possible side effects, API changes, new dependencies, refactoring existing logic
32
41
  - high: core business logic, data migrations, security, authentication, payment processing, database schema changes
33
42
 
34
- Questions rules:
43
+ existing_patterns rules:
44
+ - List patterns found in the codebase that are relevant to this task
45
+ - Include the file path and a brief description of the pattern
46
+ - If no relevant patterns exist, use an empty array []
47
+ - These inform the planner — reuse existing solutions, don't invent new ones
48
+
49
+ Questions rules (Superpowers Brainstorming discipline):
35
50
  - ONLY ask product/requirements questions — things you CANNOT determine by reading code
36
51
  - Ask about: unclear scope, missing acceptance criteria, ambiguous user behavior, missing edge case decisions
52
+ - Challenge assumptions — if the task implies an approach, consider simpler alternatives
53
+ - Check for ambiguity — could requirements be interpreted two ways?
37
54
  - Do NOT ask about technical implementation — that is the planner's job
38
55
  - Do NOT ask about things you can find by reading the codebase (file structure, frameworks, patterns)
39
56
  - If the task is clear and complete, leave questions as an empty array []