zefiro 0.9.0 → 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/dist/cli.js CHANGED
@@ -4,16 +4,15 @@ import {
4
4
  getPackageRoot,
5
5
  getProjectRoot,
6
6
  loadConfig
7
- } from "./cli-cymqw41r.js";
7
+ } from "./cli-mm7ct90g.js";
8
8
  import"./cli-z2krvkcq.js";
9
9
  import {
10
- dist_default2 as dist_default,
11
- dist_default3 as dist_default2,
12
- dist_default9 as dist_default3
10
+ dist_default3 as dist_default,
11
+ dist_default9 as dist_default2
13
12
  } from "./cli-eyd8t0cw.js";
14
13
  import {
15
14
  runExploration
16
- } from "./cli-g7n2me6z.js";
15
+ } from "./cli-7hvj61ht.js";
17
16
  import {
18
17
  banner,
19
18
  error,
@@ -24,14 +23,19 @@ import {
24
23
  success,
25
24
  warn
26
25
  } from "./cli-b26q1e27.js";
26
+ import {
27
+ generateIndexHtml,
28
+ generateReadme
29
+ } from "./cli-kjyet1n8.js";
27
30
  import {
28
31
  ensureDir,
29
32
  writeFile
30
33
  } from "./cli-zvk8gwe4.js";
31
34
  import {
32
- generateIndexHtml,
33
- generateReadme
34
- } from "./cli-6qr9gvkp.js";
35
+ buildReportGraph,
36
+ buildReportSections
37
+ } from "./cli-ewbvvxm8.js";
38
+ import"./cli-5w708rbb.js";
35
39
  import {
36
40
  __commonJS,
37
41
  __require,
@@ -2152,6 +2156,11 @@ function registerExplore(program2) {
2152
2156
  };
2153
2157
  ensureDir(config.outputDir);
2154
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));
2155
2164
  const readme = generateReadme(state);
2156
2165
  writeFile(join2(config.outputDir, "README.md"), readme);
2157
2166
  if (opts.report !== false) {
@@ -2175,6 +2184,143 @@ function registerExplore(program2) {
2175
2184
  });
2176
2185
  }
2177
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
+
2178
2324
  // ../cli-auth/dist/index.js
2179
2325
  import { createHash, randomBytes } from "node:crypto";
2180
2326
  import { createServer } from "node:http";
@@ -2203,8 +2349,8 @@ import { promisify as promisify2 } from "node:util";
2203
2349
  import { execFile as execFile2, execFileSync } from "node:child_process";
2204
2350
  import { promisify as promisify3 } from "node:util";
2205
2351
  import { execFile as execFile3 } from "node:child_process";
2206
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
2207
- import { join as join3 } from "node:path";
2352
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
2353
+ import { join as join4 } from "node:path";
2208
2354
  import { homedir } from "node:os";
2209
2355
  var __create = Object.create;
2210
2356
  var __getProtoOf = Object.getPrototypeOf;
@@ -2751,16 +2897,16 @@ defineLazyProperty(apps, "browser", () => "browser");
2751
2897
  defineLazyProperty(apps, "browserPrivate", () => "browserPrivate");
2752
2898
  var open_default = open;
2753
2899
  var import_picocolors = __toESM2(require_picocolors2(), 1);
2754
- var AUTH_DIR = join3(homedir(), ".qai");
2755
- var AUTH_FILE = join3(AUTH_DIR, "auth.json");
2900
+ var AUTH_DIR = join4(homedir(), ".qai");
2901
+ var AUTH_FILE = join4(AUTH_DIR, "auth.json");
2756
2902
  function emptyStore() {
2757
2903
  return { version: 1, sessions: [], activeSessionIndex: -1 };
2758
2904
  }
