@qlucent/fishi 0.11.0 → 0.14.1

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 +192 -3
  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 chalk12 from "chalk";
5
+ import chalk14 from "chalk";
6
6
 
7
7
  // src/commands/init.ts
8
8
  import chalk from "chalk";
@@ -2275,11 +2275,198 @@ async function designCommand(action, options) {
2275
2275
  }
2276
2276
  }
2277
2277
 
2278
+ // src/commands/security.ts
2279
+ import chalk12 from "chalk";
2280
+ import ora3 from "ora";
2281
+ import fs14 from "fs";
2282
+ import path14 from "path";
2283
+ import { runSecurityScan, generateSecurityReport, getScanRules } from "@qlucent/fishi-core";
2284
+ async function securityCommand(action, options) {
2285
+ const targetDir = process.cwd();
2286
+ if (action === "scan") {
2287
+ console.log("");
2288
+ console.log(chalk12.cyan.bold(" FISHI Security Scanner"));
2289
+ console.log(chalk12.gray(" Native SAST + OWASP vulnerability detection"));
2290
+ console.log("");
2291
+ const spinner = ora3("Scanning for vulnerabilities...").start();
2292
+ const report = runSecurityScan(targetDir);
2293
+ spinner.succeed(`Scanned ${report.summary.filesScanned} files`);
2294
+ console.log("");
2295
+ if (options.json) {
2296
+ console.log(JSON.stringify(report, null, 2));
2297
+ } else {
2298
+ const severityOrder = ["critical", "high", "medium", "low", "info"];
2299
+ const severityColors = {
2300
+ critical: chalk12.red.bold,
2301
+ high: chalk12.red,
2302
+ medium: chalk12.yellow,
2303
+ low: chalk12.blue,
2304
+ info: chalk12.gray
2305
+ };
2306
+ for (const sev of severityOrder) {
2307
+ const sevFindings = report.findings.filter((f) => f.severity === sev);
2308
+ if (sevFindings.length === 0) continue;
2309
+ console.log(severityColors[sev](` ${sev.toUpperCase()} (${sevFindings.length})`));
2310
+ for (const f of sevFindings) {
2311
+ console.log(chalk12.gray(` ${f.file}:${f.line}`));
2312
+ console.log(` ${f.message}`);
2313
+ if (f.cwe) console.log(chalk12.gray(` ${f.cwe}`));
2314
+ console.log(chalk12.green(` Fix: ${f.fix}`));
2315
+ console.log("");
2316
+ }
2317
+ }
2318
+ console.log(chalk12.white.bold(" Summary"));
2319
+ if (report.summary.critical > 0) console.log(chalk12.red(` Critical: ${report.summary.critical}`));
2320
+ if (report.summary.high > 0) console.log(chalk12.red(` High: ${report.summary.high}`));
2321
+ if (report.summary.medium > 0) console.log(chalk12.yellow(` Medium: ${report.summary.medium}`));
2322
+ if (report.summary.low > 0) console.log(chalk12.blue(` Low: ${report.summary.low}`));
2323
+ if (report.summary.info > 0) console.log(chalk12.gray(` Info: ${report.summary.info}`));
2324
+ console.log(` Total: ${report.summary.total}`);
2325
+ console.log(` Status: ${report.summary.passed ? chalk12.green("PASSED") : chalk12.red("FAILED")}`);
2326
+ console.log("");
2327
+ }
2328
+ const outputPath = options.output || (fs14.existsSync(path14.join(targetDir, ".fishi")) ? path14.join(targetDir, ".fishi", "security-report.md") : null);
2329
+ if (outputPath) {
2330
+ const dir = path14.dirname(outputPath);
2331
+ if (!fs14.existsSync(dir)) fs14.mkdirSync(dir, { recursive: true });
2332
+ fs14.writeFileSync(outputPath, generateSecurityReport(report), "utf-8");
2333
+ console.log(chalk12.green(` Report saved to ${path14.relative(targetDir, outputPath)}`));
2334
+ console.log("");
2335
+ }
2336
+ if (!report.summary.passed) process.exit(1);
2337
+ } else if (action === "rules") {
2338
+ const rules = getScanRules();
2339
+ console.log("");
2340
+ console.log(chalk12.cyan.bold(" FISHI Security Scanner \u2014 Rules"));
2341
+ console.log(chalk12.gray(` ${rules.length} rules active`));
2342
+ console.log("");
2343
+ const byCategory = {};
2344
+ for (const r of rules) {
2345
+ if (!byCategory[r.category]) byCategory[r.category] = [];
2346
+ byCategory[r.category].push(r);
2347
+ }
2348
+ for (const [cat, catRules] of Object.entries(byCategory)) {
2349
+ console.log(chalk12.white.bold(` ${cat}`));
2350
+ for (const r of catRules) {
2351
+ const sevColor = r.severity === "critical" ? chalk12.red : r.severity === "high" ? chalk12.red : r.severity === "medium" ? chalk12.yellow : chalk12.blue;
2352
+ console.log(` ${sevColor(r.severity.padEnd(8))} ${r.id}${r.cwe ? chalk12.gray(` (${r.cwe})`) : ""}`);
2353
+ console.log(chalk12.gray(` ${r.message}`));
2354
+ }
2355
+ console.log("");
2356
+ }
2357
+ } else {
2358
+ console.log(chalk12.yellow(` Unknown action: ${action}. Use: scan, rules`));
2359
+ }
2360
+ }
2361
+
2362
+ // src/commands/patterns.ts
2363
+ import chalk13 from "chalk";
2364
+ import fs15 from "fs";
2365
+ import path15 from "path";
2366
+ import {
2367
+ getPatternCategories,
2368
+ getPattern,
2369
+ searchPatterns,
2370
+ saveSelectedPatterns,
2371
+ readSelectedPatterns,
2372
+ generatePatternGuide
2373
+ } from "@qlucent/fishi-core";
2374
+ async function patternsCommand(action, options) {
2375
+ const targetDir = process.cwd();
2376
+ if (action === "list") {
2377
+ console.log("");
2378
+ console.log(chalk13.cyan.bold(" FISHI Pattern Marketplace"));
2379
+ console.log(chalk13.gray(" Pre-built architectural blueprints for common integrations"));
2380
+ console.log("");
2381
+ const categories = getPatternCategories();
2382
+ for (const cat of categories) {
2383
+ console.log(chalk13.white.bold(` ${cat.name}`));
2384
+ console.log(chalk13.gray(` ${cat.description}`));
2385
+ for (const p of cat.patterns) {
2386
+ console.log(chalk13.gray(` - ${chalk13.cyan(p.id)} \u2014 ${p.name} (${p.tools.join(", ")})`));
2387
+ }
2388
+ console.log("");
2389
+ }
2390
+ const total = categories.reduce((s, c) => s + c.patterns.length, 0);
2391
+ console.log(chalk13.gray(` ${categories.length} categories, ${total} patterns available`));
2392
+ console.log("");
2393
+ } else if (action === "search") {
2394
+ if (!options.query) {
2395
+ console.log(chalk13.yellow(' Usage: fishi patterns search --query "stripe"'));
2396
+ return;
2397
+ }
2398
+ const results = searchPatterns(options.query);
2399
+ console.log("");
2400
+ console.log(chalk13.cyan.bold(` Search: "${options.query}" \u2014 ${results.length} results`));
2401
+ console.log("");
2402
+ for (const p of results) {
2403
+ console.log(` ${chalk13.cyan(p.id)} \u2014 ${p.name} [${p.category}]`);
2404
+ console.log(chalk13.gray(` ${p.description}`));
2405
+ console.log(chalk13.gray(` Tools: ${p.tools.join(", ")}`));
2406
+ console.log("");
2407
+ }
2408
+ } else if (action === "info") {
2409
+ if (!options.query) {
2410
+ console.log(chalk13.yellow(' Usage: fishi patterns info --query "stripe"'));
2411
+ return;
2412
+ }
2413
+ const pattern = getPattern(options.query);
2414
+ if (!pattern) {
2415
+ console.log(chalk13.yellow(` Pattern "${options.query}" not found. Run: fishi patterns list`));
2416
+ return;
2417
+ }
2418
+ console.log("");
2419
+ console.log(chalk13.cyan.bold(` ${pattern.name}`));
2420
+ console.log(chalk13.gray(` Category: ${pattern.category}`));
2421
+ console.log(chalk13.gray(` Tools: ${pattern.tools.join(", ")}`));
2422
+ console.log("");
2423
+ console.log(pattern.guide);
2424
+ } else if (action === "select") {
2425
+ if (!options.query) {
2426
+ console.log(chalk13.yellow(' Usage: fishi patterns select --query "stripe,auth0,sendgrid"'));
2427
+ return;
2428
+ }
2429
+ const ids = options.query.split(",").map((s) => s.trim());
2430
+ const valid = [];
2431
+ const invalid = [];
2432
+ for (const id of ids) {
2433
+ if (getPattern(id)) valid.push(id);
2434
+ else invalid.push(id);
2435
+ }
2436
+ if (invalid.length > 0) {
2437
+ console.log(chalk13.yellow(` Unknown patterns: ${invalid.join(", ")}`));
2438
+ }
2439
+ if (valid.length > 0) {
2440
+ saveSelectedPatterns(targetDir, valid);
2441
+ const guide = generatePatternGuide(valid);
2442
+ const guidePath = path15.join(targetDir, ".fishi", "patterns-guide.md");
2443
+ fs15.writeFileSync(guidePath, guide, "utf-8");
2444
+ console.log(chalk13.green(` Selected ${valid.length} patterns: ${valid.join(", ")}`));
2445
+ console.log(chalk13.green(` Guide saved to .fishi/patterns-guide.md`));
2446
+ }
2447
+ } else if (action === "selected") {
2448
+ const selected = readSelectedPatterns(targetDir);
2449
+ if (selected.length === 0) {
2450
+ console.log(chalk13.gray(' No patterns selected. Run: fishi patterns select --query "stripe,auth0"'));
2451
+ return;
2452
+ }
2453
+ console.log("");
2454
+ console.log(chalk13.cyan.bold(" Selected Patterns"));
2455
+ for (const id of selected) {
2456
+ const p = getPattern(id);
2457
+ if (p) console.log(` ${chalk13.cyan(p.id)} \u2014 ${p.name} (${p.tools.join(", ")})`);
2458
+ }
2459
+ console.log("");
2460
+ } else {
2461
+ console.log(chalk13.yellow(` Unknown action: ${action}. Use: list, search, info, select, selected`));
2462
+ }
2463
+ }
2464
+
2278
2465
  // src/index.ts
