@qlucent/fishi 0.14.4 → 0.14.6

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 +69 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1017,8 +1017,37 @@ async function initCommand(description, options) {
1017
1017
  }]);
1018
1018
  sandboxMode = useSandbox ? "docker" : "process";
1019
1019
  } else {
1020
- console.log(chalk.yellow(" Docker not found. Using process-level sandbox (limited isolation)."));
1021
- console.log(chalk.gray(" Install Docker for full agent isolation: https://docs.docker.com/get-docker/"));
1020
+ console.log(chalk.yellow(" Docker not found."));
1021
+ console.log(chalk.gray(" Docker provides full agent isolation (recommended for security)."));
1022
+ console.log("");
1023
+ const { installDocker } = await inquirer.prompt([{
1024
+ type: "list",
1025
+ name: "installDocker",
1026
+ message: "How would you like to proceed?",
1027
+ choices: [
1028
+ { name: "Install Docker (opens install page \u2014 recommended)", value: "install" },
1029
+ { name: "Continue without Docker (process-level isolation only)", value: "skip" }
1030
+ ],
1031
+ default: "install"
1032
+ }]);
1033
+ if (installDocker === "install") {
1034
+ const dockerUrl = "https://docs.docker.com/get-docker/";
1035
+ console.log("");
1036
+ console.log(chalk.cyan(` Opening: ${dockerUrl}`));
1037
+ console.log(chalk.gray(" Install Docker, then run `fishi init` again."));
1038
+ console.log("");
1039
+ 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}`));
1047
+ }
1048
+ return;
1049
+ }
1050
+ console.log(chalk.gray(" Continuing with process-level sandbox (limited isolation)."));
1022
1051
  console.log("");
1023
1052
  }
1024
1053
  }
@@ -2468,14 +2497,41 @@ import ora4 from "ora";
2468
2497
  import path16 from "path";
2469
2498
  import fs16 from "fs";
2470
2499
  import {
2471
- getSettingsJsonTemplate,
2472
2500
  getSoulMdTemplate,
2473
2501
  getAgentsMdTemplate,
2474
2502
  getSandboxPolicyTemplate,
2475
2503
  getMonitorEmitterScript,
2476
2504
  getFileLockHookScript
2477
2505
  } from "@qlucent/fishi-core";
2478
- var CURRENT_VERSION = "0.14.3";
2506
+ var CURRENT_VERSION = "0.14.4";
2507
+ function fixHooksFormat(settings) {
2508
+ if (!settings.hooks) return false;
2509
+ let fixed = false;
2510
+ for (const [event, entries] of Object.entries(settings.hooks)) {
2511
+ if (!Array.isArray(entries)) continue;
2512
+ for (let i = 0; i < entries.length; i++) {
2513
+ const entry = entries[i];
2514
+ if (entry.command && !entry.hooks) {
2515
+ entries[i] = {
2516
+ matcher: entry.matcher || "",
2517
+ hooks: [{ type: "command", command: entry.command }]
2518
+ };
2519
+ fixed = true;
2520
+ }
2521
+ }
2522
+ }
2523
+ return fixed;
2524
+ }
2525
+ function fixDenyRules(settings) {
2526
+ if (!settings.permissions?.deny) return false;
2527
+ const original = settings.permissions.deny.length;
2528
+ settings.permissions.deny = settings.permissions.deny.filter((rule) => {
2529
+ if (rule.includes(":(){ :|:& };:")) return false;
2530
+ if (/^Bash\(\s*\)$/.test(rule)) return false;
2531
+ return true;
2532
+ });
2533
+ return settings.permissions.deny.length !== original;
2534
+ }
2479
2535
  async function upgradeCommand() {
2480
2536
  const targetDir = process.cwd();
2481
2537
  console.log("");
@@ -2493,30 +2549,18 @@ async function upgradeCommand() {
2493
2549
  if (fs16.existsSync(settingsPath)) {
2494
2550
  try {
2495
2551
  const existing = JSON.parse(fs16.readFileSync(settingsPath, "utf-8"));
2496
- let needsFix = false;
2497
- if (existing.hooks) {
2498
- for (const [event, entries] of Object.entries(existing.hooks)) {
2499
- if (Array.isArray(entries)) {
2500
- for (const entry of entries) {
2501
- if (entry.command && !entry.hooks) {
2502
- needsFix = true;
2503
- break;
2504
- }
2505
- }
2506
- }
2507
- if (needsFix) break;
2508
- }
2509
- }
2510
- if (needsFix) {
2552
+ const hooksFixed = fixHooksFormat(existing);
2553
+ const denyFixed = fixDenyRules(existing);
2554
+ if (hooksFixed || denyFixed) {
2511
2555
  const backupDir = path16.join(targetDir, ".fishi", "backup", "upgrade-" + (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\.\d+Z$/, ""));
2512
2556
  fs16.mkdirSync(backupDir, { recursive: true });
2513
2557
  fs16.copyFileSync(settingsPath, path16.join(backupDir, "settings.json"));
2514
- fs16.writeFileSync(settingsPath, getSettingsJsonTemplate(), "utf-8");
2515
- updated.push(".claude/settings.json (hooks format fixed)");
2558
+ fs16.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
2559
+ if (hooksFixed) updated.push(".claude/settings.json (hooks format: matcher+command \u2192 matcher+hooks array)");
2560
+ if (denyFixed) updated.push(".claude/settings.json (removed invalid deny rules)");
2516
2561
  }
2517
2562
  } catch {
2518
- fs16.writeFileSync(settingsPath, getSettingsJsonTemplate(), "utf-8");
2519
- updated.push(".claude/settings.json (replaced \u2014 was corrupted)");
2563
+ updated.push(".claude/settings.json (could not parse \u2014 please fix manually)");
2520
2564
  }
2521
2565
  }
2522
2566
  const soulPath = path16.join(targetDir, "SOUL.md");
@@ -2577,7 +2621,7 @@ async function upgradeCommand() {
2577
2621
  console.log("");
2578
2622
  }
2579
2623
  if (created.length > 0) {
2580
- console.log(chalk14.white.bold(" Created (new in v0.14):"));
2624
+ console.log(chalk14.white.bold(" Created (new in latest):"));
2581
2625
  for (const c of created) console.log(chalk14.cyan(` ${c}`));
2582
2626
  console.log("");
2583
2627
  }
@@ -2593,7 +2637,7 @@ async function upgradeCommand() {
2593
2637
  var program = new Command();
2594
2638
  program.name("fishi").description(
2595
2639
  chalk15.cyan("\u{1F41F} FISHI") + " \u2014 AI-Powered Software Delivery Pipeline\n Autonomous AI development with human governance"
2596
- ).version("0.14.3");
2640
+ ).version("0.14.5");
2597
2641
  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(
2598
2642
  "-c, --cost-mode <mode>",
2599
2643
  "Cost mode: performance | balanced | economy",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlucent/fishi",
3
- "version": "0.14.4",
3
+ "version": "0.14.6",
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",