@qlucent/fishi 0.1.0 → 0.3.0

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/index.js +66 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import ora from "ora";
10
10
  import inquirer from "inquirer";
11
11
  import path3 from "path";
12
12
  import fs3 from "fs";
13
+ import { detectConflicts, createBackup } from "@qlucent/fishi-core";
13
14
 
14
15
  // src/analyzers/detector.ts
15
16
  import fs from "fs";
@@ -956,14 +957,21 @@ async function initCommand(description, options) {
956
957
  console.log(chalk.gray(" Autonomous agent framework for Claude Code"));
957
958
  console.log("");
958
959
  if (fs3.existsSync(path3.join(targetDir, ".fishi"))) {
959
- console.log(
960
- chalk.yellow(" \u26A0 FISHI is already initialized in this directory.")
961
- );
962
- console.log(chalk.gray(" Run `fishi status` to see project state."));
963
- console.log(
964
- chalk.gray(" Run `fishi reset` to start over from a checkpoint.")
965
- );
966
- return;
960
+ if (options.interactive !== false) {
961
+ const { reinit } = await inquirer.prompt([{
962
+ type: "confirm",
963
+ name: "reinit",
964
+ message: "FISHI is already initialized in this directory. Re-initialize?",
965
+ default: false
966
+ }]);
967
+ if (!reinit) {
968
+ console.log(chalk.gray(" Run `fishi status` to see project state."));
969
+ return;
970
+ }
971
+ } else {
972
+ console.log(chalk.yellow(" \u26A0 FISHI already initialized. Run `fishi status` to see project state."));
973
+ return;
974
+ }
967
975
  }
968
976
  const spinner = ora("Analyzing project directory...").start();
969
977
  const detection = await detectProjectType(targetDir);
@@ -1054,6 +1062,50 @@ async function initCommand(description, options) {
1054
1062
  }
1055
1063
  }
1056
1064
  }
1065
+ const conflictResult = detectConflicts(targetDir);
1066
+ let resolutions;
1067
+ if (conflictResult.hasConflicts) {
1068
+ console.log("");
1069
+ console.log(chalk.yellow(` \u26A0 Found ${conflictResult.totalConflicts} existing file(s) that FISHI wants to create.`));
1070
+ console.log("");
1071
+ const backupSpinner = ora("Backing up existing files...").start();
1072
+ const allConflictPaths = conflictResult.categories.flatMap((c) => c.conflicts.map((f) => f.path));
1073
+ const backupPath = await createBackup(targetDir, allConflictPaths);
1074
+ backupSpinner.succeed(`Backup created at ${path3.relative(targetDir, backupPath)}`);
1075
+ console.log("");
1076
+ resolutions = { categories: {}, files: {} };
1077
+ if (options.interactive !== false) {
1078
+ for (const cat of conflictResult.categories) {
1079
+ if (cat.conflicts.length === 0) continue;
1080
+ const conflictSummary = cat.conflicts.length === 1 ? `Found existing ${cat.label} (${cat.conflicts[0].size} bytes)` : `Found ${cat.conflicts.length} existing ${cat.label} files`;
1081
+ const noMergeCategories = ["agents", "skills", "commands"];
1082
+ const canMerge = !noMergeCategories.includes(cat.name);
1083
+ const choices = canMerge ? [
1084
+ { name: "Merge \u2014 add FISHI content alongside existing", value: "merge" },
1085
+ { name: "Skip \u2014 leave existing files untouched", value: "skip" },
1086
+ { name: "Replace \u2014 overwrite with FISHI version (backup saved)", value: "replace" }
1087
+ ] : [
1088
+ { name: "Skip \u2014 leave existing files untouched", value: "skip" },
1089
+ { name: "Replace \u2014 overwrite with FISHI version (backup saved)", value: "replace" }
1090
+ ];
1091
+ const { action } = await inquirer.prompt([{
1092
+ type: "list",
1093
+ name: "action",
1094
+ message: `${conflictSummary}. How should FISHI handle this?`,
1095
+ choices,
1096
+ default: canMerge ? "merge" : "skip"
1097
+ }]);
1098
+ resolutions.categories[cat.name] = action;
1099
+ }
1100
+ } else {
1101
+ const defaultAction = options.mergeAll ? "merge" : options.replaceAll ? "replace" : "skip";
1102
+ for (const cat of conflictResult.categories) {
1103
+ if (cat.conflicts.length > 0) {
1104
+ resolutions.categories[cat.name] = defaultAction;
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1057
1109
  console.log("");
1058
1110
  const scaffoldSpinner = ora("Scaffolding FISHI framework...").start();
1059
1111
  try {
@@ -1082,7 +1134,10 @@ async function initCommand(description, options) {
1082
1134
  ...initOptions,
1083
1135
  projectName,
1084
1136
  projectType: detection.type,
1085
- brownfieldAnalysis: brownfieldData
1137
+ brownfieldAnalysis: brownfieldData,
1138
+ resolutions,
1139
+ docsReadmeExists: conflictResult?.docsReadmeExists,
1140
+ rootClaudeMdExists: conflictResult?.rootClaudeMdExists
1086
1141
  });
1087
1142
  if (brownfieldAnalysis) {
1088
1143
  const reportPath = path3.join(targetDir, ".fishi", "memory", "brownfield-analysis.md");
@@ -1598,12 +1653,12 @@ async function validateCommand() {
1598
1653
  var program = new Command();
1599
1654
  program.name("fishi").description(
1600
1655
  chalk6.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
1601
- ).version("0.1.0");
1656
+ ).version("0.3.0");
1602
1657
  program.command("init").description("Initialize FISHI in the current directory").argument("[description]", "Project description (skip wizard with zero-config)").option("-l, --language <lang>", "Primary language (e.g., typescript, python)").option("-f, --framework <framework>", "Framework (e.g., nextjs, express, django)").option(
1603
1658
  "-c, --cost-mode <mode>",
1604
1659
  "Cost mode: performance | balanced | economy",
1605
1660
  "balanced"
1606
- ).option("--no-interactive", "Skip interactive wizard even without description").action(initCommand);
1661
+ ).option("--no-interactive", "Skip interactive wizard even without description").option("--merge-all", "Merge all conflicting files (non-interactive brownfield)").option("--replace-all", "Replace all conflicting files (non-interactive brownfield)").action(initCommand);
1607
1662
  program.command("status").description("Show project status, active agents, and TaskBoard summary").action(statusCommand);
1608
1663
  program.command("mcp").description("Manage MCP server integrations").argument("<action>", "Action: add | list | remove").argument("[name]", "MCP server name").action(mcpCommand);
1609
1664
  program.command("reset").description("Rollback to a previous checkpoint").argument("[checkpoint]", "Checkpoint ID (defaults to latest)").action(resetCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlucent/fishi",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "FISHI — Your AI Dev Team That Actually Ships. Autonomous agent framework for Claude Code.",
5
5
  "license": "MIT",
6
6
  "type": "module",