zefiro 0.8.1 → 0.10.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/README.md +5 -14
- package/dist/cli-5w708rbb.js +167 -0
- package/dist/cli-6qr9gvkp.js +508 -0
- package/dist/cli-7hvj61ht.js +150 -0
- package/dist/cli-b26q1e27.js +264 -0
- package/dist/cli-ewbvvxm8.js +145 -0
- package/dist/cli-g7n2me6z.js +133 -0
- package/dist/cli-kjyet1n8.js +384 -0
- package/dist/cli-m1ghts25.js +133 -0
- package/dist/cli-mm7ct90g.js +110 -0
- package/dist/cli.js +224 -131
- package/dist/explorer-ckk9bkff.js +11 -0
- package/dist/explorer-g6bmbak1.js +10 -0
- package/dist/explorer-svj2p317.js +10 -0
- package/dist/graph-builder-ca71yjkc.js +10 -0
- package/dist/index.js +1 -1
- package/dist/mcp.js +4274 -269
- package/dist/report-sdtah1f4.js +11 -0
- package/dist/report-wh0mnnxb.js +12 -0
- package/package.json +2 -6
- package/skills/zefiro-copilot/SKILL.md +103 -0
package/dist/cli.js
CHANGED
|
@@ -4,32 +4,38 @@ import {
|
|
|
4
4
|
getPackageRoot,
|
|
5
5
|
getProjectRoot,
|
|
6
6
|
loadConfig
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-mm7ct90g.js";
|
|
8
8
|
import"./cli-z2krvkcq.js";
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
dist_default9 as dist_default3
|
|
10
|
+
dist_default3 as dist_default,
|
|
11
|
+
dist_default9 as dist_default2
|
|
13
12
|
} from "./cli-eyd8t0cw.js";
|
|
13
|
+
import {
|
|
14
|
+
runExploration
|
|
15
|
+
} from "./cli-7hvj61ht.js";
|
|
14
16
|
import {
|
|
15
17
|
banner,
|
|
16
18
|
error,
|
|
17
19
|
header,
|
|
18
20
|
info,
|
|
19
21
|
require_picocolors,
|
|
20
|
-
runExploration,
|
|
21
22
|
setVerbose,
|
|
22
23
|
success,
|
|
23
24
|
warn
|
|
24
|
-
} from "./cli-
|
|
25
|
+
} from "./cli-b26q1e27.js";
|
|
26
|
+
import {
|
|
27
|
+
generateIndexHtml,
|
|
28
|
+
generateReadme
|
|
29
|
+
} from "./cli-kjyet1n8.js";
|
|
25
30
|
import {
|
|
26
31
|
ensureDir,
|
|
27
32
|
writeFile
|
|
28
33
|
} from "./cli-zvk8gwe4.js";
|
|
29
34
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "./cli-
|
|
35
|
+
buildReportGraph,
|
|
36
|
+
buildReportSections
|
|
37
|
+
} from "./cli-ewbvvxm8.js";
|
|
38
|
+
import"./cli-5w708rbb.js";
|
|
33
39
|
import {
|
|
34
40
|
__commonJS,
|
|
35
41
|
__require,
|
|
@@ -2150,6 +2156,11 @@ function registerExplore(program2) {
|
|
|
2150
2156
|
};
|
|
2151
2157
|
ensureDir(config.outputDir);
|
|
2152
2158
|
const state = await runExploration(config);
|
|
2159
|
+
const serializableState = {
|
|
2160
|
+
...state,
|
|
2161
|
+
pages: Object.fromEntries(state.pages)
|
|
2162
|
+
};
|
|
2163
|
+
writeFile(join2(config.outputDir, ".exploration-state.json"), JSON.stringify(serializableState, null, 2));
|
|
2153
2164
|
const readme = generateReadme(state);
|
|
2154
2165
|
writeFile(join2(config.outputDir, "README.md"), readme);
|
|
2155
2166
|
if (opts.report !== false) {
|
|
@@ -2173,6 +2184,143 @@ function registerExplore(program2) {
|
|
|
2173
2184
|
});
|
|
2174
2185
|
}
|
|
2175
2186
|
|
|
2187
|
+
// src/commands/push.ts
|
|
2188
|
+
import { join as join3 } from "node:path";
|
|
2189
|
+
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
2190
|
+
function loadExplorationState(outputDir, baseUrl) {
|
|
2191
|
+
const sectionsDir = join3(outputDir, "sections");
|
|
2192
|
+
const readmePath = join3(outputDir, "README.md");
|
|
2193
|
+
if (!existsSync(sectionsDir)) {
|
|
2194
|
+
throw new Error(`No sections/ directory found in ${outputDir}. Run 'zefiro explore' first.`);
|
|
2195
|
+
}
|
|
2196
|
+
const statePath = join3(outputDir, ".exploration-state.json");
|
|
2197
|
+
if (existsSync(statePath)) {
|
|
2198
|
+
const raw = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
2199
|
+
const pages = new Map(Object.entries(raw.pages));
|
|
2200
|
+
return { ...raw, pages };
|
|
2201
|
+
}
|
|
2202
|
+
throw new Error(`No exploration state found at ${statePath}.
|
|
2203
|
+
` + `Re-run 'zefiro explore' to generate the state file (required for push).`);
|
|
2204
|
+
}
|
|
2205
|
+
function loadSectionMarkdowns(outputDir) {
|
|
2206
|
+
const sectionsDir = join3(outputDir, "sections");
|
|
2207
|
+
const markdowns = new Map;
|
|
2208
|
+
if (!existsSync(sectionsDir))
|
|
2209
|
+
return markdowns;
|
|
2210
|
+
for (const file of readdirSync(sectionsDir)) {
|
|
2211
|
+
if (file.endsWith(".md")) {
|
|
2212
|
+
const slug = file.replace(/\.md$/, "");
|
|
2213
|
+
markdowns.set(slug, readFileSync(join3(sectionsDir, file), "utf-8"));
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
return markdowns;
|
|
2217
|
+
}
|
|
2218
|
+
function loadScreenshots(outputDir) {
|
|
2219
|
+
const screenshotsDir = join3(outputDir, "screenshots");
|
|
2220
|
+
if (!existsSync(screenshotsDir))
|
|
2221
|
+
return [];
|
|
2222
|
+
const screenshots = [];
|
|
2223
|
+
for (const slugDir of readdirSync(screenshotsDir)) {
|
|
2224
|
+
const fullDir = join3(screenshotsDir, slugDir);
|
|
2225
|
+
try {
|
|
2226
|
+
const files = readdirSync(fullDir);
|
|
2227
|
+
for (let i = 0;i < files.length; i++) {
|
|
2228
|
+
const file = files[i];
|
|
2229
|
+
if (!file.endsWith(".png") && !file.endsWith(".jpg"))
|
|
2230
|
+
continue;
|
|
2231
|
+
const data = readFileSync(join3(fullDir, file)).toString("base64");
|
|
2232
|
+
screenshots.push({
|
|
2233
|
+
sectionSlug: slugDir,
|
|
2234
|
+
filename: file,
|
|
2235
|
+
label: file.replace(/^\d+-/, "").replace(/\.\w+$/, ""),
|
|
2236
|
+
sortOrder: i,
|
|
2237
|
+
data
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
} catch {}
|
|
2241
|
+
}
|
|
2242
|
+
return screenshots;
|
|
2243
|
+
}
|
|
2244
|
+
function registerPush(program2) {
|
|
2245
|
+
program2.command("push").description("Push exploration report to QA Intelligence").option("--output <dir>", "Exploration output directory").option("--key <apiKey>", "App API key (or set QAI_API_KEY)").option("--api-url <url>", "API base URL (or set QAI_API_URL)").option("--commit-sha <sha>", "Git commit SHA to associate with this report").option("--dry-run", "Build payload and show stats without pushing").action(async (opts) => {
|
|
2246
|
+
try {
|
|
2247
|
+
const ctx = await resolveCommandContext(program2);
|
|
2248
|
+
header("zefiro push");
|
|
2249
|
+
const apiKey = opts.key || process.env.QAI_API_KEY;
|
|
2250
|
+
if (!apiKey && !opts.dryRun) {
|
|
2251
|
+
error("Missing API key. Use --key or set QAI_API_KEY environment variable.");
|
|
2252
|
+
info("Get your app API key from the app settings page in QA Intelligence.");
|
|
2253
|
+
process.exit(1);
|
|
2254
|
+
}
|
|
2255
|
+
const apiUrl = opts.apiUrl || process.env.QAI_API_URL || "https://qaligent.space";
|
|
2256
|
+
const outputDir = opts.output ? join3(ctx.paths.projectRoot, opts.output) : ctx.paths.outputDir;
|
|
2257
|
+
info(`Output dir: ${outputDir}`);
|
|
2258
|
+
info(`API URL: ${apiUrl}`);
|
|
2259
|
+
const baseUrl = ctx.config.baseUrl ?? "http://localhost:3000";
|
|
2260
|
+
const state = loadExplorationState(outputDir, baseUrl);
|
|
2261
|
+
const visitedPages = Array.from(state.pages.values()).filter((p) => p.status === "visited");
|
|
2262
|
+
info(`Pages found: ${visitedPages.length}`);
|
|
2263
|
+
const graph = buildReportGraph(state);
|
|
2264
|
+
info(`Graph: ${graph.nodes.length} nodes, ${graph.edges.length} edges, ${graph.sectionGroups.length} groups`);
|
|
2265
|
+
const markdowns = loadSectionMarkdowns(outputDir);
|
|
2266
|
+
const sections = buildReportSections(visitedPages, markdowns);
|
|
2267
|
+
const screenshots = loadScreenshots(outputDir);
|
|
2268
|
+
info(`Screenshots: ${screenshots.length}`);
|
|
2269
|
+
const readmePath = join3(outputDir, "README.md");
|
|
2270
|
+
const readme = existsSync(readmePath) ? readFileSync(readmePath, "utf-8") : `# Application Map
|
|
2271
|
+
|
|
2272
|
+
${visitedPages.length} pages explored.`;
|
|
2273
|
+
const payload = {
|
|
2274
|
+
title: `Zefiro Scan — ${new Date().toISOString().split("T")[0]}`,
|
|
2275
|
+
readme,
|
|
2276
|
+
sections,
|
|
2277
|
+
graph,
|
|
2278
|
+
screenshots,
|
|
2279
|
+
commitSha: opts.commitSha || undefined
|
|
2280
|
+
};
|
|
2281
|
+
if (opts.dryRun) {
|
|
2282
|
+
console.log("");
|
|
2283
|
+
success("Dry run — payload built successfully:");
|
|
2284
|
+
console.log(` Title: ${payload.title}`);
|
|
2285
|
+
console.log(` Sections: ${payload.sections.length}`);
|
|
2286
|
+
console.log(` Nodes: ${payload.graph.nodes.length}`);
|
|
2287
|
+
console.log(` Edges: ${payload.graph.edges.length}`);
|
|
2288
|
+
console.log(` Groups: ${payload.graph.sectionGroups.length}`);
|
|
2289
|
+
console.log(` Screenshots: ${payload.screenshots.length}`);
|
|
2290
|
+
console.log(` Payload size: ~${Math.round(JSON.stringify(payload).length / 1024)}KB`);
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2293
|
+
info("Pushing to QA Intelligence...");
|
|
2294
|
+
const res = await fetch(`${apiUrl}/api/v2/push-report`, {
|
|
2295
|
+
method: "POST",
|
|
2296
|
+
headers: {
|
|
2297
|
+
"Content-Type": "application/json",
|
|
2298
|
+
Authorization: `Bearer ${apiKey}`
|
|
2299
|
+
},
|
|
2300
|
+
body: JSON.stringify(payload)
|
|
2301
|
+
});
|
|
2302
|
+
if (!res.ok) {
|
|
2303
|
+
const body = await res.text();
|
|
2304
|
+
throw new Error(`Push failed (${res.status}): ${body}`);
|
|
2305
|
+
}
|
|
2306
|
+
const result = await res.json();
|
|
2307
|
+
console.log("");
|
|
2308
|
+
success("Report pushed successfully!");
|
|
2309
|
+
console.log("");
|
|
2310
|
+
console.log(` Version: v${result.version}`);
|
|
2311
|
+
console.log(` App ID: ${result.appId}`);
|
|
2312
|
+
console.log(` Pushed at: ${result.pushedAt}`);
|
|
2313
|
+
console.log(` Sections: ${result.stats.sections}`);
|
|
2314
|
+
console.log(` Screenshots: ${result.stats.screenshots}`);
|
|
2315
|
+
console.log(` Nodes: ${result.stats.graphNodes}`);
|
|
2316
|
+
console.log(` Edges: ${result.stats.graphEdges}`);
|
|
2317
|
+
} catch (err) {
|
|
2318
|
+
error(err.message);
|
|
2319
|
+
process.exit(1);
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2176
2324
|
// ../cli-auth/dist/index.js
|
|
2177
2325
|
import { createHash, randomBytes } from "node:crypto";
|
|
2178
2326
|
import { createServer } from "node:http";
|
|
@@ -2201,8 +2349,8 @@ import { promisify as promisify2 } from "node:util";
|
|
|
2201
2349
|
import { execFile as execFile2, execFileSync } from "node:child_process";
|
|
2202
2350
|
import { promisify as promisify3 } from "node:util";
|
|
2203
2351
|
import { execFile as execFile3 } from "node:child_process";
|
|
2204
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2205
|
-
import { join as
|
|
2352
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
|
|
2353
|
+
import { join as join4 } from "node:path";
|
|
2206
2354
|
import { homedir } from "node:os";
|
|
2207
2355
|
var __create = Object.create;
|
|
2208
2356
|
var __getProtoOf = Object.getPrototypeOf;
|
|
@@ -2749,16 +2897,16 @@ defineLazyProperty(apps, "browser", () => "browser");
|
|
|
2749
2897
|
defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
|
|
2750
2898
|
var open_default = open;
|
|
2751
2899
|
var import_picocolors = __toESM2(require_picocolors2(), 1);
|
|
2752
|
-
var AUTH_DIR =
|
|
2753
|
-
var AUTH_FILE =
|
|
2900
|
+
var AUTH_DIR = join4(homedir(), ".qai");
|
|
2901
|
+
var AUTH_FILE = join4(AUTH_DIR, "auth.json");
|
|
2754
2902
|
function emptyStore() {
|
|
2755
2903
|
return { version: 1, sessions: [], activeSessionIndex: -1 };
|
|
2756
2904
|
}
|
|
2757
2905
|
function loadStore() {
|
|
2758
|
-
if (!
|
|
2906
|
+
if (!existsSync2(AUTH_FILE))
|
|
2759
2907
|
return emptyStore();
|
|
2760
2908
|
try {
|
|
2761
|
-
const data = JSON.parse(
|
|
2909
|
+
const data = JSON.parse(readFileSync2(AUTH_FILE, "utf-8"));
|
|
2762
2910
|
if (data.version !== 1)
|
|
2763
2911
|
return emptyStore();
|
|
2764
2912
|
return data;
|
|
@@ -3119,7 +3267,19 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
|
3119
3267
|
var TOOLS = [
|
|
3120
3268
|
"zefiro_explore — explore a web application via BFS",
|
|
3121
3269
|
"zefiro_read_docs — read generated documentation",
|
|
3122
|
-
"zefiro_scan_codebase — scan project test infrastructure"
|
|
3270
|
+
"zefiro_scan_codebase — scan project test infrastructure",
|
|
3271
|
+
"zefiro_copilot_start — start an interactive copilot session",
|
|
3272
|
+
"zefiro_copilot_stop — stop session and generate report",
|
|
3273
|
+
"zefiro_copilot_navigate — navigate to a URL",
|
|
3274
|
+
"zefiro_copilot_snapshot — get page accessibility snapshot",
|
|
3275
|
+
"zefiro_copilot_screenshot — take a screenshot",
|
|
3276
|
+
"zefiro_copilot_click — click an element",
|
|
3277
|
+
"zefiro_copilot_fill — fill a form field",
|
|
3278
|
+
"zefiro_copilot_get_links — extract page links",
|
|
3279
|
+
"zefiro_copilot_record_page — record current page documentation",
|
|
3280
|
+
"zefiro_copilot_get_session — get session state",
|
|
3281
|
+
"zefiro_copilot_check_input — check pending user input",
|
|
3282
|
+
"zefiro_copilot_propose_action — propose action to user"
|
|
3123
3283
|
];
|
|
3124
3284
|
var DESKTOP_CONFIG = JSON.stringify({
|
|
3125
3285
|
mcpServers: {
|
|
@@ -3162,78 +3322,10 @@ function registerMcp(program2) {
|
|
|
3162
3322
|
|
|
3163
3323
|
// src/commands/init.ts
|
|
3164
3324
|
import { join as join5 } from "node:path";
|
|
3165
|
-
import { readdirSync, readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
3325
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
3166
3326
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync, cpSync } from "node:fs";
|
|
3170
|
-
import { join as join4 } from "node:path";
|
|
3171
|
-
var LEGACY_DIR = ".e2e-ai";
|
|
3172
|
-
async function migrateFromLegacy(projectRoot, nonInteractive) {
|
|
3173
|
-
const legacyPath = join4(projectRoot, LEGACY_DIR);
|
|
3174
|
-
const newPath = join4(projectRoot, CONFIG_DIR);
|
|
3175
|
-
if (!existsSync2(legacyPath))
|
|
3176
|
-
return false;
|
|
3177
|
-
if (existsSync2(join4(newPath, "config.ts")) || existsSync2(join4(newPath, "config.js")) || existsSync2(join4(newPath, "config.mjs"))) {
|
|
3178
|
-
return false;
|
|
3179
|
-
}
|
|
3180
|
-
try {
|
|
3181
|
-
info(`Legacy ${LEGACY_DIR}/ detected — migrating to ${CONFIG_DIR}/
|
|
3182
|
-
`);
|
|
3183
|
-
ensureDir(newPath);
|
|
3184
|
-
let migrated = 0;
|
|
3185
|
-
for (const name of ["config.ts", "config.js", "config.mjs"]) {
|
|
3186
|
-
const src = join4(legacyPath, name);
|
|
3187
|
-
if (existsSync2(src)) {
|
|
3188
|
-
let content = readFileSync2(src, "utf-8");
|
|
3189
|
-
content = content.replace(/from\s+['"]e2e-ai\/config['"]/g, "from 'zefiro/config'");
|
|
3190
|
-
writeFile(join4(newPath, name), content);
|
|
3191
|
-
migrated++;
|
|
3192
|
-
break;
|
|
3193
|
-
}
|
|
3194
|
-
}
|
|
3195
|
-
const contextSrc = join4(legacyPath, "context.md");
|
|
3196
|
-
if (existsSync2(contextSrc)) {
|
|
3197
|
-
cpSync(contextSrc, join4(newPath, "context.md"));
|
|
3198
|
-
migrated++;
|
|
3199
|
-
}
|
|
3200
|
-
const agentsSrc = join4(legacyPath, "agents");
|
|
3201
|
-
if (existsSync2(agentsSrc)) {
|
|
3202
|
-
cpSync(agentsSrc, join4(newPath, "agents"), { recursive: true });
|
|
3203
|
-
migrated++;
|
|
3204
|
-
}
|
|
3205
|
-
const cacheSrc = join4(legacyPath, "scan-cache");
|
|
3206
|
-
if (existsSync2(cacheSrc)) {
|
|
3207
|
-
cpSync(cacheSrc, join4(newPath, "scan-cache"), { recursive: true });
|
|
3208
|
-
migrated++;
|
|
3209
|
-
}
|
|
3210
|
-
const astSrc = join4(legacyPath, "ast-scan.json");
|
|
3211
|
-
if (existsSync2(astSrc)) {
|
|
3212
|
-
cpSync(astSrc, join4(newPath, "ast-scan.json"));
|
|
3213
|
-
migrated++;
|
|
3214
|
-
}
|
|
3215
|
-
success(`Migrated ${migrated} item(s) from ${LEGACY_DIR}/ to ${CONFIG_DIR}/`);
|
|
3216
|
-
if (!nonInteractive) {
|
|
3217
|
-
const remove = await dist_default({
|
|
3218
|
-
message: `Remove old ${LEGACY_DIR}/ directory?`,
|
|
3219
|
-
default: false
|
|
3220
|
-
});
|
|
3221
|
-
if (remove) {
|
|
3222
|
-
rmSync(legacyPath, { recursive: true, force: true });
|
|
3223
|
-
success(`Removed ${LEGACY_DIR}/`);
|
|
3224
|
-
}
|
|
3225
|
-
}
|
|
3226
|
-
return true;
|
|
3227
|
-
} catch (err) {
|
|
3228
|
-
warn(`Migration from ${LEGACY_DIR}/ failed: ${err instanceof Error ? err.message : err}`);
|
|
3229
|
-
warn(`Continuing with fresh initialization...
|
|
3230
|
-
`);
|
|
3231
|
-
return false;
|
|
3232
|
-
}
|
|
3233
|
-
}
|
|
3234
|
-
|
|
3235
|
-
// src/commands/init.ts
|
|
3236
|
-
var SKILLS_TARGET = ".claude/skills/zefiro";
|
|
3327
|
+
var SKILLS_TARGET_BASE = ".claude/skills";
|
|
3328
|
+
var SKILL_DIRS = ["zefiro", "zefiro-copilot"];
|
|
3237
3329
|
function registerInit(program2) {
|
|
3238
3330
|
program2.command("init").description("Initialize zefiro configuration for your project").option("--non-interactive", "Skip interactive prompts, use defaults").action(async (cmdOpts) => {
|
|
3239
3331
|
try {
|
|
@@ -3241,7 +3333,6 @@ function registerInit(program2) {
|
|
|
3241
3333
|
const packageRoot = getPackageRoot();
|
|
3242
3334
|
const nonInteractive = !!cmdOpts?.nonInteractive;
|
|
3243
3335
|
header("zefiro init");
|
|
3244
|
-
await migrateFromLegacy(projectRoot, nonInteractive);
|
|
3245
3336
|
const qaiDir = join5(projectRoot, CONFIG_DIR);
|
|
3246
3337
|
const isReInit = existsSync3(qaiDir);
|
|
3247
3338
|
if (isReInit) {
|
|
@@ -3285,11 +3376,11 @@ function getDefaultAnswers() {
|
|
|
3285
3376
|
async function askConfigQuestions() {
|
|
3286
3377
|
info(`Configure your zefiro setup:
|
|
3287
3378
|
`);
|
|
3288
|
-
const baseUrl = await
|
|
3379
|
+
const baseUrl = await dist_default({
|
|
3289
3380
|
message: "Application base URL (e.g., http://localhost:3000)",
|
|
3290
3381
|
default: process.env.QAI_BASE_URL ?? ""
|
|
3291
3382
|
});
|
|
3292
|
-
const authMethod = await
|
|
3383
|
+
const authMethod = await dist_default2({
|
|
3293
3384
|
message: "Authentication method",
|
|
3294
3385
|
choices: [
|
|
3295
3386
|
{ name: "Manual (authenticate in headed browser)", value: "manual" },
|
|
@@ -3297,7 +3388,7 @@ async function askConfigQuestions() {
|
|
|
3297
3388
|
],
|
|
3298
3389
|
default: "manual"
|
|
3299
3390
|
});
|
|
3300
|
-
const outputDir = await
|
|
3391
|
+
const outputDir = await dist_default({
|
|
3301
3392
|
message: "Output directory for exploration results",
|
|
3302
3393
|
default: "app-report"
|
|
3303
3394
|
});
|
|
@@ -3331,44 +3422,56 @@ ${qaiBlock}
|
|
|
3331
3422
|
success(`Environment variables written to .env`);
|
|
3332
3423
|
}
|
|
3333
3424
|
async function copySkillsToLocal(projectRoot, packageRoot, nonInteractive) {
|
|
3334
|
-
const
|
|
3335
|
-
const
|
|
3336
|
-
if (!existsSync3(
|
|
3425
|
+
const sourceBase = join5(packageRoot, "skills");
|
|
3426
|
+
const targetBase = join5(projectRoot, SKILLS_TARGET_BASE);
|
|
3427
|
+
if (!existsSync3(sourceBase)) {
|
|
3337
3428
|
warn("Could not read package skills directory");
|
|
3338
3429
|
return 0;
|
|
3339
3430
|
}
|
|
3340
|
-
|
|
3341
|
-
|
|
3431
|
+
let totalSourceFiles = [];
|
|
3432
|
+
let totalExistingFiles = 0;
|
|
3433
|
+
for (const skillDir of SKILL_DIRS) {
|
|
3434
|
+
const sourceDir = join5(sourceBase, skillDir);
|
|
3435
|
+
if (!existsSync3(sourceDir))
|
|
3436
|
+
continue;
|
|
3437
|
+
const files = collectMarkdownFiles(sourceDir, sourceDir);
|
|
3438
|
+
for (const f of files)
|
|
3439
|
+
totalSourceFiles.push({ dir: skillDir, relPath: f });
|
|
3440
|
+
}
|
|
3441
|
+
if (totalSourceFiles.length === 0)
|
|
3342
3442
|
return 0;
|
|
3343
|
-
const
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3443
|
+
for (const skillDir of SKILL_DIRS) {
|
|
3444
|
+
const targetDir = join5(targetBase, skillDir);
|
|
3445
|
+
if (existsSync3(targetDir)) {
|
|
3446
|
+
totalExistingFiles += collectMarkdownFiles(targetDir, targetDir).length;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
if (totalExistingFiles > 0) {
|
|
3450
|
+
if (nonInteractive) {
|
|
3451
|
+
info(`Skill files already exist in ${SKILLS_TARGET_BASE}/, skipping`);
|
|
3452
|
+
return 0;
|
|
3453
|
+
}
|
|
3454
|
+
const { confirm } = await import("./index-0yaea7f8.js");
|
|
3455
|
+
const overwrite = await confirm({
|
|
3456
|
+
message: `Update skills to latest version? (${totalSourceFiles.length} files, currently ${totalExistingFiles} in ${SKILLS_TARGET_BASE}/)`,
|
|
3457
|
+
default: true
|
|
3458
|
+
});
|
|
3459
|
+
if (!overwrite) {
|
|
3460
|
+
info("Skipping skill copy");
|
|
3461
|
+
return 0;
|
|
3360
3462
|
}
|
|
3361
3463
|
}
|
|
3362
|
-
for (const relPath of
|
|
3363
|
-
const content = readFileSync3(join5(
|
|
3364
|
-
writeFile(join5(
|
|
3464
|
+
for (const { dir, relPath } of totalSourceFiles) {
|
|
3465
|
+
const content = readFileSync3(join5(sourceBase, dir, relPath), "utf-8");
|
|
3466
|
+
writeFile(join5(targetBase, dir, relPath), content);
|
|
3365
3467
|
}
|
|
3366
|
-
|
|
3367
|
-
|
|
3468
|
+
const skillNames = SKILL_DIRS.join(", ");
|
|
3469
|
+
success(`Skills copied to ${SKILLS_TARGET_BASE}/ [${skillNames}] (${totalSourceFiles.length} files)`);
|
|
3470
|
+
return totalSourceFiles.length;
|
|
3368
3471
|
}
|
|
3369
3472
|
function collectMarkdownFiles(dir, baseDir) {
|
|
3370
3473
|
const results = [];
|
|
3371
|
-
for (const entry of
|
|
3474
|
+
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
3372
3475
|
const fullPath = join5(dir, entry.name);
|
|
3373
3476
|
if (entry.isDirectory()) {
|
|
3374
3477
|
results.push(...collectMarkdownFiles(fullPath, baseDir));
|
|
@@ -3393,17 +3496,7 @@ program2.name("zefiro").description("AI-powered application explorer and documen
|
|
|
3393
3496
|
});
|
|
3394
3497
|
registerInit(program2);
|
|
3395
3498
|
registerExplore(program2);
|
|
3499
|
+
registerPush(program2);
|
|
3396
3500
|
registerAuth(program2);
|
|
3397
3501
|
registerMcp(program2);
|
|
3398
|
-
|
|
3399
|
-
var commandNames = program2.commands.map((c) => c.name());
|
|
3400
|
-
var hasCommand = userArgs.some((a) => commandNames.includes(a));
|
|
3401
|
-
var hasFlags = userArgs.some((a) => a.startsWith("-"));
|
|
3402
|
-
var cols = process.stdout.columns || 80;
|
|
3403
|
-
var rows = process.stdout.rows || 24;
|
|
3404
|
-
if (!hasCommand && !hasFlags && process.stdout.isTTY && cols >= 60 && rows >= 20) {
|
|
3405
|
-
const { launchTui } = await import("./App-bh752tgg.js");
|
|
3406
|
-
await launchTui(program2);
|
|
3407
|
-
} else {
|
|
3408
|
-
program2.parse();
|
|
3409
|
-
}
|
|
3502
|
+
program2.parse();
|