2759
2905
  function loadStore() {
2760
- if (!existsSync(AUTH_FILE))
2906
+ if (!existsSync2(AUTH_FILE))
2761
2907
  return emptyStore();
2762
2908
  try {
2763
- const data = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
2909
+ const data = JSON.parse(readFileSync2(AUTH_FILE, "utf-8"));
2764
2910
  if (data.version !== 1)
2765
2911
  return emptyStore();
2766
2912
  return data;
@@ -3121,7 +3267,19 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
3121
3267
  var TOOLS = [
3122
3268
  "zefiro_explore — explore a web application via BFS",
3123
3269
  "zefiro_read_docs — read generated documentation",
3124
- "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"
3125
3283
  ];
3126
3284
  var DESKTOP_CONFIG = JSON.stringify({
3127
3285
  mcpServers: {
@@ -3164,77 +3322,8 @@ function registerMcp(program2) {
3164
3322
 
3165
3323
  // src/commands/init.ts
3166
3324
  import { join as join5 } from "node:path";
3167
- 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";
3168
3326
  var import_picocolors5 = __toESM(require_picocolors(), 1);
3169
-
3170
- // src/config/migrate.ts
3171
- import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync, cpSync } from "node:fs";
3172
- import { join as join4 } from "node:path";
3173
- var LEGACY_DIR = ".e2e-ai";
3174
- async function migrateFromLegacy(projectRoot, nonInteractive) {
3175
- const legacyPath = join4(projectRoot, LEGACY_DIR);
3176
- const newPath = join4(projectRoot, CONFIG_DIR);
3177
- if (!existsSync2(legacyPath))
3178
- return false;
3179
- if (existsSync2(join4(newPath, "config.ts")) || existsSync2(join4(newPath, "config.js")) || existsSync2(join4(newPath, "config.mjs"))) {
3180
- return false;
3181
- }
3182
- try {
3183
- info(`Legacy ${LEGACY_DIR}/ detected — migrating to ${CONFIG_DIR}/
3184
- `);
3185
- ensureDir(newPath);
3186
- let migrated = 0;
3187
- for (const name of ["config.ts", "config.js", "config.mjs"]) {
3188
- const src = join4(legacyPath, name);
3189
- if (existsSync2(src)) {
3190
- let content = readFileSync2(src, "utf-8");
3191
- content = content.replace(/from\s+['"]e2e-ai\/config['"]/g, "from 'zefiro/config'");
3192
- writeFile(join4(newPath, name), content);
3193
- migrated++;
3194
- break;
3195
- }
3196
- }
3197
- const contextSrc = join4(legacyPath, "context.md");
3198
- if (existsSync2(contextSrc)) {
3199
- cpSync(contextSrc, join4(newPath, "context.md"));
3200
- migrated++;
3201
- }
3202
- const agentsSrc = join4(legacyPath, "agents");
3203
- if (existsSync2(agentsSrc)) {
3204
- cpSync(agentsSrc, join4(newPath, "agents"), { recursive: true });
3205
- migrated++;
3206
- }
3207
- const cacheSrc = join4(legacyPath, "scan-cache");
3208
- if (existsSync2(cacheSrc)) {
3209
- cpSync(cacheSrc, join4(newPath, "scan-cache"), { recursive: true });
3210
- migrated++;
3211
- }
3212
- const astSrc = join4(legacyPath, "ast-scan.json");
3213
- if (existsSync2(astSrc)) {
3214
- cpSync(astSrc, join4(newPath, "ast-scan.json"));
3215
- migrated++;
3216
- }
3217
- success(`Migrated ${migrated} item(s) from ${LEGACY_DIR}/ to ${CONFIG_DIR}/`);
3218
- if (!nonInteractive) {
3219
- const remove = await dist_default({
3220
- message: `Remove old ${LEGACY_DIR}/ directory?`,
3221
- default: false
3222
- });
3223
- if (remove) {
3224
- rmSync(legacyPath, { recursive: true, force: true });
3225
- success(`Removed ${LEGACY_DIR}/`);
3226
- }
3227
- }
3228
- return true;
3229
- } catch (err) {
3230
- warn(`Migration from ${LEGACY_DIR}/ failed: ${err instanceof Error ? err.message : err}`);
3231
- warn(`Continuing with fresh initialization...
3232
- `);
3233
- return false;
3234
- }
3235
- }
3236
-
3237
- // src/commands/init.ts
3238
3327
  var SKILLS_TARGET_BASE = ".claude/skills";
3239
3328
  var SKILL_DIRS = ["zefiro", "zefiro-copilot"];
3240
3329
  function registerInit(program2) {
@@ -3244,7 +3333,6 @@ function registerInit(program2) {
3244
3333
  const packageRoot = getPackageRoot();
3245
3334
  const nonInteractive = !!cmdOpts?.nonInteractive;
3246
3335
  header("zefiro init");
3247
- await migrateFromLegacy(projectRoot, nonInteractive);
3248
3336
  const qaiDir = join5(projectRoot, CONFIG_DIR);
3249
3337
  const isReInit = existsSync3(qaiDir);
3250
3338
  if (isReInit) {
@@ -3288,11 +3376,11 @@ function getDefaultAnswers() {
3288
3376
  async function askConfigQuestions() {
3289
3377
  info(`Configure your zefiro setup:
3290
3378
  `);
3291
- const baseUrl = await dist_default2({
3379
+ const baseUrl = await dist_default({
3292
3380
  message: "Application base URL (e.g., http://localhost:3000)",
3293
3381
  default: process.env.QAI_BASE_URL ?? ""
3294
3382
  });
3295
- const authMethod = await dist_default3({
3383
+ const authMethod = await dist_default2({
3296
3384
  message: "Authentication method",
3297
3385
  choices: [
3298
3386
  { name: "Manual (authenticate in headed browser)", value: "manual" },
@@ -3300,7 +3388,7 @@ async function askConfigQuestions() {
3300
3388
  ],
3301
3389
  default: "manual"
3302
3390
  });
3303
- const outputDir = await dist_default2({
3391
+ const outputDir = await dist_default({
3304
3392
  message: "Output directory for exploration results",
3305
3393
  default: "app-report"
3306
3394
  });
@@ -3383,7 +3471,7 @@ async function copySkillsToLocal(projectRoot, packageRoot, nonInteractive) {
3383
3471
  }
3384
3472
  function collectMarkdownFiles(dir, baseDir) {
3385
3473
  const results = [];
3386
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
3474
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
3387
3475
  const fullPath = join5(dir, entry.name);
3388
3476
  if (entry.isDirectory()) {
3389
3477
  results.push(...collectMarkdownFiles(fullPath, baseDir));
@@ -3408,17 +3496,7 @@ program2.name("zefiro").description("AI-powered application explorer and documen
3408
3496
  });
3409
3497
  registerInit(program2);
3410
3498
  registerExplore(program2);
3499
+ registerPush(program2);
3411
3500
  registerAuth(program2);
3412
3501
  registerMcp(program2);
3413
- var userArgs = process.argv.slice(2);
3414
- var commandNames = program2.commands.map((c) => c.name());
3415
- var hasCommand = userArgs.some((a) => commandNames.includes(a));
3416
- var hasFlags = userArgs.some((a) => a.startsWith("-"));
3417
- var cols = process.stdout.columns || 80;
3418
- var rows = process.stdout.rows || 24;
3419
- if (!hasCommand && !hasFlags && process.stdout.isTTY && cols >= 60 && rows >= 20) {
3420
- const { launchTui } = await import("./App-bh752tgg.js");
3421
- await launchTui(program2);
3422
- } else {
3423
- program2.parse();
3424
- }
3502
+ program2.parse();
@@ -0,0 +1,11 @@
1
+ import {
2
+ runExploration
3
+ } from "./cli-7hvj61ht.js";
4
+ import"./cli-b26q1e27.js";
5
+ import"./cli-kjyet1n8.js";
6
+ import"./cli-zvk8gwe4.js";
7
+ import"./cli-5w708rbb.js";
8
+ import"./cli-wckvcay0.js";
9
+ export {
10
+ runExploration
11
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ runExploration
3
+ } from "./cli-m1ghts25.js";
4
+ import"./cli-b26q1e27.js";
5
+ import"./cli-6qr9gvkp.js";
6
+ import"./cli-zvk8gwe4.js";
7
+ import"./cli-wckvcay0.js";
8
+ export {
9
+ runExploration
10
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ buildReportGraph,
3
+ buildReportSections
4
+ } from "./cli-ewbvvxm8.js";
5
+ import"./cli-5w708rbb.js";
6
+ import"./cli-wckvcay0.js";
7
+ export {
8
+ buildReportSections,
9
+ buildReportGraph
10
+ };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  getPackageRoot,
4
4
  getProjectRoot,
5
5
  loadConfig
6
- } from "./cli-cymqw41r.js";
6
+ } from "./cli-mm7ct90g.js";
7
7
  import"./cli-z2krvkcq.js";
8
8
  import"./cli-wckvcay0.js";
9
9
  export {