2279
2466
  var program = new Command();
2280
2467
  program.name("fishi").description(
2281
- chalk12.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
2282
- ).version("0.11.0");
2468
+ chalk14.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
2469
+ ).version("0.14.1");
2283
2470
  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(
2284
2471
  "-c, --cost-mode <mode>",
2285
2472
  "Cost mode: performance | balanced | economy",
@@ -2295,4 +2482,6 @@ program.command("sandbox").description("Sandbox status and policy management").a
2295
2482
  program.command("quickstart").description("Vibe mode \u2014 skip gates, scaffold + start dev server immediately").argument("[description]", "What are you building?").option("-l, --language <lang>", "Primary language").option("-f, --framework <framework>", "Framework").option("-c, --cost-mode <mode>", "Cost mode", "balanced").option("--dev-cmd <cmd>", "Custom dev server command").option("--port <port>", "Dev server port").action(quickstartCommand);
2296
2483
  program.command("preview").description("Start live preview dev server").option("--dev-cmd <cmd>", "Custom dev server command").option("--port <port>", "Dev server port").action(previewCommand);
2297
2484
  program.command("design").description("Design system \u2014 detect tokens, init design system, validate with Brand Guardian").argument("<action>", "Action: detect | init | validate").option("-o, --output <path>", "Output path for design config").action(designCommand);
2485
+ program.command("security").description("Security scanner \u2014 native SAST + OWASP vulnerability detection").argument("<action>", "Action: scan | rules").option("-o, --output <path>", "Save report to file").option("--json", "Output as JSON").action(securityCommand);
2486
+ program.command("patterns").description("Pattern marketplace \u2014 browse, search, select integration blueprints").argument("<action>", "Action: list | search | info | select | selected").option("-q, --query <query>", "Search query or pattern ID(s)").option("-c, --category <category>", "Filter by category").option("-o, --output <path>", "Save guide to file").action(patternsCommand);
2298
2487
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlucent/fishi",
3
- "version": "0.11.0",
3
+ "version": "0.14.1",
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",