@qlucent/fishi 0.7.0 → 0.9.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 +292 -3
- 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
|
|
5
|
+
import chalk12 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/commands/init.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -1970,11 +1970,297 @@ async function sandboxCommand(action) {
|
|
|
1970
1970
|
}
|
|
1971
1971
|
}
|
|
1972
1972
|
|
|
1973
|
+
// src/commands/quickstart.ts
|
|
1974
|
+
import chalk9 from "chalk";
|
|
1975
|
+
import ora2 from "ora";
|
|
1976
|
+
import path11 from "path";
|
|
1977
|
+
import fs11 from "fs";
|
|
1978
|
+
import { detectDevServer, startDevServer, getVibeModeConfig } from "@qlucent/fishi-core";
|
|
1979
|
+
import { detectConflicts as detectConflicts2, createBackup as createBackup2 } from "@qlucent/fishi-core";
|
|
1980
|
+
import { detectDocker as detectDocker3 } from "@qlucent/fishi-core";
|
|
1981
|
+
async function quickstartCommand(description, options) {
|
|
1982
|
+
const targetDir = process.cwd();
|
|
1983
|
+
const projectName = path11.basename(targetDir);
|
|
1984
|
+
console.log("");
|
|
1985
|
+
console.log(chalk9.cyan.bold(" FISHI \u2014 Vibe Mode"));
|
|
1986
|
+
console.log(chalk9.gray(" Skip the ceremony, start shipping"));
|
|
1987
|
+
console.log("");
|
|
1988
|
+
if (fs11.existsSync(path11.join(targetDir, ".fishi"))) {
|
|
1989
|
+
console.log(chalk9.yellow(" FISHI already initialized. Starting dev server only..."));
|
|
1990
|
+
const serverConfig2 = detectDevServer(targetDir, options.devCmd);
|
|
1991
|
+
if (serverConfig2.detected) {
|
|
1992
|
+
console.log(chalk9.green(` Starting ${serverConfig2.framework} dev server on :${serverConfig2.port}...`));
|
|
1993
|
+
const child = startDevServer(targetDir, serverConfig2);
|
|
1994
|
+
child.stdout?.on("data", (d) => process.stdout.write(d));
|
|
1995
|
+
child.stderr?.on("data", (d) => process.stderr.write(d));
|
|
1996
|
+
child.on("close", (code) => process.exit(code || 0));
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
console.log(chalk9.yellow(" Could not detect dev server. Use --dev-cmd to specify."));
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
const spinner = ora2("Analyzing project...").start();
|
|
2003
|
+
const detection = await detectProjectType(targetDir);
|
|
2004
|
+
spinner.succeed(`Project type: ${chalk9.bold(detection.type)}`);
|
|
2005
|
+
let brownfieldAnalysis = null;
|
|
2006
|
+
if (detection.type === "brownfield" || detection.type === "hybrid") {
|
|
2007
|
+
const analysisSpinner = ora2("Running brownfield analysis...").start();
|
|
2008
|
+
brownfieldAnalysis = await runBrownfieldAnalysis(targetDir);
|
|
2009
|
+
analysisSpinner.succeed("Brownfield analysis complete");
|
|
2010
|
+
}
|
|
2011
|
+
const conflictResult = detectConflicts2(targetDir);
|
|
2012
|
+
let resolutions;
|
|
2013
|
+
if (conflictResult.hasConflicts) {
|
|
2014
|
+
console.log(chalk9.yellow(` Auto-merging ${conflictResult.totalConflicts} conflicting files (vibe mode)...`));
|
|
2015
|
+
const allPaths = conflictResult.categories.flatMap((c) => c.conflicts.map((f) => f.path));
|
|
2016
|
+
await createBackup2(targetDir, allPaths);
|
|
2017
|
+
resolutions = { categories: {}, files: {} };
|
|
2018
|
+
for (const cat of conflictResult.categories) {
|
|
2019
|
+
if (cat.conflicts.length > 0) {
|
|
2020
|
+
const noMerge = ["agents", "skills", "commands"];
|
|
2021
|
+
resolutions.categories[cat.name] = noMerge.includes(cat.name) ? "skip" : "merge";
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
const initOptions = {
|
|
2026
|
+
description: description || `${projectName} project`,
|
|
2027
|
+
interactive: false,
|
|
2028
|
+
costMode: options.costMode || "balanced",
|
|
2029
|
+
language: options.language || brownfieldAnalysis?.language,
|
|
2030
|
+
framework: options.framework || brownfieldAnalysis?.framework
|
|
2031
|
+
};
|
|
2032
|
+
let brownfieldData = void 0;
|
|
2033
|
+
if (brownfieldAnalysis) {
|
|
2034
|
+
brownfieldData = {
|
|
2035
|
+
language: brownfieldAnalysis.language,
|
|
2036
|
+
framework: brownfieldAnalysis.framework,
|
|
2037
|
+
testFramework: brownfieldAnalysis.testFramework,
|
|
2038
|
+
packageManager: brownfieldAnalysis.packageManager,
|
|
2039
|
+
linter: brownfieldAnalysis.linter,
|
|
2040
|
+
formatter: brownfieldAnalysis.formatter,
|
|
2041
|
+
cssFramework: brownfieldAnalysis.cssFramework,
|
|
2042
|
+
orm: brownfieldAnalysis.orm,
|
|
2043
|
+
database: brownfieldAnalysis.database,
|
|
2044
|
+
authProvider: brownfieldAnalysis.authProvider,
|
|
2045
|
+
apiStyle: brownfieldAnalysis.apiStyle,
|
|
2046
|
+
monorepo: brownfieldAnalysis.monorepo,
|
|
2047
|
+
conventions: brownfieldAnalysis.conventions,
|
|
2048
|
+
codePatterns: brownfieldAnalysis.codePatterns,
|
|
2049
|
+
fileStats: {
|
|
2050
|
+
totalFiles: brownfieldAnalysis.fileStats.totalFiles,
|
|
2051
|
+
codeFiles: brownfieldAnalysis.fileStats.codeFiles,
|
|
2052
|
+
testFiles: brownfieldAnalysis.fileStats.testFiles
|
|
2053
|
+
}
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
const scaffoldSpinner = ora2("Scaffolding FISHI...").start();
|
|
2057
|
+
try {
|
|
2058
|
+
const result = await scaffold(targetDir, {
|
|
2059
|
+
...initOptions,
|
|
2060
|
+
projectName,
|
|
2061
|
+
projectType: detection.type,
|
|
2062
|
+
brownfieldAnalysis: brownfieldData,
|
|
2063
|
+
resolutions,
|
|
2064
|
+
docsReadmeExists: conflictResult.docsReadmeExists,
|
|
2065
|
+
rootClaudeMdExists: conflictResult.rootClaudeMdExists
|
|
2066
|
+
});
|
|
2067
|
+
scaffoldSpinner.succeed(`Scaffolded: ${result.agentCount} agents, ${result.skillCount} skills, ${result.commandCount} commands`);
|
|
2068
|
+
} catch (error) {
|
|
2069
|
+
scaffoldSpinner.fail("Scaffolding failed");
|
|
2070
|
+
console.error(chalk9.red(` Error: ${error instanceof Error ? error.message : error}`));
|
|
2071
|
+
process.exit(1);
|
|
2072
|
+
}
|
|
2073
|
+
const fishiYamlPath = path11.join(targetDir, ".fishi", "fishi.yaml");
|
|
2074
|
+
if (fs11.existsSync(fishiYamlPath)) {
|
|
2075
|
+
fs11.appendFileSync(fishiYamlPath, getVibeModeConfig(true), "utf-8");
|
|
2076
|
+
}
|
|
2077
|
+
const dockerAvailable = detectDocker3();
|
|
2078
|
+
const sandboxMode = dockerAvailable ? "docker" : "process";
|
|
2079
|
+
fs11.appendFileSync(fishiYamlPath, `
|
|
2080
|
+
sandbox:
|
|
2081
|
+
mode: ${sandboxMode}
|
|
2082
|
+
docker_available: ${dockerAvailable}
|
|
2083
|
+
`, "utf-8");
|
|
2084
|
+
const projectYamlPath = path11.join(targetDir, ".fishi", "state", "project.yaml");
|
|
2085
|
+
if (fs11.existsSync(projectYamlPath)) {
|
|
2086
|
+
let content = fs11.readFileSync(projectYamlPath, "utf-8");
|
|
2087
|
+
content = content.replace(/^phase:\s*.+$/m, "phase: development");
|
|
2088
|
+
fs11.writeFileSync(projectYamlPath, content, "utf-8");
|
|
2089
|
+
}
|
|
2090
|
+
const serverConfig = detectDevServer(targetDir, options.devCmd);
|
|
2091
|
+
console.log("");
|
|
2092
|
+
console.log(chalk9.cyan.bold(" Vibe Mode Active"));
|
|
2093
|
+
console.log(chalk9.gray(` Phase: ${chalk9.green("development")} (gates auto-skipped)`));
|
|
2094
|
+
console.log(chalk9.gray(` Sandbox: ${sandboxMode}`));
|
|
2095
|
+
if (serverConfig.detected) {
|
|
2096
|
+
const port = options.port ? parseInt(options.port, 10) : serverConfig.port;
|
|
2097
|
+
console.log(chalk9.gray(` Dev server: ${serverConfig.framework} on :${port}`));
|
|
2098
|
+
console.log("");
|
|
2099
|
+
console.log(chalk9.green.bold(` Preview: http://localhost:${port}`));
|
|
2100
|
+
console.log("");
|
|
2101
|
+
console.log(chalk9.gray(" Starting dev server..."));
|
|
2102
|
+
console.log("");
|
|
2103
|
+
const child = startDevServer(targetDir, { ...serverConfig, port });
|
|
2104
|
+
child.stdout?.on("data", (d) => process.stdout.write(d));
|
|
2105
|
+
child.stderr?.on("data", (d) => process.stderr.write(d));
|
|
2106
|
+
child.on("close", (code) => {
|
|
2107
|
+
console.log(chalk9.gray(`
|
|
2108
|
+
Dev server stopped (exit ${code})`));
|
|
2109
|
+
});
|
|
2110
|
+
process.on("SIGINT", () => {
|
|
2111
|
+
child.kill();
|
|
2112
|
+
console.log(chalk9.gray("\n Dev server stopped."));
|
|
2113
|
+
process.exit(0);
|
|
2114
|
+
});
|
|
2115
|
+
} else {
|
|
2116
|
+
console.log("");
|
|
2117
|
+
console.log(chalk9.yellow(" No dev server detected. Run your dev server manually."));
|
|
2118
|
+
console.log(chalk9.gray(' Or use: fishi quickstart --dev-cmd "npm run dev"'));
|
|
2119
|
+
console.log("");
|
|
2120
|
+
console.log(chalk9.cyan.bold(" Ready to ship!"));
|
|
2121
|
+
console.log(chalk9.gray(" Run `claude` to start working with your AI dev team."));
|
|
2122
|
+
console.log("");
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
// src/commands/preview.ts
|
|
2127
|
+
import chalk10 from "chalk";
|
|
2128
|
+
import fs12 from "fs";
|
|
2129
|
+
import path12 from "path";
|
|
2130
|
+
import { detectDevServer as detectDevServer2, startDevServer as startDevServer2 } from "@qlucent/fishi-core";
|
|
2131
|
+
async function previewCommand(options) {
|
|
2132
|
+
const targetDir = process.cwd();
|
|
2133
|
+
if (!fs12.existsSync(path12.join(targetDir, ".fishi"))) {
|
|
2134
|
+
console.log(chalk10.yellow(" No FISHI project found. Run `fishi init` or `fishi quickstart` first."));
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
const serverConfig = detectDevServer2(targetDir, options.devCmd);
|
|
2138
|
+
if (!serverConfig.detected) {
|
|
2139
|
+
console.log(chalk10.yellow(" Could not detect dev server."));
|
|
2140
|
+
console.log(chalk10.gray(' Use --dev-cmd to specify: fishi preview --dev-cmd "npm run dev"'));
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
const port = options.port ? parseInt(options.port, 10) : serverConfig.port;
|
|
2144
|
+
console.log("");
|
|
2145
|
+
console.log(chalk10.cyan.bold(" FISHI Live Preview"));
|
|
2146
|
+
console.log(chalk10.gray(` Framework: ${serverConfig.framework}`));
|
|
2147
|
+
console.log(chalk10.green.bold(` URL: http://localhost:${port}`));
|
|
2148
|
+
console.log(chalk10.gray(" Press Ctrl+C to stop"));
|
|
2149
|
+
console.log("");
|
|
2150
|
+
const child = startDevServer2(targetDir, { ...serverConfig, port });
|
|
2151
|
+
child.stdout?.on("data", (d) => process.stdout.write(d));
|
|
2152
|
+
child.stderr?.on("data", (d) => process.stderr.write(d));
|
|
2153
|
+
child.on("close", (code) => {
|
|
2154
|
+
console.log(chalk10.gray(`
|
|
2155
|
+
Dev server stopped (exit ${code})`));
|
|
2156
|
+
});
|
|
2157
|
+
process.on("SIGINT", () => {
|
|
2158
|
+
child.kill();
|
|
2159
|
+
console.log(chalk10.gray("\n Dev server stopped."));
|
|
2160
|
+
process.exit(0);
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
// src/commands/design.ts
|
|
2165
|
+
import chalk11 from "chalk";
|
|
2166
|
+
import fs13 from "fs";
|
|
2167
|
+
import path13 from "path";
|
|
2168
|
+
import {
|
|
2169
|
+
detectDesignTokens,
|
|
2170
|
+
generateDefaultTokens,
|
|
2171
|
+
detectComponentRegistry,
|
|
2172
|
+
runBrandGuardian,
|
|
2173
|
+
generateDesignSystemConfig
|
|
2174
|
+
} from "@qlucent/fishi-core";
|
|
2175
|
+
async function designCommand(action, options) {
|
|
2176
|
+
const targetDir = process.cwd();
|
|
2177
|
+
if (action === "detect") {
|
|
2178
|
+
console.log("");
|
|
2179
|
+
console.log(chalk11.cyan.bold(" FISHI Design System \u2014 Detect"));
|
|
2180
|
+
console.log("");
|
|
2181
|
+
const tokens = detectDesignTokens(targetDir);
|
|
2182
|
+
const registry = detectComponentRegistry(targetDir);
|
|
2183
|
+
console.log(chalk11.white.bold(" Design Tokens"));
|
|
2184
|
+
console.log(chalk11.gray(` Colors: ${Object.keys(tokens.colors).length} detected`));
|
|
2185
|
+
console.log(chalk11.gray(` Typography: ${tokens.typography.fontFamilies.length} font families, ${Object.keys(tokens.typography.scale).length} scale values`));
|
|
2186
|
+
console.log(chalk11.gray(` Spacing: ${Object.keys(tokens.spacing).length} values`));
|
|
2187
|
+
console.log(chalk11.gray(` Border radius: ${Object.keys(tokens.borderRadius).length} values`));
|
|
2188
|
+
console.log(chalk11.gray(` Dark mode: ${tokens.darkMode ? chalk11.green("yes") : chalk11.yellow("no")}`));
|
|
2189
|
+
console.log("");
|
|
2190
|
+
console.log(chalk11.white.bold(" Component Registry"));
|
|
2191
|
+
console.log(chalk11.gray(` Library: ${registry.library || "none detected"}`));
|
|
2192
|
+
console.log(chalk11.gray(` Framework: ${registry.framework || "none detected"}`));
|
|
2193
|
+
console.log(chalk11.gray(` Components: ${registry.components.length} found`));
|
|
2194
|
+
if (registry.components.length > 0) {
|
|
2195
|
+
const byType = {};
|
|
2196
|
+
for (const c of registry.components) byType[c.type] = (byType[c.type] || 0) + 1;
|
|
2197
|
+
for (const [type, count] of Object.entries(byType)) {
|
|
2198
|
+
console.log(chalk11.gray(` ${type}: ${count}`));
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
console.log("");
|
|
2202
|
+
if (options.output || fs13.existsSync(path13.join(targetDir, ".fishi"))) {
|
|
2203
|
+
const outputPath = options.output || path13.join(targetDir, ".fishi", "design-system.json");
|
|
2204
|
+
const dir = path13.dirname(outputPath);
|
|
2205
|
+
if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
|
|
2206
|
+
fs13.writeFileSync(outputPath, generateDesignSystemConfig(tokens, registry), "utf-8");
|
|
2207
|
+
console.log(chalk11.green(` Saved to ${path13.relative(targetDir, outputPath)}`));
|
|
2208
|
+
}
|
|
2209
|
+
} else if (action === "init") {
|
|
2210
|
+
console.log("");
|
|
2211
|
+
console.log(chalk11.cyan.bold(" FISHI Design System \u2014 Initialize"));
|
|
2212
|
+
console.log("");
|
|
2213
|
+
let tokens = detectDesignTokens(targetDir);
|
|
2214
|
+
const hasExisting = Object.keys(tokens.colors).length > 0;
|
|
2215
|
+
if (!hasExisting) {
|
|
2216
|
+
tokens = generateDefaultTokens();
|
|
2217
|
+
console.log(chalk11.yellow(" No design tokens found \u2014 using FISHI defaults."));
|
|
2218
|
+
} else {
|
|
2219
|
+
console.log(chalk11.green(` Detected ${Object.keys(tokens.colors).length} colors from your project.`));
|
|
2220
|
+
}
|
|
2221
|
+
const registry = detectComponentRegistry(targetDir);
|
|
2222
|
+
const outputPath = path13.join(targetDir, ".fishi", "design-system.json");
|
|
2223
|
+
const dir = path13.dirname(outputPath);
|
|
2224
|
+
if (!fs13.existsSync(dir)) fs13.mkdirSync(dir, { recursive: true });
|
|
2225
|
+
fs13.writeFileSync(outputPath, generateDesignSystemConfig(tokens, registry), "utf-8");
|
|
2226
|
+
console.log(chalk11.green(` Design system saved to .fishi/design-system.json`));
|
|
2227
|
+
console.log(chalk11.gray(" Your agents will use these tokens for consistent styling."));
|
|
2228
|
+
console.log("");
|
|
2229
|
+
} else if (action === "validate") {
|
|
2230
|
+
console.log("");
|
|
2231
|
+
console.log(chalk11.cyan.bold(" FISHI Brand Guardian \u2014 Validation"));
|
|
2232
|
+
console.log("");
|
|
2233
|
+
const tokens = detectDesignTokens(targetDir);
|
|
2234
|
+
const report = runBrandGuardian(targetDir, tokens);
|
|
2235
|
+
if (report.issues.length === 0) {
|
|
2236
|
+
console.log(chalk11.green(" No issues found! Your frontend follows the design system."));
|
|
2237
|
+
} else {
|
|
2238
|
+
for (const issue of report.issues) {
|
|
2239
|
+
const icon = issue.severity === "error" ? chalk11.red("ERROR") : issue.severity === "warning" ? chalk11.yellow("WARN") : chalk11.blue("INFO");
|
|
2240
|
+
console.log(` ${icon} ${chalk11.gray(issue.file)}:${issue.line}`);
|
|
2241
|
+
console.log(` ${issue.message}`);
|
|
2242
|
+
if (issue.fix) console.log(` ${chalk11.gray("Fix: " + issue.fix)}`);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
console.log("");
|
|
2246
|
+
console.log(chalk11.white.bold(" Summary"));
|
|
2247
|
+
console.log(chalk11.gray(` Files scanned: ${report.stats.filesScanned}`));
|
|
2248
|
+
console.log(chalk11.red(` Errors: ${report.stats.errors}`));
|
|
2249
|
+
console.log(chalk11.yellow(` Warnings: ${report.stats.warnings}`));
|
|
2250
|
+
console.log(chalk11.blue(` Info: ${report.stats.infos}`));
|
|
2251
|
+
console.log(` Status: ${report.passed ? chalk11.green("PASSED") : chalk11.red("FAILED")}`);
|
|
2252
|
+
console.log("");
|
|
2253
|
+
if (!report.passed) process.exit(1);
|
|
2254
|
+
} else {
|
|
2255
|
+
console.log(chalk11.yellow(` Unknown action: ${action}. Use: detect, init, validate`));
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
|
|
1973
2259
|
// src/index.ts
|
|
1974
2260
|
var program = new Command();
|
|
1975
2261
|
program.name("fishi").description(
|
|
1976
|
-
|
|
1977
|
-
).version("0.
|
|
2262
|
+
chalk12.cyan("\u{1F41F} FISHI") + " \u2014 Your AI Dev Team That Actually Ships\n Autonomous agent framework for Claude Code"
|
|
2263
|
+
).version("0.9.0");
|
|
1978
2264
|
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(
|
|
1979
2265
|
"-c, --cost-mode <mode>",
|
|
1980
2266
|
"Cost mode: performance | balanced | economy",
|
|
@@ -1987,4 +2273,7 @@ program.command("validate").description("Validate scaffold integrity \u2014 chec
|
|
|
1987
2273
|
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);
|
|
1988
2274
|
program.command("dashboard").description("Agent observability \u2014 web dashboard at http://localhost:4269").option("-p, --port <port>", "Port number", "4269").action(dashboardCommand);
|
|
1989
2275
|
program.command("sandbox").description("Sandbox status and policy management").argument("<action>", "Action: status | policy").action(sandboxCommand);
|
|
2276
|
+
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);
|
|
2277
|
+
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);
|
|
2278
|
+
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);
|
|
1990
2279
|
program.parse();
|