@kody-ade/kody-engine-lite 0.1.33 → 0.1.35

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.
Files changed (2) hide show
  1. package/dist/bin/cli.js +161 -126
  2. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -2516,15 +2516,70 @@ var init_task_resolution = __esm({
2516
2516
  }
2517
2517
  });
2518
2518
 
2519
- // src/entry.ts
2520
- var entry_exports = {};
2519
+ // src/cli/task-state.ts
2521
2520
  import * as fs18 from "fs";
2522
2521
  import * as path17 from "path";
2522
+ function resolveTaskAction(issueNumber, existingTaskId, existingState) {
2523
+ if (!existingTaskId || !existingState) {
2524
+ return { action: "start-fresh", taskId: `${issueNumber}-${generateTaskId()}` };
2525
+ }
2526
+ if (existingState.state === "completed") {
2527
+ return { action: "already-completed", taskId: existingTaskId };
2528
+ }
2529
+ if (existingState.state === "running") {
2530
+ return { action: "already-running", taskId: existingTaskId };
2531
+ }
2532
+ if (existingState.state === "failed") {
2533
+ for (const stageName of STAGE_ORDER) {
2534
+ const stage = existingState.stages[stageName];
2535
+ if (!stage) continue;
2536
+ if (stage.error?.includes("paused")) {
2537
+ const idx = STAGE_ORDER.indexOf(stageName);
2538
+ if (idx < STAGE_ORDER.length - 1) {
2539
+ return { action: "resume", taskId: existingTaskId, fromStage: STAGE_ORDER[idx + 1] };
2540
+ }
2541
+ }
2542
+ if (stage.state === "failed" || stage.state === "pending") {
2543
+ return { action: "resume", taskId: existingTaskId, fromStage: stageName };
2544
+ }
2545
+ }
2546
+ return { action: "resume", taskId: existingTaskId, fromStage: "taskify" };
2547
+ }
2548
+ return { action: "start-fresh", taskId: `${issueNumber}-${generateTaskId()}` };
2549
+ }
2550
+ function resolveForIssue(issueNumber, projectDir) {
2551
+ const existingTaskId = findLatestTaskForIssue(issueNumber, projectDir);
2552
+ if (!existingTaskId) {
2553
+ return resolveTaskAction(issueNumber, null, null);
2554
+ }
2555
+ const statusPath = path17.join(projectDir, ".tasks", existingTaskId, "status.json");
2556
+ let existingState = null;
2557
+ if (fs18.existsSync(statusPath)) {
2558
+ try {
2559
+ existingState = JSON.parse(fs18.readFileSync(statusPath, "utf-8"));
2560
+ } catch {
2561
+ }
2562
+ }
2563
+ return resolveTaskAction(issueNumber, existingTaskId, existingState);
2564
+ }
2565
+ var STAGE_ORDER;
2566
+ var init_task_state = __esm({
2567
+ "src/cli/task-state.ts"() {
2568
+ "use strict";
2569
+ init_task_resolution();
2570
+ STAGE_ORDER = ["taskify", "plan", "build", "verify", "review", "review-fix", "ship"];
2571
+ }
2572
+ });
2573
+
2574
+ // src/entry.ts
2575
+ var entry_exports = {};
2576
+ import * as fs19 from "fs";
2577
+ import * as path18 from "path";
2523
2578
  async function main() {
2524
2579
  const input = parseArgs();
2525
- const projectDir = input.cwd ? path17.resolve(input.cwd) : process.cwd();
2580
+ const projectDir = input.cwd ? path18.resolve(input.cwd) : process.cwd();
2526
2581
  if (input.cwd) {
2527
- if (!fs18.existsSync(projectDir)) {
2582
+ if (!fs19.existsSync(projectDir)) {
2528
2583
  console.error(`--cwd path does not exist: ${projectDir}`);
2529
2584
  process.exit(1);
2530
2585
  }
@@ -2534,16 +2589,35 @@ async function main() {
2534
2589
  }
2535
2590
  let taskId = input.taskId;
2536
2591
  if (!taskId) {
2537
- if ((input.command === "rerun" || input.command === "fix") && input.issueNumber) {
2538
- const found = findLatestTaskForIssue(input.issueNumber, projectDir);
2539
- if (!found) {
2540
- console.error(`No previous task found for issue #${input.issueNumber}`);
2541
- process.exit(1);
2592
+ if (input.issueNumber) {
2593
+ const taskAction = resolveForIssue(input.issueNumber, projectDir);
2594
+ logger.info(`Task action: ${taskAction.action}`);
2595
+ if (taskAction.action === "already-completed") {
2596
+ logger.info(`Issue #${input.issueNumber} already completed (task ${taskAction.taskId})`);
2597
+ if (!input.local) {
2598
+ try {
2599
+ postComment(input.issueNumber, `\u2705 Issue #${input.issueNumber} already completed (task \`${taskAction.taskId}\`)`);
2600
+ } catch {
2601
+ }
2602
+ }
2603
+ process.exit(0);
2604
+ }
2605
+ if (taskAction.action === "already-running") {
2606
+ logger.info(`Issue #${input.issueNumber} already running (task ${taskAction.taskId})`);
2607
+ if (!input.local) {
2608
+ try {
2609
+ postComment(input.issueNumber, `\u23F3 Pipeline already running for issue #${input.issueNumber} (task \`${taskAction.taskId}\`)`);
2610
+ } catch {
2611
+ }
2612
+ }
2613
+ process.exit(0);
2614
+ }
2615
+ taskId = taskAction.taskId;
2616
+ if (taskAction.action === "resume") {
2617
+ input.fromStage = taskAction.fromStage;
2618
+ input.command = "rerun";
2619
+ logger.info(`Resuming task ${taskId} from ${taskAction.fromStage}`);
2542
2620
  }
2543
- taskId = found;
2544
- logger.info(`Found latest task for issue #${input.issueNumber}: ${taskId}`);
2545
- } else if (input.issueNumber) {
2546
- taskId = `${input.issueNumber}-${generateTaskId()}`;
2547
2621
  } else if (input.command === "run" && input.task) {
2548
2622
  taskId = generateTaskId();
2549
2623
  } else {
@@ -2551,8 +2625,8 @@ async function main() {
2551
2625
  process.exit(1);
2552
2626
  }
2553
2627
  }
2554
- const taskDir = path17.join(projectDir, ".tasks", taskId);
2555
- fs18.mkdirSync(taskDir, { recursive: true });
2628
+ const taskDir = path18.join(projectDir, ".tasks", taskId);
2629
+ fs19.mkdirSync(taskDir, { recursive: true });
2556
2630
  if (input.command === "status") {
2557
2631
  printStatus(taskId, taskDir);
2558
2632
  return;
@@ -2560,67 +2634,27 @@ async function main() {
2560
2634
  logger.info("Preflight checks:");
2561
2635
  runPreflight();
2562
2636
  if (input.task) {
2563
- fs18.writeFileSync(path17.join(taskDir, "task.md"), input.task);
2637
+ fs19.writeFileSync(path18.join(taskDir, "task.md"), input.task);
2564
2638
  }
2565
- const taskMdPath = path17.join(taskDir, "task.md");
2566
- if (!fs18.existsSync(taskMdPath) && input.issueNumber) {
2639
+ const taskMdPath = path18.join(taskDir, "task.md");
2640
+ if (!fs19.existsSync(taskMdPath) && input.issueNumber) {
2567
2641
  logger.info(`Fetching issue #${input.issueNumber} body as task...`);
2568
2642
  const issue = getIssue(input.issueNumber);
2569
2643
  if (issue) {
2570
2644
  const taskContent = `# ${issue.title}
2571
2645
 
2572
2646
  ${issue.body ?? ""}`;
2573
- fs18.writeFileSync(taskMdPath, taskContent);
2647
+ fs19.writeFileSync(taskMdPath, taskContent);
2574
2648
  logger.info(` Task loaded from issue #${input.issueNumber}: ${issue.title}`);
2575
2649
  }
2576
2650
  }
2577
- if (input.command === "run") {
2578
- if (!fs18.existsSync(taskMdPath)) {
2579
- console.error("No task.md found. Provide --task, --issue-number, or ensure .tasks/<id>/task.md exists.");
2580
- process.exit(1);
2581
- }
2651
+ if (!fs19.existsSync(taskMdPath)) {
2652
+ console.error("No task.md found. Provide --task, --issue-number, or ensure .tasks/<id>/task.md exists.");
2653
+ process.exit(1);
2582
2654
  }
2583
2655
  if (input.command === "fix" && !input.fromStage) {
2584
2656
  input.fromStage = "build";
2585
2657
  }
2586
- if (input.command === "rerun" && !input.fromStage) {
2587
- const statusPath = path17.join(taskDir, "status.json");
2588
- if (fs18.existsSync(statusPath)) {
2589
- try {
2590
- const status = JSON.parse(fs18.readFileSync(statusPath, "utf-8"));
2591
- const stageNames = ["taskify", "plan", "build", "verify", "review", "review-fix", "ship"];
2592
- let foundPaused = false;
2593
- for (const name of stageNames) {
2594
- const s = status.stages[name];
2595
- if (s?.error?.includes("paused")) {
2596
- const idx = stageNames.indexOf(name);
2597
- if (idx < stageNames.length - 1) {
2598
- input.fromStage = stageNames[idx + 1];
2599
- foundPaused = true;
2600
- logger.info(`Auto-detected resume from: ${input.fromStage} (after paused ${name})`);
2601
- break;
2602
- }
2603
- }
2604
- if (s?.state === "failed" || s?.state === "pending") {
2605
- input.fromStage = name;
2606
- foundPaused = true;
2607
- logger.info(`Auto-detected resume from: ${input.fromStage}`);
2608
- break;
2609
- }
2610
- }
2611
- if (!foundPaused) {
2612
- input.fromStage = "taskify";
2613
- logger.info("No paused/failed stage found, resuming from taskify");
2614
- }
2615
- } catch {
2616
- console.error("--from <stage> is required (could not read status.json)");
2617
- process.exit(1);
2618
- }
2619
- } else {
2620
- logger.info("No status.json found \u2014 running full pipeline with feedback");
2621
- input.command = "run";
2622
- }
2623
- }
2624
2658
  const config = getProjectConfig();
2625
2659
  let litellmProcess = null;
2626
2660
  const cleanupLitellm = () => {
@@ -2694,7 +2728,7 @@ To rerun: \`@kody rerun ${taskId} --from <stage>\``
2694
2728
  }
2695
2729
  }
2696
2730
  const state = await runPipeline(ctx);
2697
- const files = fs18.readdirSync(taskDir);
2731
+ const files = fs19.readdirSync(taskDir);
2698
2732
  console.log(`
2699
2733
  Artifacts in ${taskDir}:`);
2700
2734
  for (const f of files) {
@@ -2738,6 +2772,7 @@ var init_entry = __esm({
2738
2772
  init_args();
2739
2773
  init_litellm();
2740
2774
  init_task_resolution();
2775
+ init_task_state();
2741
2776
  main().catch(async (err) => {
2742
2777
  const msg = err instanceof Error ? err.message : String(err);
2743
2778
  console.error(msg);
@@ -2755,15 +2790,15 @@ var init_entry = __esm({
2755
2790
  });
2756
2791
 
2757
2792
  // src/bin/cli.ts
2758
- import * as fs19 from "fs";
2759
- import * as path18 from "path";
2793
+ import * as fs20 from "fs";
2794
+ import * as path19 from "path";
2760
2795
  import { execFileSync as execFileSync11 } from "child_process";
2761
2796
  import { fileURLToPath } from "url";
2762
- var __dirname = path18.dirname(fileURLToPath(import.meta.url));
2763
- var PKG_ROOT = path18.resolve(__dirname, "..", "..");
2797
+ var __dirname = path19.dirname(fileURLToPath(import.meta.url));
2798
+ var PKG_ROOT = path19.resolve(__dirname, "..", "..");
2764
2799
  function getVersion() {
2765
- const pkgPath = path18.join(PKG_ROOT, "package.json");
2766
- const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
2800
+ const pkgPath = path19.join(PKG_ROOT, "package.json");
2801
+ const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
2767
2802
  return pkg.version;
2768
2803
  }
2769
2804
  function checkCommand2(name, args2, fix) {
@@ -2779,7 +2814,7 @@ function checkCommand2(name, args2, fix) {
2779
2814
  }
2780
2815
  }
2781
2816
  function checkFile(filePath, description, fix) {
2782
- if (fs19.existsSync(filePath)) {
2817
+ if (fs20.existsSync(filePath)) {
2783
2818
  return { name: description, ok: true, detail: filePath };
2784
2819
  }
2785
2820
  return { name: description, ok: false, fix };
@@ -2851,10 +2886,10 @@ function checkGhSecret(repoSlug, secretName) {
2851
2886
  }
2852
2887
  function detectArchitecture(cwd) {
2853
2888
  const detected = [];
2854
- const pkgPath = path18.join(cwd, "package.json");
2855
- if (fs19.existsSync(pkgPath)) {
2889
+ const pkgPath = path19.join(cwd, "package.json");
2890
+ if (fs20.existsSync(pkgPath)) {
2856
2891
  try {
2857
- const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf-8"));
2892
+ const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf-8"));
2858
2893
  const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
2859
2894
  if (allDeps.next) detected.push(`- Framework: Next.js ${allDeps.next}`);
2860
2895
  else if (allDeps.react) detected.push(`- Framework: React ${allDeps.react}`);
@@ -2877,41 +2912,41 @@ function detectArchitecture(cwd) {
2877
2912
  if (allDeps.tailwindcss) detected.push(`- CSS: Tailwind CSS ${allDeps.tailwindcss}`);
2878
2913
  if (pkg.type === "module") detected.push("- Module system: ESM");
2879
2914
  else detected.push("- Module system: CommonJS");
2880
- if (fs19.existsSync(path18.join(cwd, "pnpm-lock.yaml"))) detected.push("- Package manager: pnpm");
2881
- else if (fs19.existsSync(path18.join(cwd, "yarn.lock"))) detected.push("- Package manager: yarn");
2882
- else if (fs19.existsSync(path18.join(cwd, "bun.lockb"))) detected.push("- Package manager: bun");
2883
- else if (fs19.existsSync(path18.join(cwd, "package-lock.json"))) detected.push("- Package manager: npm");
2915
+ if (fs20.existsSync(path19.join(cwd, "pnpm-lock.yaml"))) detected.push("- Package manager: pnpm");
2916
+ else if (fs20.existsSync(path19.join(cwd, "yarn.lock"))) detected.push("- Package manager: yarn");
2917
+ else if (fs20.existsSync(path19.join(cwd, "bun.lockb"))) detected.push("- Package manager: bun");
2918
+ else if (fs20.existsSync(path19.join(cwd, "package-lock.json"))) detected.push("- Package manager: npm");
2884
2919
  } catch {
2885
2920
  }
2886
2921
  }
2887
2922
  try {
2888
- const entries = fs19.readdirSync(cwd, { withFileTypes: true });
2923
+ const entries = fs20.readdirSync(cwd, { withFileTypes: true });
2889
2924
  const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules").map((e) => e.name);
2890
2925
  if (dirs.length > 0) detected.push(`- Top-level directories: ${dirs.join(", ")}`);
2891
2926
  } catch {
2892
2927
  }
2893
- const srcDir = path18.join(cwd, "src");
2894
- if (fs19.existsSync(srcDir)) {
2928
+ const srcDir = path19.join(cwd, "src");
2929
+ if (fs20.existsSync(srcDir)) {
2895
2930
  try {
2896
- const srcEntries = fs19.readdirSync(srcDir, { withFileTypes: true });
2931
+ const srcEntries = fs20.readdirSync(srcDir, { withFileTypes: true });
2897
2932
  const srcDirs = srcEntries.filter((e) => e.isDirectory()).map((e) => e.name);
2898
2933
  if (srcDirs.length > 0) detected.push(`- src/ structure: ${srcDirs.join(", ")}`);
2899
2934
  } catch {
2900
2935
  }
2901
2936
  }
2902
2937
  const configs = [];
2903
- if (fs19.existsSync(path18.join(cwd, "tsconfig.json"))) configs.push("tsconfig.json");
2904
- if (fs19.existsSync(path18.join(cwd, "docker-compose.yml")) || fs19.existsSync(path18.join(cwd, "docker-compose.yaml"))) configs.push("docker-compose");
2905
- if (fs19.existsSync(path18.join(cwd, "Dockerfile"))) configs.push("Dockerfile");
2906
- if (fs19.existsSync(path18.join(cwd, ".env")) || fs19.existsSync(path18.join(cwd, ".env.local"))) configs.push(".env");
2938
+ if (fs20.existsSync(path19.join(cwd, "tsconfig.json"))) configs.push("tsconfig.json");
2939
+ if (fs20.existsSync(path19.join(cwd, "docker-compose.yml")) || fs20.existsSync(path19.join(cwd, "docker-compose.yaml"))) configs.push("docker-compose");
2940
+ if (fs20.existsSync(path19.join(cwd, "Dockerfile"))) configs.push("Dockerfile");
2941
+ if (fs20.existsSync(path19.join(cwd, ".env")) || fs20.existsSync(path19.join(cwd, ".env.local"))) configs.push(".env");
2907
2942
  if (configs.length > 0) detected.push(`- Config files: ${configs.join(", ")}`);
2908
2943
  return detected;
2909
2944
  }
2910
2945
  function detectBasicConfig(cwd) {
2911
2946
  let pm = "pnpm";
2912
- if (fs19.existsSync(path18.join(cwd, "yarn.lock"))) pm = "yarn";
2913
- else if (fs19.existsSync(path18.join(cwd, "bun.lockb"))) pm = "bun";
2914
- else if (!fs19.existsSync(path18.join(cwd, "pnpm-lock.yaml")) && fs19.existsSync(path18.join(cwd, "package-lock.json"))) pm = "npm";
2947
+ if (fs20.existsSync(path19.join(cwd, "yarn.lock"))) pm = "yarn";
2948
+ else if (fs20.existsSync(path19.join(cwd, "bun.lockb"))) pm = "bun";
2949
+ else if (!fs20.existsSync(path19.join(cwd, "pnpm-lock.yaml")) && fs20.existsSync(path19.join(cwd, "package-lock.json"))) pm = "npm";
2915
2950
  let defaultBranch = "main";
2916
2951
  try {
2917
2952
  const ref = execFileSync11("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
@@ -2955,9 +2990,9 @@ function smartInit(cwd) {
2955
2990
  const basic = detectBasicConfig(cwd);
2956
2991
  let context = "";
2957
2992
  const readIfExists = (rel, maxChars = 3e3) => {
2958
- const p = path18.join(cwd, rel);
2959
- if (fs19.existsSync(p)) {
2960
- const content = fs19.readFileSync(p, "utf-8");
2993
+ const p = path19.join(cwd, rel);
2994
+ if (fs20.existsSync(p)) {
2995
+ const content = fs20.readFileSync(p, "utf-8");
2961
2996
  return content.slice(0, maxChars);
2962
2997
  }
2963
2998
  return null;
@@ -2983,14 +3018,14 @@ ${claudeMd}
2983
3018
 
2984
3019
  `;
2985
3020
  try {
2986
- const topDirs = fs19.readdirSync(cwd, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules").map((e) => e.name);
3021
+ const topDirs = fs20.readdirSync(cwd, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules").map((e) => e.name);
2987
3022
  context += `## Top-level directories
2988
3023
  ${topDirs.join(", ")}
2989
3024
 
2990
3025
  `;
2991
- const srcDir = path18.join(cwd, "src");
2992
- if (fs19.existsSync(srcDir)) {
2993
- const srcDirs = fs19.readdirSync(srcDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
3026
+ const srcDir = path19.join(cwd, "src");
3027
+ if (fs20.existsSync(srcDir)) {
3028
+ const srcDirs = fs20.readdirSync(srcDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
2994
3029
  context += `## src/ subdirectories
2995
3030
  ${srcDirs.join(", ")}
2996
3031
 
@@ -3000,7 +3035,7 @@ ${srcDirs.join(", ")}
3000
3035
  }
3001
3036
  const existingFiles = [];
3002
3037
  for (const f of [".env.example", "CLAUDE.md", ".ai-docs", "vitest.config.ts", "vitest.config.mts", "jest.config.ts", "playwright.config.ts", ".eslintrc.js", "eslint.config.mjs", ".prettierrc"]) {
3003
- if (fs19.existsSync(path18.join(cwd, f))) existingFiles.push(f);
3038
+ if (fs20.existsSync(path19.join(cwd, f))) existingFiles.push(f);
3004
3039
  }
3005
3040
  if (existingFiles.length) context += `## Config files present
3006
3041
  ${existingFiles.join(", ")}
@@ -3106,7 +3141,7 @@ ${context}`;
3106
3141
  function validateQualityCommands(cwd, config, pm) {
3107
3142
  let scripts = {};
3108
3143
  try {
3109
- const pkg = JSON.parse(fs19.readFileSync(path18.join(cwd, "package.json"), "utf-8"));
3144
+ const pkg = JSON.parse(fs20.readFileSync(path19.join(cwd, "package.json"), "utf-8"));
3110
3145
  scripts = pkg.scripts ?? {};
3111
3146
  } catch {
3112
3147
  return;
@@ -3140,7 +3175,7 @@ function validateQualityCommands(cwd, config, pm) {
3140
3175
  function buildFallbackConfig(cwd, basic) {
3141
3176
  const pkg = (() => {
3142
3177
  try {
3143
- return JSON.parse(fs19.readFileSync(path18.join(cwd, "package.json"), "utf-8"));
3178
+ return JSON.parse(fs20.readFileSync(path19.join(cwd, "package.json"), "utf-8"));
3144
3179
  } catch {
3145
3180
  return {};
3146
3181
  }
@@ -3180,34 +3215,34 @@ function initCommand(opts) {
3180
3215
  console.log(`Project: ${cwd}
3181
3216
  `);
3182
3217
  console.log("\u2500\u2500 Files \u2500\u2500");
3183
- const templatesDir = path18.join(PKG_ROOT, "templates");
3184
- const workflowSrc = path18.join(templatesDir, "kody.yml");
3185
- const workflowDest = path18.join(cwd, ".github", "workflows", "kody.yml");
3186
- if (!fs19.existsSync(workflowSrc)) {
3218
+ const templatesDir = path19.join(PKG_ROOT, "templates");
3219
+ const workflowSrc = path19.join(templatesDir, "kody.yml");
3220
+ const workflowDest = path19.join(cwd, ".github", "workflows", "kody.yml");
3221
+ if (!fs20.existsSync(workflowSrc)) {
3187
3222
  console.error(" \u2717 Template kody.yml not found in package");
3188
3223
  process.exit(1);
3189
3224
  }
3190
- if (fs19.existsSync(workflowDest) && !opts.force) {
3225
+ if (fs20.existsSync(workflowDest) && !opts.force) {
3191
3226
  console.log(" \u25CB .github/workflows/kody.yml (exists, use --force to overwrite)");
3192
3227
  } else {
3193
- fs19.mkdirSync(path18.dirname(workflowDest), { recursive: true });
3194
- fs19.copyFileSync(workflowSrc, workflowDest);
3228
+ fs20.mkdirSync(path19.dirname(workflowDest), { recursive: true });
3229
+ fs20.copyFileSync(workflowSrc, workflowDest);
3195
3230
  console.log(" \u2713 .github/workflows/kody.yml");
3196
3231
  }
3197
- const configDest = path18.join(cwd, "kody.config.json");
3232
+ const configDest = path19.join(cwd, "kody.config.json");
3198
3233
  let smartResult = null;
3199
- if (!fs19.existsSync(configDest) || opts.force) {
3234
+ if (!fs20.existsSync(configDest) || opts.force) {
3200
3235
  smartResult = smartInit(cwd);
3201
- fs19.writeFileSync(configDest, JSON.stringify(smartResult.config, null, 2) + "\n");
3236
+ fs20.writeFileSync(configDest, JSON.stringify(smartResult.config, null, 2) + "\n");
3202
3237
  console.log(" \u2713 kody.config.json (auto-configured)");
3203
3238
  } else {
3204
3239
  console.log(" \u25CB kody.config.json (exists)");
3205
3240
  }
3206
- const gitignorePath = path18.join(cwd, ".gitignore");
3207
- if (fs19.existsSync(gitignorePath)) {
3208
- const content = fs19.readFileSync(gitignorePath, "utf-8");
3241
+ const gitignorePath = path19.join(cwd, ".gitignore");
3242
+ if (fs20.existsSync(gitignorePath)) {
3243
+ const content = fs20.readFileSync(gitignorePath, "utf-8");
3209
3244
  if (!content.includes(".tasks/")) {
3210
- fs19.appendFileSync(gitignorePath, "\n.tasks/\n");
3245
+ fs20.appendFileSync(gitignorePath, "\n.tasks/\n");
3211
3246
  console.log(" \u2713 .gitignore (added .tasks/)");
3212
3247
  } else {
3213
3248
  console.log(" \u25CB .gitignore (.tasks/ already present)");
@@ -3220,7 +3255,7 @@ function initCommand(opts) {
3220
3255
  checkCommand2("git", ["--version"], "Install git"),
3221
3256
  checkCommand2("node", ["--version"], "Install Node.js >= 22"),
3222
3257
  checkCommand2("pnpm", ["--version"], "Install: npm i -g pnpm"),
3223
- checkFile(path18.join(cwd, "package.json"), "package.json", "Run: pnpm init")
3258
+ checkFile(path19.join(cwd, "package.json"), "package.json", "Run: pnpm init")
3224
3259
  ];
3225
3260
  for (const c of checks) {
3226
3261
  if (c.ok) {
@@ -3297,9 +3332,9 @@ function initCommand(opts) {
3297
3332
  }
3298
3333
  }
3299
3334
  console.log("\n\u2500\u2500 Config \u2500\u2500");
3300
- if (fs19.existsSync(configDest)) {
3335
+ if (fs20.existsSync(configDest)) {
3301
3336
  try {
3302
- const config = JSON.parse(fs19.readFileSync(configDest, "utf-8"));
3337
+ const config = JSON.parse(fs20.readFileSync(configDest, "utf-8"));
3303
3338
  const configChecks = [];
3304
3339
  if (config.github?.owner && config.github?.repo) {
3305
3340
  configChecks.push({ name: "github.owner/repo", ok: true, detail: `${config.github.owner}/${config.github.repo}` });
@@ -3326,21 +3361,21 @@ function initCommand(opts) {
3326
3361
  }
3327
3362
  }
3328
3363
  console.log("\n\u2500\u2500 Project Memory \u2500\u2500");
3329
- const memoryDir = path18.join(cwd, ".kody", "memory");
3330
- fs19.mkdirSync(memoryDir, { recursive: true });
3331
- const archPath = path18.join(memoryDir, "architecture.md");
3332
- const conventionsPath = path18.join(memoryDir, "conventions.md");
3333
- if (fs19.existsSync(archPath) && !opts.force) {
3364
+ const memoryDir = path19.join(cwd, ".kody", "memory");
3365
+ fs20.mkdirSync(memoryDir, { recursive: true });
3366
+ const archPath = path19.join(memoryDir, "architecture.md");
3367
+ const conventionsPath = path19.join(memoryDir, "conventions.md");
3368
+ if (fs20.existsSync(archPath) && !opts.force) {
3334
3369
  console.log(" \u25CB .kody/memory/architecture.md (exists, use --force to regenerate)");
3335
3370
  } else if (smartResult?.architecture) {
3336
- fs19.writeFileSync(archPath, smartResult.architecture);
3371
+ fs20.writeFileSync(archPath, smartResult.architecture);
3337
3372
  const lineCount = smartResult.architecture.split("\n").length;
3338
3373
  console.log(` \u2713 .kody/memory/architecture.md (${lineCount} lines, LLM-generated)`);
3339
3374
  } else {
3340
3375
  const archItems = detectArchitecture(cwd);
3341
3376
  if (archItems.length > 0) {
3342
3377
  const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3343
- fs19.writeFileSync(archPath, `# Architecture (auto-detected ${timestamp2})
3378
+ fs20.writeFileSync(archPath, `# Architecture (auto-detected ${timestamp2})
3344
3379
 
3345
3380
  ## Overview
3346
3381
  ${archItems.join("\n")}
@@ -3350,14 +3385,14 @@ ${archItems.join("\n")}
3350
3385
  console.log(" \u25CB No architecture detected");
3351
3386
  }
3352
3387
  }
3353
- if (fs19.existsSync(conventionsPath) && !opts.force) {
3388
+ if (fs20.existsSync(conventionsPath) && !opts.force) {
3354
3389
  console.log(" \u25CB .kody/memory/conventions.md (exists, use --force to regenerate)");
3355
3390
  } else if (smartResult?.conventions) {
3356
- fs19.writeFileSync(conventionsPath, smartResult.conventions);
3391
+ fs20.writeFileSync(conventionsPath, smartResult.conventions);
3357
3392
  const lineCount = smartResult.conventions.split("\n").length;
3358
3393
  console.log(` \u2713 .kody/memory/conventions.md (${lineCount} lines, LLM-generated)`);
3359
3394
  } else {
3360
- fs19.writeFileSync(conventionsPath, "# Conventions\n\n<!-- Auto-learned conventions will be appended here -->\n");
3395
+ fs20.writeFileSync(conventionsPath, "# Conventions\n\n<!-- Auto-learned conventions will be appended here -->\n");
3361
3396
  console.log(" \u2713 .kody/memory/conventions.md (seed)");
3362
3397
  }
3363
3398
  console.log("\n\u2500\u2500 Git \u2500\u2500");
@@ -3366,7 +3401,7 @@ ${archItems.join("\n")}
3366
3401
  "kody.config.json",
3367
3402
  ".kody/memory/architecture.md",
3368
3403
  ".kody/memory/conventions.md"
3369
- ].filter((f) => fs19.existsSync(path18.join(cwd, f)));
3404
+ ].filter((f) => fs20.existsSync(path19.join(cwd, f)));
3370
3405
  if (filesToCommit.length > 0) {
3371
3406
  try {
3372
3407
  execFileSync11("git", ["add", ...filesToCommit], { cwd, stdio: "pipe" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine-lite",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "description": "Autonomous SDLC pipeline: Kody orchestration + Claude Code + LiteLLM",
5
5
  "license": "MIT",
6
6
  "type": "module",