@reshotdev/screenshot 0.0.1-beta.2 → 0.0.1-beta.6
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 +2 -2
- package/package.json +9 -2
- package/src/commands/auth.js +1 -3
- package/src/commands/ci-setup.js +2 -2
- package/src/commands/drifts.js +5 -70
- package/src/commands/import-tests.js +13 -13
- package/src/commands/ingest.js +10 -10
- package/src/commands/init.js +16 -277
- package/src/commands/publish.js +3 -204
- package/src/commands/pull.js +2 -2
- package/src/commands/setup-wizard.js +123 -523
- package/src/commands/setup.js +7 -7
- package/src/commands/status.js +26 -43
- package/src/commands/sync.js +28 -236
- package/src/commands/ui.js +1 -1
- package/src/index.js +9 -90
- package/src/lib/api-client.js +8 -8
- package/src/lib/capture-engine.js +3 -3
- package/src/lib/capture-script-runner.js +27 -37
- package/src/lib/config.js +8 -72
- package/src/lib/record-config.js +1 -1
- package/src/lib/standalone-mode.js +1 -1
- package/src/lib/storage-providers.js +4 -4
- package/src/lib/ui-api.js +3 -3
- package/web/manager/dist/assets/{index--ZgioErz.js → index-8H7P9ANi.js} +1 -1
- package/web/manager/dist/index.html +1 -1
- package/src/commands/validate-docs.js +0 -529
|
@@ -1,42 +1,11 @@
|
|
|
1
|
-
// setup-wizard.js -
|
|
2
|
-
//
|
|
3
|
-
// Individual commands (auth, init) still exist for power users
|
|
1
|
+
// setup-wizard.js - Interactive setup wizard
|
|
2
|
+
// Streamlined flow: auth + config + studio launch
|
|
4
3
|
|
|
5
4
|
const inquirer = require("inquirer");
|
|
6
5
|
const chalk = require("chalk");
|
|
7
6
|
const fs = require("fs-extra");
|
|
8
7
|
const path = require("path");
|
|
9
8
|
const config = require("../lib/config");
|
|
10
|
-
const {
|
|
11
|
-
validateStorageConfig,
|
|
12
|
-
getStorageSetupHelp,
|
|
13
|
-
} = require("../lib/storage-providers");
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Auto-detect documentation directories
|
|
17
|
-
*/
|
|
18
|
-
function detectDocumentationRoot() {
|
|
19
|
-
const commonPaths = [
|
|
20
|
-
"docs",
|
|
21
|
-
"documentation",
|
|
22
|
-
"content",
|
|
23
|
-
"doc",
|
|
24
|
-
"guides",
|
|
25
|
-
".vitepress/content",
|
|
26
|
-
".docusaurus/docs",
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
for (const dir of commonPaths) {
|
|
30
|
-
const fullPath = path.join(process.cwd(), dir);
|
|
31
|
-
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
|
|
32
|
-
const files = fs.readdirSync(fullPath);
|
|
33
|
-
if (files.some((f) => f.endsWith(".md") || f.endsWith(".mdx"))) {
|
|
34
|
-
return dir;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
9
|
|
|
41
10
|
/**
|
|
42
11
|
* Detect if this is a Git repository and if it's GitHub
|
|
@@ -91,184 +60,16 @@ function detectPlaywright() {
|
|
|
91
60
|
return { hasPlaywright: false, configFile: null };
|
|
92
61
|
}
|
|
93
62
|
|
|
94
|
-
/**
|
|
95
|
-
* Generate documentation block configuration
|
|
96
|
-
*/
|
|
97
|
-
function generateDocumentationConfig(root = "./docs", strategy = "git_pr") {
|
|
98
|
-
return {
|
|
99
|
-
root,
|
|
100
|
-
include: ["**/*.md", "**/*.mdx"],
|
|
101
|
-
exclude: ["**/_*.mdx", "**/node_modules/**", "**/.next/**"],
|
|
102
|
-
strategy,
|
|
103
|
-
assetFormat: "markdown",
|
|
104
|
-
mappings: {},
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Scaffold a basic documentation structure
|
|
110
|
-
*/
|
|
111
|
-
async function scaffoldDocumentation(template = "basic") {
|
|
112
|
-
const docsDir = path.join(process.cwd(), "docs");
|
|
113
|
-
fs.ensureDirSync(docsDir);
|
|
114
|
-
|
|
115
|
-
const readmeContent = `# Documentation
|
|
116
|
-
|
|
117
|
-
This directory contains documentation for your project.
|
|
118
|
-
|
|
119
|
-
## Linking Docs to Visual Journeys
|
|
120
|
-
|
|
121
|
-
Add \`reshot_journey\` frontmatter to your markdown files to link them to Playwright test captures:
|
|
122
|
-
|
|
123
|
-
\`\`\`markdown
|
|
124
|
-
---
|
|
125
|
-
title: "Feature Name"
|
|
126
|
-
reshot_journey: "feature/workflow-name"
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
# Feature Documentation
|
|
130
|
-
|
|
131
|
-
Your content here...
|
|
132
|
-
\`\`\`
|
|
133
|
-
|
|
134
|
-
The journey key should match your Playwright test structure. For example:
|
|
135
|
-
- Test file: \`tests/01-auth-flows.spec.ts\` with "Login Flow" describe block
|
|
136
|
-
- Journey key: \`auth-flows/login-flow\`
|
|
137
|
-
|
|
138
|
-
## Commands
|
|
139
|
-
|
|
140
|
-
- \`reshot import-tests\` - Import existing Playwright tests
|
|
141
|
-
- \`reshot sync\` - Sync visuals and documentation
|
|
142
|
-
- \`reshot status\` - View sync status and drifts
|
|
143
|
-
- \`reshot validate\` - Validate configuration
|
|
144
|
-
- \`reshot studio\` - Open visual management UI
|
|
145
|
-
|
|
146
|
-
For more information, visit: https://docs.reshot.dev
|
|
147
|
-
`;
|
|
148
|
-
|
|
149
|
-
fs.writeFileSync(path.join(docsDir, "README.md"), readmeContent);
|
|
150
|
-
|
|
151
|
-
const exampleContent = `---
|
|
152
|
-
title: "Getting Started"
|
|
153
|
-
reshot_journey: "onboarding/first-steps"
|
|
154
|
-
description: "Quick start guide for new users"
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
# Getting Started
|
|
158
|
-
|
|
159
|
-
Welcome! This is an example documentation file linked to the \`onboarding/first-steps\` journey.
|
|
160
|
-
|
|
161
|
-
## Overview
|
|
162
|
-
|
|
163
|
-
When Reshot detects UI changes in your Playwright tests, it will automatically propose updates to this document with new screenshots and descriptions.
|
|
164
|
-
|
|
165
|
-
## Steps
|
|
166
|
-
|
|
167
|
-
1. **Step 1**: Description of first step
|
|
168
|
-
|
|
169
|
-
<!-- Reshot will inject screenshots here when visual drift is detected -->
|
|
170
|
-
|
|
171
|
-
2. **Step 2**: Description of second step
|
|
172
|
-
|
|
173
|
-
3. **Step 3**: Description of third step
|
|
174
|
-
|
|
175
|
-
## Next Steps
|
|
176
|
-
|
|
177
|
-
- Link more documents to journeys
|
|
178
|
-
- Run \`reshot sync\` to upload traces
|
|
179
|
-
- Check \`reshot status\` for drift notifications
|
|
180
|
-
`;
|
|
181
|
-
|
|
182
|
-
fs.writeFileSync(path.join(docsDir, "getting-started.md"), exampleContent);
|
|
183
|
-
return "docs";
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Check if a documentation framework is already set up
|
|
188
|
-
*/
|
|
189
|
-
function detectDocumentationFramework() {
|
|
190
|
-
const frameworks = [
|
|
191
|
-
{
|
|
192
|
-
name: "Astro/Starlight",
|
|
193
|
-
files: ["astro.config.mjs", "astro.config.ts"],
|
|
194
|
-
deps: ["@astrojs/starlight"],
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
name: "Docusaurus",
|
|
198
|
-
files: ["docusaurus.config.js", "docusaurus.config.ts"],
|
|
199
|
-
deps: ["@docusaurus/core"],
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
name: "VitePress",
|
|
203
|
-
files: [".vitepress/config.js", ".vitepress/config.ts"],
|
|
204
|
-
deps: ["vitepress"],
|
|
205
|
-
},
|
|
206
|
-
{ name: "Mintlify", files: ["mint.json"], deps: [] },
|
|
207
|
-
{ name: "GitBook", files: [".gitbook.yaml"], deps: [] },
|
|
208
|
-
];
|
|
209
|
-
|
|
210
|
-
// Check for config files
|
|
211
|
-
for (const fw of frameworks) {
|
|
212
|
-
for (const file of fw.files) {
|
|
213
|
-
if (fs.existsSync(path.join(process.cwd(), file))) {
|
|
214
|
-
return { framework: fw.name, detected: true };
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Check package.json for deps
|
|
220
|
-
try {
|
|
221
|
-
const pkg = fs.readJsonSync(path.join(process.cwd(), "package.json"));
|
|
222
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
223
|
-
|
|
224
|
-
for (const fw of frameworks) {
|
|
225
|
-
for (const dep of fw.deps) {
|
|
226
|
-
if (allDeps[dep]) {
|
|
227
|
-
return { framework: fw.name, detected: true };
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
} catch {
|
|
232
|
-
// No package.json
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return { framework: null, detected: false };
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Count documentation files in a directory
|
|
240
|
-
*/
|
|
241
|
-
function countDocFiles(dir) {
|
|
242
|
-
if (!fs.existsSync(dir)) return 0;
|
|
243
|
-
|
|
244
|
-
let count = 0;
|
|
245
|
-
function walk(d) {
|
|
246
|
-
for (const item of fs.readdirSync(d)) {
|
|
247
|
-
const full = path.join(d, item);
|
|
248
|
-
if (fs.statSync(full).isDirectory()) {
|
|
249
|
-
if (!item.startsWith(".") && item !== "node_modules") walk(full);
|
|
250
|
-
} else if (item.endsWith(".md") || item.endsWith(".mdx")) {
|
|
251
|
-
count++;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
walk(dir);
|
|
256
|
-
return count;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
63
|
/**
|
|
260
64
|
* Main setup wizard
|
|
261
65
|
*/
|
|
262
66
|
async function setupWizard(options = {}) {
|
|
263
67
|
const { offline = false, force = false } = options;
|
|
264
68
|
|
|
265
|
-
console.log(chalk.cyan.bold("\n🚀 Reshot Setup
|
|
266
|
-
console.log(chalk.gray("Let's configure Reshot for your project.\n"));
|
|
69
|
+
console.log(chalk.cyan.bold("\n🚀 Reshot Setup\n"));
|
|
267
70
|
|
|
268
71
|
// Detect project context
|
|
269
|
-
const gitInfo = detectGitInfo();
|
|
270
72
|
const playwrightInfo = detectPlaywright();
|
|
271
|
-
const existingDocsRoot = detectDocumentationRoot();
|
|
272
73
|
|
|
273
74
|
// Check existing setup
|
|
274
75
|
let existingSettings = null;
|
|
@@ -292,7 +93,7 @@ async function setupWizard(options = {}) {
|
|
|
292
93
|
// No existing config
|
|
293
94
|
}
|
|
294
95
|
|
|
295
|
-
// If already set up and not forcing,
|
|
96
|
+
// If already set up and not forcing, show status and offer options
|
|
296
97
|
if ((isAlreadyAuthed || existingConfig) && !force) {
|
|
297
98
|
console.log(
|
|
298
99
|
chalk.yellow("⚠ Reshot is already configured in this project.\n"),
|
|
@@ -307,20 +108,39 @@ async function setupWizard(options = {}) {
|
|
|
307
108
|
if (existingConfig) {
|
|
308
109
|
console.log(
|
|
309
110
|
chalk.green(" ✔ Config found:"),
|
|
310
|
-
chalk.cyan("
|
|
111
|
+
chalk.cyan("reshot.config.json"),
|
|
311
112
|
);
|
|
312
113
|
}
|
|
313
114
|
|
|
314
|
-
const
|
|
115
|
+
const choices = [];
|
|
116
|
+
|
|
117
|
+
if (isAlreadyAuthed) {
|
|
118
|
+
choices.push({
|
|
119
|
+
name: "Re-authenticate (connect to a different project)",
|
|
120
|
+
value: "reauth",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
choices.push({
|
|
125
|
+
name: "Reconfigure (regenerate reshot.config.json)",
|
|
126
|
+
value: "reconfig",
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
choices.push({
|
|
130
|
+
name: "Exit",
|
|
131
|
+
value: "exit",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const { action } = await inquirer.prompt([
|
|
315
135
|
{
|
|
316
|
-
type: "
|
|
317
|
-
name: "
|
|
318
|
-
message: "
|
|
319
|
-
|
|
136
|
+
type: "list",
|
|
137
|
+
name: "action",
|
|
138
|
+
message: "What would you like to do?",
|
|
139
|
+
choices,
|
|
320
140
|
},
|
|
321
141
|
]);
|
|
322
142
|
|
|
323
|
-
if (
|
|
143
|
+
if (action === "exit") {
|
|
324
144
|
console.log(
|
|
325
145
|
chalk.gray("\nRun"),
|
|
326
146
|
chalk.cyan("reshot studio"),
|
|
@@ -328,19 +148,47 @@ async function setupWizard(options = {}) {
|
|
|
328
148
|
);
|
|
329
149
|
return;
|
|
330
150
|
}
|
|
151
|
+
|
|
152
|
+
if (action === "reauth") {
|
|
153
|
+
console.log(chalk.gray("\nOpening browser for authentication...\n"));
|
|
154
|
+
const authCommand = require("./auth");
|
|
155
|
+
await authCommand();
|
|
156
|
+
|
|
157
|
+
// Re-read settings after auth
|
|
158
|
+
try {
|
|
159
|
+
existingSettings = config.readSettings();
|
|
160
|
+
isAlreadyAuthed = !!(
|
|
161
|
+
existingSettings?.apiKey && existingSettings?.projectId
|
|
162
|
+
);
|
|
163
|
+
} catch {
|
|
164
|
+
throw new Error("Authentication failed. Please try again.");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!isAlreadyAuthed) {
|
|
168
|
+
throw new Error("Authentication was not completed.");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(
|
|
172
|
+
chalk.green("\n✔ Connected to"),
|
|
173
|
+
chalk.cyan(existingSettings.projectName || existingSettings.projectId),
|
|
174
|
+
);
|
|
175
|
+
console.log(
|
|
176
|
+
chalk.gray("\nRun"),
|
|
177
|
+
chalk.cyan("reshot studio"),
|
|
178
|
+
chalk.gray("to manage your visuals.\n"),
|
|
179
|
+
);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// action === "reconfig" — fall through to config generation below
|
|
331
184
|
}
|
|
332
185
|
|
|
333
186
|
// ========================================
|
|
334
187
|
// STEP 1: Platform Connection
|
|
335
188
|
// ========================================
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
let useCloud = false;
|
|
339
|
-
let projectId = existingSettings?.projectId;
|
|
340
|
-
let apiKey = existingSettings?.apiKey;
|
|
341
|
-
let projectName = existingSettings?.projectName;
|
|
189
|
+
if (!isAlreadyAuthed && !offline) {
|
|
190
|
+
console.log(chalk.cyan("\n━━━ Step 1: Platform Connection ━━━\n"));
|
|
342
191
|
|
|
343
|
-
if (!offline) {
|
|
344
192
|
const { connectToCloud } = await inquirer.prompt([
|
|
345
193
|
{
|
|
346
194
|
type: "list",
|
|
@@ -356,13 +204,10 @@ async function setupWizard(options = {}) {
|
|
|
356
204
|
value: false,
|
|
357
205
|
},
|
|
358
206
|
],
|
|
359
|
-
default: isAlreadyAuthed ? 0 : 1,
|
|
360
207
|
},
|
|
361
208
|
]);
|
|
362
209
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (useCloud && !isAlreadyAuthed) {
|
|
210
|
+
if (connectToCloud) {
|
|
366
211
|
console.log(chalk.gray("\nOpening browser for authentication...\n"));
|
|
367
212
|
|
|
368
213
|
const authCommand = require("./auth");
|
|
@@ -371,10 +216,9 @@ async function setupWizard(options = {}) {
|
|
|
371
216
|
// Re-read settings after auth
|
|
372
217
|
try {
|
|
373
218
|
existingSettings = config.readSettings();
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
isAlreadyAuthed = !!(apiKey && projectId);
|
|
219
|
+
isAlreadyAuthed = !!(
|
|
220
|
+
existingSettings?.apiKey && existingSettings?.projectId
|
|
221
|
+
);
|
|
378
222
|
} catch {
|
|
379
223
|
throw new Error("Authentication failed. Please try again.");
|
|
380
224
|
}
|
|
@@ -385,322 +229,90 @@ async function setupWizard(options = {}) {
|
|
|
385
229
|
|
|
386
230
|
console.log(
|
|
387
231
|
chalk.green("\n✔ Connected to"),
|
|
388
|
-
chalk.cyan(projectName || projectId),
|
|
389
|
-
);
|
|
390
|
-
} else if (useCloud && isAlreadyAuthed) {
|
|
391
|
-
console.log(
|
|
392
|
-
chalk.green("✔ Already connected to"),
|
|
393
|
-
chalk.cyan(projectName || projectId),
|
|
232
|
+
chalk.cyan(existingSettings.projectName || existingSettings.projectId),
|
|
394
233
|
);
|
|
234
|
+
} else {
|
|
235
|
+
console.log(chalk.gray("Running in offline mode — no cloud sync."));
|
|
395
236
|
}
|
|
396
|
-
} else {
|
|
397
|
-
console.log(chalk.gray("Running in offline mode
|
|
237
|
+
} else if (offline) {
|
|
238
|
+
console.log(chalk.gray("Running in offline mode — no cloud sync."));
|
|
398
239
|
}
|
|
399
240
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
// ========================================
|
|
403
|
-
console.log(chalk.cyan("\n━━━ Step 2: Features ━━━\n"));
|
|
404
|
-
|
|
405
|
-
const { features } = await inquirer.prompt([
|
|
406
|
-
{
|
|
407
|
-
type: "checkbox",
|
|
408
|
-
name: "features",
|
|
409
|
-
message: "Which features would you like to enable?",
|
|
410
|
-
choices: [
|
|
411
|
-
{
|
|
412
|
-
name: "Visual capture from Playwright tests",
|
|
413
|
-
value: "visuals",
|
|
414
|
-
checked: playwrightInfo.hasPlaywright,
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
name: "Documentation sync (detect drift, auto-update docs)",
|
|
418
|
-
value: "docsync",
|
|
419
|
-
checked: !!existingDocsRoot,
|
|
420
|
-
},
|
|
421
|
-
],
|
|
422
|
-
validate: (answers) => {
|
|
423
|
-
if (answers.length === 0) {
|
|
424
|
-
return "Please select at least one feature";
|
|
425
|
-
}
|
|
426
|
-
return true;
|
|
427
|
-
},
|
|
428
|
-
},
|
|
429
|
-
]);
|
|
430
|
-
|
|
431
|
-
const enableVisuals = features.includes("visuals");
|
|
432
|
-
const enableDocSync = features.includes("docsync");
|
|
241
|
+
const useCloud = isAlreadyAuthed;
|
|
242
|
+
const projectId = existingSettings?.projectId;
|
|
433
243
|
|
|
434
244
|
// ========================================
|
|
435
|
-
// STEP
|
|
245
|
+
// STEP 2: Visual Capture Configuration
|
|
436
246
|
// ========================================
|
|
437
|
-
|
|
438
|
-
let journeyMappings = {};
|
|
247
|
+
console.log(chalk.cyan("\n━━━ Visual Capture ━━━\n"));
|
|
439
248
|
|
|
440
|
-
|
|
441
|
-
console.log(chalk.cyan("\n━━━ Step 3: Visual Capture ━━━\n"));
|
|
442
|
-
|
|
443
|
-
if (playwrightInfo.hasPlaywright) {
|
|
444
|
-
console.log(chalk.green("✔ Playwright detected"));
|
|
445
|
-
if (playwrightInfo.configFile) {
|
|
446
|
-
console.log(chalk.gray(` Config: ${playwrightInfo.configFile}`));
|
|
447
|
-
}
|
|
249
|
+
let traceDir = "./test-results";
|
|
448
250
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
name: "importTests",
|
|
454
|
-
message:
|
|
455
|
-
"Import existing Playwright tests to create journey mappings?",
|
|
456
|
-
default: true,
|
|
457
|
-
},
|
|
458
|
-
]);
|
|
459
|
-
|
|
460
|
-
if (importTests) {
|
|
461
|
-
console.log(chalk.gray("\nScanning Playwright tests..."));
|
|
462
|
-
try {
|
|
463
|
-
const importTestsCommand = require("./import-tests");
|
|
464
|
-
const result = await importTestsCommand({
|
|
465
|
-
interactive: false,
|
|
466
|
-
dryRun: false,
|
|
467
|
-
});
|
|
468
|
-
if (result?.journeyMappings) {
|
|
469
|
-
journeyMappings = result.journeyMappings;
|
|
470
|
-
console.log(
|
|
471
|
-
chalk.green(
|
|
472
|
-
`✔ Imported ${Object.keys(journeyMappings).length} journey mapping(s)`,
|
|
473
|
-
),
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
} catch (err) {
|
|
477
|
-
console.log(chalk.yellow(`⚠ Could not import tests: ${err.message}`));
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
} else {
|
|
481
|
-
console.log(chalk.yellow("⚠ Playwright not detected"));
|
|
482
|
-
console.log(
|
|
483
|
-
chalk.gray(" Install with: npm install -D @playwright/test"),
|
|
484
|
-
);
|
|
251
|
+
if (playwrightInfo.hasPlaywright) {
|
|
252
|
+
console.log(chalk.green("✔ Playwright detected"));
|
|
253
|
+
if (playwrightInfo.configFile) {
|
|
254
|
+
console.log(chalk.gray(` Config: ${playwrightInfo.configFile}`));
|
|
485
255
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
message: "Playwright test-results directory:",
|
|
492
|
-
default: "./test-results",
|
|
493
|
-
},
|
|
494
|
-
]);
|
|
495
|
-
|
|
496
|
-
traceDir = customTraceDir;
|
|
256
|
+
} else {
|
|
257
|
+
console.log(chalk.yellow("⚠ Playwright not detected"));
|
|
258
|
+
console.log(
|
|
259
|
+
chalk.gray(" Install with: npm install -D @playwright/test"),
|
|
260
|
+
);
|
|
497
261
|
}
|
|
498
262
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// Check for existing documentation framework
|
|
508
|
-
const docFramework = detectDocumentationFramework();
|
|
509
|
-
let docsRoot = existingDocsRoot;
|
|
510
|
-
|
|
511
|
-
if (docFramework.detected) {
|
|
512
|
-
console.log(chalk.green(`✔ ${docFramework.framework} detected`));
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (docsRoot) {
|
|
516
|
-
const docCount = countDocFiles(path.join(process.cwd(), docsRoot));
|
|
517
|
-
console.log(
|
|
518
|
-
chalk.green(
|
|
519
|
-
`✔ Found documentation at: ${docsRoot}/ (${docCount} files)`,
|
|
520
|
-
),
|
|
521
|
-
);
|
|
522
|
-
|
|
523
|
-
const { useDetected } = await inquirer.prompt([
|
|
524
|
-
{
|
|
525
|
-
type: "confirm",
|
|
526
|
-
name: "useDetected",
|
|
527
|
-
message: `Use ${docsRoot}/ for documentation sync?`,
|
|
528
|
-
default: true,
|
|
529
|
-
},
|
|
530
|
-
]);
|
|
531
|
-
|
|
532
|
-
if (!useDetected) {
|
|
533
|
-
docsRoot = null;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (!docsRoot) {
|
|
538
|
-
const choices = [
|
|
539
|
-
{ name: "Create docs/ directory with examples", value: "scaffold" },
|
|
540
|
-
{ name: "Specify existing directory path", value: "specify" },
|
|
541
|
-
];
|
|
542
|
-
|
|
543
|
-
// Add Astro Starlight option if not already a docs framework
|
|
544
|
-
if (!docFramework.detected) {
|
|
545
|
-
choices.push({
|
|
546
|
-
name:
|
|
547
|
-
chalk.cyan("Create Astro Starlight project") +
|
|
548
|
-
chalk.gray(" (recommended for new docs)"),
|
|
549
|
-
value: "starlight",
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const { docAction } = await inquirer.prompt([
|
|
554
|
-
{
|
|
555
|
-
type: "list",
|
|
556
|
-
name: "docAction",
|
|
557
|
-
message: "Documentation setup:",
|
|
558
|
-
choices,
|
|
559
|
-
},
|
|
560
|
-
]);
|
|
561
|
-
|
|
562
|
-
if (docAction === "scaffold") {
|
|
563
|
-
console.log(chalk.gray("\nCreating docs/ directory..."));
|
|
564
|
-
docsRoot = await scaffoldDocumentation();
|
|
565
|
-
console.log(chalk.green("✔ Created docs/ with example files"));
|
|
566
|
-
} else if (docAction === "starlight") {
|
|
567
|
-
console.log(chalk.cyan("\nTo create an Astro Starlight project:\n"));
|
|
568
|
-
console.log(
|
|
569
|
-
chalk.white(" npm create astro@latest -- --template starlight"),
|
|
570
|
-
);
|
|
571
|
-
console.log(
|
|
572
|
-
chalk.gray(
|
|
573
|
-
"\nRun that command, then re-run reshot setup to link it.\n",
|
|
574
|
-
),
|
|
575
|
-
);
|
|
576
|
-
|
|
577
|
-
// Still create a basic docs folder as fallback
|
|
578
|
-
const { createBasic } = await inquirer.prompt([
|
|
579
|
-
{
|
|
580
|
-
type: "confirm",
|
|
581
|
-
name: "createBasic",
|
|
582
|
-
message: "Create a basic docs/ folder for now?",
|
|
583
|
-
default: true,
|
|
584
|
-
},
|
|
585
|
-
]);
|
|
586
|
-
|
|
587
|
-
if (createBasic) {
|
|
588
|
-
docsRoot = await scaffoldDocumentation();
|
|
589
|
-
console.log(chalk.green("✔ Created docs/ with example files"));
|
|
590
|
-
}
|
|
591
|
-
} else {
|
|
592
|
-
const { customPath } = await inquirer.prompt([
|
|
593
|
-
{
|
|
594
|
-
type: "input",
|
|
595
|
-
name: "customPath",
|
|
596
|
-
message: "Documentation directory path:",
|
|
597
|
-
default: "./docs",
|
|
598
|
-
validate: (input) => {
|
|
599
|
-
const fullPath = path.join(process.cwd(), input);
|
|
600
|
-
if (!fs.existsSync(fullPath)) {
|
|
601
|
-
return `Directory ${input} does not exist. Create it first or use scaffolding.`;
|
|
602
|
-
}
|
|
603
|
-
return true;
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
]);
|
|
607
|
-
docsRoot = customPath;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Determine strategy
|
|
612
|
-
let strategy = "git_pr";
|
|
613
|
-
|
|
614
|
-
if (useCloud && docsRoot) {
|
|
615
|
-
if (gitInfo.isGitHub) {
|
|
616
|
-
console.log(chalk.green("\n✔ GitHub repository detected"));
|
|
617
|
-
const { useGitPR } = await inquirer.prompt([
|
|
618
|
-
{
|
|
619
|
-
type: "confirm",
|
|
620
|
-
name: "useGitPR",
|
|
621
|
-
message: "Auto-create Pull Requests for documentation updates?",
|
|
622
|
-
default: true,
|
|
623
|
-
},
|
|
624
|
-
]);
|
|
625
|
-
strategy = useGitPR ? "git_pr" : "external_host";
|
|
626
|
-
} else {
|
|
627
|
-
const { strategyChoice } = await inquirer.prompt([
|
|
628
|
-
{
|
|
629
|
-
type: "list",
|
|
630
|
-
name: "strategyChoice",
|
|
631
|
-
message: "How should documentation updates be delivered?",
|
|
632
|
-
choices: [
|
|
633
|
-
{ name: "Git Pull Requests", value: "git_pr" },
|
|
634
|
-
{
|
|
635
|
-
name: "Notifications only (external CMS)",
|
|
636
|
-
value: "external_host",
|
|
637
|
-
},
|
|
638
|
-
],
|
|
639
|
-
},
|
|
640
|
-
]);
|
|
641
|
-
strategy = strategyChoice;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
263
|
+
const { customTraceDir } = await inquirer.prompt([
|
|
264
|
+
{
|
|
265
|
+
type: "input",
|
|
266
|
+
name: "customTraceDir",
|
|
267
|
+
message: "Playwright test-results directory:",
|
|
268
|
+
default: "./test-results",
|
|
269
|
+
},
|
|
270
|
+
]);
|
|
644
271
|
|
|
645
|
-
|
|
646
|
-
}
|
|
272
|
+
traceDir = customTraceDir;
|
|
647
273
|
|
|
648
274
|
// ========================================
|
|
649
|
-
//
|
|
275
|
+
// Generate Configuration
|
|
650
276
|
// ========================================
|
|
651
277
|
console.log(chalk.cyan("\n━━━ Generating Configuration ━━━\n"));
|
|
652
278
|
|
|
653
279
|
const newConfig = {
|
|
654
|
-
$schema: "https://reshot.dev/schemas/
|
|
280
|
+
$schema: "https://reshot.dev/schemas/reshot-config.json",
|
|
655
281
|
version: "2.0",
|
|
656
282
|
baseUrl: existingConfig?.baseUrl || "http://localhost:3000",
|
|
657
283
|
viewport: existingConfig?.viewport || { width: 1280, height: 720 },
|
|
658
|
-
_metadata: {
|
|
659
|
-
features: {
|
|
660
|
-
visuals: enableVisuals,
|
|
661
|
-
docsync: enableDocSync,
|
|
662
|
-
},
|
|
663
|
-
},
|
|
664
284
|
};
|
|
665
285
|
|
|
666
286
|
if (useCloud && projectId) {
|
|
667
287
|
newConfig.projectId = projectId;
|
|
668
288
|
}
|
|
669
289
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
journeyMappings:
|
|
674
|
-
Object.keys(journeyMappings).length > 0 ? journeyMappings : undefined,
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
if (!useCloud) {
|
|
678
|
-
const { customAssetDir } = await inquirer.prompt([
|
|
679
|
-
{
|
|
680
|
-
type: "input",
|
|
681
|
-
name: "customAssetDir",
|
|
682
|
-
message: "Where should screenshots be saved?",
|
|
683
|
-
default: ".reshot/output",
|
|
684
|
-
},
|
|
685
|
-
]);
|
|
686
|
-
newConfig.assetDir = customAssetDir;
|
|
687
|
-
} else {
|
|
688
|
-
newConfig.assetDir = ".reshot/output";
|
|
689
|
-
}
|
|
290
|
+
newConfig.visuals = {
|
|
291
|
+
traceDir,
|
|
292
|
+
};
|
|
690
293
|
|
|
691
|
-
|
|
294
|
+
if (!useCloud) {
|
|
295
|
+
const { customAssetDir } = await inquirer.prompt([
|
|
296
|
+
{
|
|
297
|
+
type: "input",
|
|
298
|
+
name: "customAssetDir",
|
|
299
|
+
message: "Where should screenshots be saved?",
|
|
300
|
+
default: ".reshot/output",
|
|
301
|
+
},
|
|
302
|
+
]);
|
|
303
|
+
newConfig.assetDir = customAssetDir;
|
|
304
|
+
} else {
|
|
305
|
+
newConfig.assetDir = ".reshot/output";
|
|
692
306
|
}
|
|
693
307
|
|
|
694
|
-
|
|
695
|
-
newConfig.documentation = docConfig;
|
|
696
|
-
}
|
|
308
|
+
newConfig.scenarios = existingConfig?.scenarios || [];
|
|
697
309
|
|
|
698
310
|
// Write configuration
|
|
699
311
|
config.writeConfig(newConfig);
|
|
700
|
-
console.log(chalk.green("✔ Created
|
|
312
|
+
console.log(chalk.green("✔ Created reshot.config.json"));
|
|
701
313
|
|
|
702
314
|
// ========================================
|
|
703
|
-
//
|
|
315
|
+
// Success & Next Steps
|
|
704
316
|
// ========================================
|
|
705
317
|
console.log(chalk.green("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
|
|
706
318
|
console.log(chalk.green.bold("✔ Reshot setup complete!"));
|
|
@@ -709,26 +321,14 @@ async function setupWizard(options = {}) {
|
|
|
709
321
|
console.log(chalk.cyan("Next steps:\n"));
|
|
710
322
|
|
|
711
323
|
console.log(
|
|
712
|
-
` 1. ${chalk.gray("Review")} ${chalk.cyan("
|
|
324
|
+
` 1. ${chalk.gray("Review")} ${chalk.cyan("reshot.config.json")} ${chalk.gray("and commit to your repo")}`,
|
|
713
325
|
);
|
|
326
|
+
console.log(
|
|
327
|
+
` 2. ${chalk.gray("Run Playwright tests to generate traces:")}`,
|
|
328
|
+
);
|
|
329
|
+
console.log(` ${chalk.cyan("npx playwright test")}`);
|
|
714
330
|
|
|
715
|
-
|
|
716
|
-
console.log(
|
|
717
|
-
` 2. ${chalk.gray("Run Playwright tests to generate traces:")}`,
|
|
718
|
-
);
|
|
719
|
-
console.log(` ${chalk.cyan("npx playwright test")}`);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
if (enableDocSync) {
|
|
723
|
-
console.log(
|
|
724
|
-
` ${enableVisuals ? "3" : "2"}. ${chalk.gray("Add")} ${chalk.cyan("reshot_journey")} ${chalk.gray("frontmatter to your markdown files")}`,
|
|
725
|
-
);
|
|
726
|
-
console.log(
|
|
727
|
-
` ${chalk.gray('Example: reshot_journey: "auth/login-flow"')}`,
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
console.log(`\n ${chalk.gray("Sync visuals and docs to Reshot:")}`);
|
|
331
|
+
console.log(`\n ${chalk.gray("Sync visuals to Reshot:")}`);
|
|
732
332
|
console.log(` ${chalk.cyan("reshot sync")}`);
|
|
733
333
|
|
|
734
334
|
console.log(`\n ${chalk.gray("Launch the visual management UI:")}`);
|