@qlucent/fishi 0.14.6 → 0.14.8

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 +88 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1025,30 +1025,94 @@ async function initCommand(description, options) {
1025
1025
  name: "installDocker",
1026
1026
  message: "How would you like to proceed?",
1027
1027
  choices: [
1028
- { name: "Install Docker (opens install page \u2014 recommended)", value: "install" },
1028
+ { name: "Install Docker automatically (recommended)", value: "install" },
1029
1029
  { name: "Continue without Docker (process-level isolation only)", value: "skip" }
1030
1030
  ],
1031
1031
  default: "install"
1032
1032
  }]);
1033
1033
  if (installDocker === "install") {
1034
- const dockerUrl = "https://docs.docker.com/get-docker/";
1034
+ const { execSync: execSyncInstall } = await import("child_process");
1035
+ const platform = process.platform;
1036
+ let installCmd = "";
1037
+ let platformName = "";
1038
+ if (platform === "win32") {
1039
+ installCmd = "winget install Docker.DockerDesktop --accept-package-agreements --accept-source-agreements";
1040
+ platformName = "Windows (winget)";
1041
+ } else if (platform === "darwin") {
1042
+ installCmd = "brew install --cask docker";
1043
+ platformName = "macOS (Homebrew)";
1044
+ } else {
1045
+ try {
1046
+ execSyncInstall("which apt-get", { stdio: "ignore" });
1047
+ installCmd = "sudo apt-get update && sudo apt-get install -y docker.io docker-compose-v2";
1048
+ platformName = "Linux (apt)";
1049
+ } catch {
1050
+ try {
1051
+ execSyncInstall("which dnf", { stdio: "ignore" });
1052
+ installCmd = "sudo dnf install -y docker docker-compose";
1053
+ platformName = "Linux (dnf)";
1054
+ } catch {
1055
+ try {
1056
+ execSyncInstall("which yum", { stdio: "ignore" });
1057
+ installCmd = "sudo yum install -y docker docker-compose";
1058
+ platformName = "Linux (yum)";
1059
+ } catch {
1060
+ console.log(chalk.red(" Could not detect package manager. Install Docker manually:"));
1061
+ console.log(chalk.gray(" https://docs.docker.com/get-docker/"));
1062
+ console.log(chalk.gray(" Then run `fishi init` again."));
1063
+ console.log("");
1064
+ return;
1065
+ }
1066
+ }
1067
+ }
1068
+ }
1035
1069
  console.log("");
1036
- console.log(chalk.cyan(` Opening: ${dockerUrl}`));
1037
- console.log(chalk.gray(" Install Docker, then run `fishi init` again."));
1070
+ console.log(chalk.cyan(` Detected: ${platformName}`));
1071
+ console.log(chalk.gray(` Running: ${installCmd}`));
1038
1072
  console.log("");
1073
+ const installSpinner = ora("Installing Docker...").start();
1039
1074
  try {
1040
- const { execSync: execSyncOpen } = await import("child_process");
1041
- const platform = process.platform;
1042
- if (platform === "win32") execSyncOpen(`start ${dockerUrl}`, { stdio: "ignore" });
1043
- else if (platform === "darwin") execSyncOpen(`open ${dockerUrl}`, { stdio: "ignore" });
1044
- else execSyncOpen(`xdg-open ${dockerUrl}`, { stdio: "ignore" });
1045
- } catch {
1046
- console.log(chalk.gray(` Visit: ${dockerUrl}`));
1075
+ execSyncInstall(installCmd, { stdio: "inherit", timeout: 3e5 });
1076
+ installSpinner.succeed("Docker installed");
1077
+ console.log("");
1078
+ if (platform === "linux") {
1079
+ try {
1080
+ execSyncInstall("sudo systemctl start docker", { stdio: "ignore" });
1081
+ execSyncInstall("sudo systemctl enable docker", { stdio: "ignore" });
1082
+ execSyncInstall(`sudo usermod -aG docker ${process.env.USER || "root"}`, { stdio: "ignore" });
1083
+ } catch {
1084
+ }
1085
+ }
1086
+ const readySpinner = ora("Waiting for Docker to start...").start();
1087
+ let dockerReady = false;
1088
+ for (let i = 0; i < 30; i++) {
1089
+ try {
1090
+ execSyncInstall("docker info", { stdio: "ignore", timeout: 5e3 });
1091
+ dockerReady = true;
1092
+ break;
1093
+ } catch {
1094
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
1095
+ }
1096
+ }
1097
+ if (dockerReady) {
1098
+ readySpinner.succeed("Docker is ready");
1099
+ sandboxMode = "docker";
1100
+ } else {
1101
+ readySpinner.warn("Docker installed but not running yet");
1102
+ console.log(chalk.gray(" Start Docker Desktop manually, then run `fishi upgrade` to switch to Docker mode."));
1103
+ console.log(chalk.gray(" Continuing with process-level sandbox for now."));
1104
+ }
1105
+ console.log("");
1106
+ } catch (err) {
1107
+ installSpinner.fail("Docker installation failed");
1108
+ console.log(chalk.gray(" Install manually: https://docs.docker.com/get-docker/"));
1109
+ console.log(chalk.gray(" Continuing with process-level sandbox."));
1110
+ console.log("");
1047
1111
  }
1048
- return;
1112
+ } else {
1113
+ console.log(chalk.gray(" Continuing with process-level sandbox (limited isolation)."));
1114
+ console.log("");
1049
1115
  }
1050
- console.log(chalk.gray(" Continuing with process-level sandbox (limited isolation)."));
1051
- console.log("");
1052
1116
  }
1053
1117
  }
1054
1118
  let brownfieldAnalysis = null;
@@ -2528,8 +2592,17 @@ function fixDenyRules(settings) {
2528
2592
  settings.permissions.deny = settings.permissions.deny.filter((rule) => {
2529
2593
  if (rule.includes(":(){ :|:& };:")) return false;
2530
2594
  if (/^Bash\(\s*\)$/.test(rule)) return false;
2595
+ if (rule === "Bash(npm *)" || rule === "Bash(yarn *)") return false;
2531
2596
  return true;
2532
2597
  });
2598
+ if (settings.permissions?.allow) {
2599
+ if (!settings.permissions.allow.includes("Bash(npm *)")) {
2600
+ settings.permissions.allow.push("Bash(npm *)");
2601
+ }
2602
+ if (!settings.permissions.allow.includes("Bash(yarn *)")) {
2603
+ settings.permissions.allow.push("Bash(yarn *)");
2604
+ }
2605
+ }
2533
2606
  return settings.permissions.deny.length !== original;
2534
2607
  }
2535
2608
  async function upgradeCommand() {
@@ -2637,7 +2710,7 @@ async function upgradeCommand() {
2637
2710
  var program = new Command();
2638
2711
  program.name("fishi").description(
2639
2712
  chalk15.cyan("\u{1F41F} FISHI") + " \u2014 AI-Powered Software Delivery Pipeline\n Autonomous AI development with human governance"
2640
- ).version("0.14.5");
2713
+ ).version("0.14.7");
2641
2714
  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(
2642
2715
  "-c, --cost-mode <mode>",
2643
2716
  "Cost mode: performance | balanced | economy",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlucent/fishi",
3
- "version": "0.14.6",
3
+ "version": "0.14.8",
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",