@qlucent/fishi 0.1.0 → 0.2.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.
- package/dist/index.js +65 -11
- 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
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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,9 @@ 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
|
|
1086
1140
|
});
|
|
1087
1141
|
if (brownfieldAnalysis) {
|
|
1088
1142
|
const reportPath = path3.join(targetDir, ".fishi", "memory", "brownfield-analysis.md");
|
|
@@ -1598,12 +1652,12 @@ async function validateCommand() {
|
|
|
1598
1652
|
var program = new Command();
|
|
1599
1653
|
program.name("fishi").description(
|
|
1600
1654
|
chalk6.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
|
|
1601
|
-
).version("0.
|
|
1655
|
+
).version("0.2.0");
|
|
1602
1656
|
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
1657
|
"-c, --cost-mode <mode>",
|
|
1604
1658
|
"Cost mode: performance | balanced | economy",
|
|
1605
1659
|
"balanced"
|
|
1606
|
-
).option("--no-interactive", "Skip interactive wizard even without description").action(initCommand);
|
|
1660
|
+
).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
1661
|
program.command("status").description("Show project status, active agents, and TaskBoard summary").action(statusCommand);
|
|
1608
1662
|
program.command("mcp").description("Manage MCP server integrations").argument("<action>", "Action: add | list | remove").argument("[name]", "MCP server name").action(mcpCommand);
|
|
1609
1663
|
program.command("reset").description("Rollback to a previous checkpoint").argument("[checkpoint]", "Checkpoint ID (defaults to latest)").action(resetCommand);
|