@kody-ade/kody-engine-lite 0.1.64 → 0.1.66

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/dist/bin/cli.js CHANGED
@@ -3911,7 +3911,7 @@ function buildConfig(cwd, basic) {
3911
3911
  }
3912
3912
  return "";
3913
3913
  };
3914
- return {
3914
+ const config = {
3915
3915
  "$schema": "https://raw.githubusercontent.com/aharonyaircohen/Kody-Engine-Lite/main/kody.config.schema.json",
3916
3916
  quality: {
3917
3917
  typecheck: find("typecheck", "type-check") || (pkg.devDependencies?.typescript ? `${basic.pm} tsc --noEmit` : ""),
@@ -3927,6 +3927,37 @@ function buildConfig(cwd, basic) {
3927
3927
  modelMap: { cheap: "haiku", mid: "sonnet", strong: "opus" }
3928
3928
  }
3929
3929
  };
3930
+ const mcp = detectMcpConfig(cwd, basic.pm, pkg);
3931
+ if (mcp) config.mcp = mcp;
3932
+ return config;
3933
+ }
3934
+ var FRONTEND_DEPS = ["next", "react", "vue", "svelte", "nuxt", "astro", "solid-js", "angular", "@angular/core"];
3935
+ function detectMcpConfig(cwd, pm, pkg) {
3936
+ const allDeps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
3937
+ const hasFrontend = FRONTEND_DEPS.some((dep) => dep in allDeps);
3938
+ if (!hasFrontend) return void 0;
3939
+ const scripts = pkg.scripts ?? {};
3940
+ const hasDevScript = !!scripts.dev;
3941
+ const isNext = "next" in allDeps || "nuxt" in allDeps;
3942
+ const isVite = "vite" in allDeps;
3943
+ const defaultPort = isNext ? 3e3 : isVite ? 5173 : 3e3;
3944
+ const mcp = {
3945
+ enabled: true,
3946
+ servers: {
3947
+ playwright: {
3948
+ command: "npx",
3949
+ args: ["@playwright/mcp@latest"]
3950
+ }
3951
+ },
3952
+ stages: ["build", "review"]
3953
+ };
3954
+ if (hasDevScript) {
3955
+ mcp.devServer = {
3956
+ command: `${pm} dev`,
3957
+ url: `http://localhost:${defaultPort}`
3958
+ };
3959
+ }
3960
+ return mcp;
3930
3961
  }
3931
3962
  function initCommand(opts) {
3932
3963
  const cwd = process.cwd();
@@ -4462,11 +4493,17 @@ REMINDER: Output the full prompt template first (unchanged), then your three app
4462
4493
  } catch {
4463
4494
  console.log(" \u25CB Label creation skipped");
4464
4495
  }
4496
+ console.log("\n\u2500\u2500 Skills \u2500\u2500");
4497
+ const installedSkillPaths = installSkillsForProject(cwd);
4465
4498
  console.log("\n\u2500\u2500 Git \u2500\u2500");
4466
4499
  const filesToCommit = [
4467
4500
  ".kody/memory/architecture.md",
4468
- ".kody/memory/conventions.md"
4501
+ ".kody/memory/conventions.md",
4502
+ ...installedSkillPaths
4469
4503
  ].filter((f) => fs22.existsSync(path21.join(cwd, f)));
4504
+ if (fs22.existsSync(path21.join(cwd, "skills-lock.json"))) {
4505
+ filesToCommit.push("skills-lock.json");
4506
+ }
4470
4507
  for (const stage of STEP_STAGES) {
4471
4508
  const stepFile = `.kody/steps/${stage}.md`;
4472
4509
  if (fs22.existsSync(path21.join(cwd, stepFile))) {
@@ -4599,6 +4636,77 @@ function detectArchitectureBasic(cwd) {
4599
4636
  }
4600
4637
  return detected;
4601
4638
  }
4639
+ var SKILL_MAPPINGS = [
4640
+ {
4641
+ detect: (deps) => "next" in deps,
4642
+ skills: [
4643
+ { package: "vercel-labs/agent-skills@vercel-react-best-practices", label: "React best practices (Vercel)" }
4644
+ ]
4645
+ },
4646
+ {
4647
+ detect: (deps) => "react" in deps && !("next" in deps),
4648
+ skills: [
4649
+ { package: "vercel-labs/agent-skills@vercel-react-best-practices", label: "React best practices (Vercel)" }
4650
+ ]
4651
+ },
4652
+ {
4653
+ detect: (deps) => FRONTEND_DEPS.some((d) => d in deps),
4654
+ skills: [
4655
+ { package: "microsoft/playwright-cli@playwright-cli", label: "Playwright browser automation" }
4656
+ ]
4657
+ }
4658
+ ];
4659
+ function detectSkillsForProject(cwd) {
4660
+ const pkgPath = path21.join(cwd, "package.json");
4661
+ if (!fs22.existsSync(pkgPath)) return [];
4662
+ try {
4663
+ const pkg = JSON.parse(fs22.readFileSync(pkgPath, "utf-8"));
4664
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
4665
+ const seen = /* @__PURE__ */ new Set();
4666
+ const skills = [];
4667
+ for (const mapping of SKILL_MAPPINGS) {
4668
+ if (mapping.detect(allDeps)) {
4669
+ for (const skill of mapping.skills) {
4670
+ if (!seen.has(skill.package)) {
4671
+ seen.add(skill.package);
4672
+ skills.push(skill);
4673
+ }
4674
+ }
4675
+ }
4676
+ }
4677
+ return skills;
4678
+ } catch {
4679
+ return [];
4680
+ }
4681
+ }
4682
+ function installSkillsForProject(cwd) {
4683
+ const skills = detectSkillsForProject(cwd);
4684
+ if (skills.length === 0) {
4685
+ console.log(" \u25CB No skills to install (no frontend framework detected)");
4686
+ return [];
4687
+ }
4688
+ const installedPaths = [];
4689
+ for (const skill of skills) {
4690
+ try {
4691
+ console.log(` Installing: ${skill.label} (${skill.package})`);
4692
+ execFileSync11("npx", ["skills", "add", skill.package, "--yes"], {
4693
+ cwd,
4694
+ encoding: "utf-8",
4695
+ timeout: 6e4,
4696
+ stdio: ["pipe", "pipe", "pipe"]
4697
+ });
4698
+ const skillName = skill.package.split("@").pop() ?? "";
4699
+ const agentPath = `.agents/skills/${skillName}`;
4700
+ const claudePath = `.claude/skills/${skillName}`;
4701
+ if (fs22.existsSync(path21.join(cwd, agentPath))) installedPaths.push(agentPath);
4702
+ if (fs22.existsSync(path21.join(cwd, claudePath))) installedPaths.push(claudePath);
4703
+ console.log(` \u2713 ${skill.label}`);
4704
+ } catch (err) {
4705
+ console.log(` \u2717 ${skill.label} \u2014 failed to install`);
4706
+ }
4707
+ }
4708
+ return installedPaths;
4709
+ }
4602
4710
  var args = process.argv.slice(2);
4603
4711
  var command = args[0];
4604
4712
  if (command === "init") {
@@ -4618,5 +4726,6 @@ export {
4618
4726
  checkGhRepoAccess,
4619
4727
  checkGhSecret,
4620
4728
  detectArchitectureBasic,
4621
- detectBasicConfig
4729
+ detectBasicConfig,
4730
+ detectSkillsForProject
4622
4731
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine-lite",
3
- "version": "0.1.64",
3
+ "version": "0.1.66",
4
4
  "description": "Autonomous SDLC pipeline: Kody orchestration + Claude Code + LiteLLM",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -224,6 +224,9 @@ jobs:
224
224
  - name: Install Claude Code CLI
225
225
  run: npm install -g @anthropic-ai/claude-code
226
226
 
227
+ - name: Install LiteLLM proxy
228
+ run: pip install 'litellm[proxy]'
229
+
227
230
  - name: Configure git
228
231
  run: |
229
232
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
@@ -232,6 +235,7 @@ jobs:
232
235
  - name: Run Kody pipeline
233
236
  env:
234
237
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
238
+ MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
235
239
  GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
236
240
  TASK_ID: ${{ github.event.inputs.task_id || needs.parse.outputs.task_id }}
237
241
  MODE: ${{ github.event.inputs.mode || needs.parse.outputs.mode || 'full' }}
@@ -254,7 +258,8 @@ jobs:
254
258
  [ -n "$TASK_ID" ] && ARGS="$ARGS --task-id $TASK_ID"
255
259
  [ -n "$PR_NUMBER" ] && ARGS="$ARGS --pr-number $PR_NUMBER"
256
260
  [ -n "$FROM_STAGE" ] && ARGS="$ARGS --from $FROM_STAGE"
257
- # FEEDBACK is passed via env var, not CLI arg (avoids shell escaping issues)
261
+ # FEEDBACK is also passed via env var (avoids shell escaping issues)
262
+ [ -n "$FEEDBACK" ] && ARGS="$ARGS --feedback \"$FEEDBACK\""
258
263
  [ "$DRY_RUN" = "true" ] && ARGS="$ARGS --dry-run"
259
264
  kody-engine-lite $CMD $ARGS
260
265
  fi
@@ -290,10 +295,11 @@ jobs:
290
295
  - name: Upload artifacts
291
296
  if: always()
292
297
  uses: actions/upload-artifact@v4
298
+ continue-on-error: true
293
299
  with:
294
300
  name: kody-tasks-${{ github.event.inputs.task_id || needs.parse.outputs.task_id }}
295
301
  path: .kody/tasks/
296
- retention-days: 7
302
+ retention-days: 3
297
303
 
298
304
  # ─── Error Notifications ─────────────────────────────────────────────────────
299
305
  notify-parse-error: