@qlucent/fishi 0.6.0 → 0.7.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 +77 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk8 from "chalk";
5
+ import chalk9 from "chalk";
6
6
 
7
7
  // src/commands/init.ts
8
8
  import chalk from "chalk";
@@ -10,7 +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
+ import { detectConflicts, createBackup, detectDocker } from "@qlucent/fishi-core";
14
14
 
15
15
  // src/analyzers/detector.ts
16
16
  import fs from "fs";
@@ -1005,6 +1005,23 @@ async function initCommand(description, options) {
1005
1005
  } else {
1006
1006
  initOptions = await runWizard(options);
1007
1007
  }
1008
+ const dockerAvailable = detectDocker();
1009
+ let sandboxMode = "process";
1010
+ if (options.interactive !== false) {
1011
+ if (dockerAvailable) {
1012
+ const { useSandbox } = await inquirer.prompt([{
1013
+ type: "confirm",
1014
+ name: "useSandbox",
1015
+ message: "Docker detected. Use Docker sandbox for agent isolation? (Recommended)",
1016
+ default: true
1017
+ }]);
1018
+ sandboxMode = useSandbox ? "docker" : "process";
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/"));
1022
+ console.log("");
1023
+ }
1024
+ }
1008
1025
  let brownfieldAnalysis = null;
1009
1026
  if (detection.type === "brownfield" || detection.type === "hybrid") {
1010
1027
  console.log("");
@@ -1148,6 +1165,21 @@ async function initCommand(description, options) {
1148
1165
  const report = generateBrownfieldReport(brownfieldAnalysis);
1149
1166
  fs3.writeFileSync(reportPath, report, "utf-8");
1150
1167
  }
1168
+ const sandboxYaml = `
1169
+ sandbox:
1170
+ mode: ${sandboxMode}
1171
+ docker_available: ${dockerAvailable}
1172
+ `;
1173
+ const fishiYamlPath = path3.join(targetDir, ".fishi", "fishi.yaml");
1174
+ if (fs3.existsSync(fishiYamlPath)) {
1175
+ fs3.appendFileSync(fishiYamlPath, sandboxYaml, "utf-8");
1176
+ }
1177
+ const { getSandboxPolicyTemplate, getDockerfileTemplate } = await import("@qlucent/fishi-core");
1178
+ fs3.writeFileSync(path3.join(targetDir, ".fishi", "sandbox-policy.yaml"), getSandboxPolicyTemplate(), "utf-8");
1179
+ if (sandboxMode === "docker") {
1180
+ fs3.mkdirSync(path3.join(targetDir, ".fishi", "docker"), { recursive: true });
1181
+ fs3.writeFileSync(path3.join(targetDir, ".fishi", "docker", "Dockerfile"), getDockerfileTemplate(), "utf-8");
1182
+ }
1151
1183
  scaffoldSpinner.succeed("FISHI framework scaffolded successfully!");
1152
1184
  console.log("");
1153
1185
  console.log(chalk.bold(" Created:"));
@@ -1158,6 +1190,7 @@ async function initCommand(description, options) {
1158
1190
  console.log(chalk.gray(` \u{1F4C4} .claude/CLAUDE.md \u2014 Project instructions`));
1159
1191
  console.log(chalk.gray(` \u{1F4C4} .claude/settings.json \u2014 Hooks & permissions`));
1160
1192
  console.log(chalk.gray(` \u{1F4C4} .mcp.json \u2014 MCP server config`));
1193
+ console.log(chalk.gray(` \u{1F512} Sandbox: ${sandboxMode} mode${sandboxMode === "docker" ? " (full isolation)" : " (limited isolation)"}`));
1161
1194
  if (brownfieldAnalysis) {
1162
1195
  console.log(chalk.gray(` \u{1F4C4} .fishi/memory/brownfield-analysis.md \u2014 Codebase analysis report`));
1163
1196
  console.log("");
@@ -1898,11 +1931,50 @@ async function dashboardCommand(options) {
1898
1931
  });
1899
1932
  }
1900
1933
 
1934
+ // src/commands/sandbox.ts
1935
+ import chalk8 from "chalk";
1936
+ import fs10 from "fs";
1937
+ import path10 from "path";
1938
+ import { detectDocker as detectDocker2, readSandboxConfig, readSandboxPolicy } from "@qlucent/fishi-core";
1939
+ async function sandboxCommand(action) {
1940
+ const targetDir = process.cwd();
1941
+ if (!fs10.existsSync(path10.join(targetDir, ".fishi"))) {
1942
+ console.log(chalk8.yellow(" No FISHI project found. Run `fishi init` first."));
1943
+ return;
1944
+ }
1945
+ if (action === "status") {
1946
+ const config = readSandboxConfig(targetDir);
1947
+ const dockerNow = detectDocker2();
1948
+ console.log("");
1949
+ console.log(chalk8.cyan.bold(" FISHI Sandbox Status"));
1950
+ console.log("");
1951
+ console.log(chalk8.white(" Mode: ") + (config.mode === "docker" ? chalk8.green("Docker") : chalk8.yellow("Process")));
1952
+ console.log(chalk8.white(" Docker available: ") + (dockerNow ? chalk8.green("yes") : chalk8.red("no")));
1953
+ if (config.mode === "docker" && !dockerNow) {
1954
+ console.log(chalk8.red(" Warning: Docker mode configured but Docker not available!"));
1955
+ }
1956
+ console.log("");
1957
+ const policy = readSandboxPolicy(targetDir);
1958
+ console.log(chalk8.white.bold(" Policy"));
1959
+ console.log(chalk8.gray(` Timeout: ${policy.timeout}s`));
1960
+ console.log(chalk8.gray(` Memory limit: ${policy.memory}`));
1961
+ console.log(chalk8.gray(` CPU limit: ${policy.cpus}`));
1962
+ console.log(chalk8.gray(` Network allow: ${policy.networkAllow.join(", ")}`));
1963
+ console.log(chalk8.gray(` Env passthrough: ${policy.envPassthrough.length > 0 ? policy.envPassthrough.join(", ") : "(none)"}`));
1964
+ console.log("");
1965
+ } else if (action === "policy") {
1966
+ const policy = readSandboxPolicy(targetDir);
1967
+ console.log(JSON.stringify(policy, null, 2));
1968
+ } else {
1969
+ console.log(chalk8.yellow(` Unknown action: ${action}. Use: status, policy`));
1970
+ }
1971
+ }
1972
+
1901
1973
  // src/index.ts
1902
1974
  var program = new Command();
1903
1975
  program.name("fishi").description(
1904
- chalk8.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
1905
- ).version("0.6.0");
1976
+ chalk9.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
1977
+ ).version("0.7.0");
1906
1978
  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(
1907
1979
  "-c, --cost-mode <mode>",
1908
1980
  "Cost mode: performance | balanced | economy",
@@ -1914,4 +1986,5 @@ program.command("reset").description("Rollback to a previous checkpoint").argume
1914
1986
  program.command("validate").description("Validate scaffold integrity \u2014 checks files, frontmatter, cross-references, pipeline, and permissions").action(validateCommand);
1915
1987
  program.command("monitor").description("Agent observability \u2014 TUI dashboard showing agent activity, tokens, gates").option("-w, --watch", "Watch mode \u2014 auto-refresh on changes").action(monitorCommand);
1916
1988
  program.command("dashboard").description("Agent observability \u2014 web dashboard at http://localhost:4269").option("-p, --port <port>", "Port number", "4269").action(dashboardCommand);
1989
+ program.command("sandbox").description("Sandbox status and policy management").argument("<action>", "Action: status | policy").action(sandboxCommand);
1917
1990
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlucent/fishi",
3
- "version": "0.6.0",
3
+ "version": "0.7.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",