@wasao/kagemusha 0.1.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/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/commands/capture.d.ts +7 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +27 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +269 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/preview.d.ts +6 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +33 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/run.d.ts +6 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +39 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +53 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/annotate.d.ts +3 -0
- package/dist/lib/annotate.d.ts.map +1 -0
- package/dist/lib/annotate.js +102 -0
- package/dist/lib/annotate.js.map +1 -0
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +92 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crawl.d.ts +6 -0
- package/dist/lib/crawl.d.ts.map +1 -0
- package/dist/lib/crawl.js +95 -0
- package/dist/lib/crawl.js.map +1 -0
- package/dist/lib/screenshot.d.ts +3 -0
- package/dist/lib/screenshot.d.ts.map +1 -0
- package/dist/lib/screenshot.js +166 -0
- package/dist/lib/screenshot.js.map +1 -0
- package/dist/lib/upload.d.ts +9 -0
- package/dist/lib/upload.d.ts.map +1 -0
- package/dist/lib/upload.js +43 -0
- package/dist/lib/upload.js.map +1 -0
- package/dist/types.d.ts +168 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hideto Iwasawa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# kagemusha
|
|
2
|
+
|
|
3
|
+
Auto-update help center screenshots when your code changes.
|
|
4
|
+
The shadow warrior for your documentation.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
When you push code, Kagemusha automatically captures screenshots of your app and uploads them to S3. No more manually taking screenshots and updating help articles.
|
|
9
|
+
|
|
10
|
+
- **Auto-discover pages** — Crawls your app to find pages, select which ones to capture
|
|
11
|
+
- **Playwright-powered** — Supports login, click actions, element selection, and full-page capture
|
|
12
|
+
- **Annotations** — Add arrows, rectangles, and labels to screenshots
|
|
13
|
+
- **S3 upload** — Screenshots are uploaded with stable URLs for embedding in help centers
|
|
14
|
+
- **Local mode** — Save screenshots locally for review before uploading
|
|
15
|
+
- **GitHub Actions ready** — Runs on every merge to main
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Install
|
|
21
|
+
npm install -D kagemusha
|
|
22
|
+
|
|
23
|
+
# Interactive setup (generates config, discovers pages, creates workflow)
|
|
24
|
+
npx kagemusha init
|
|
25
|
+
|
|
26
|
+
# Preview screenshots locally
|
|
27
|
+
npx kagemusha preview
|
|
28
|
+
|
|
29
|
+
# Run full pipeline (capture → upload)
|
|
30
|
+
npx kagemusha run
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## How it works
|
|
34
|
+
|
|
35
|
+
1. `npx kagemusha init` scans your app and lets you pick which pages to screenshot
|
|
36
|
+
2. Config and definition files are generated in your repo
|
|
37
|
+
3. On every merge to main, GitHub Actions runs `npx kagemusha run`
|
|
38
|
+
4. Screenshots are captured and uploaded to S3
|
|
39
|
+
5. Help center articles reference the S3 URLs — images stay up to date automatically
|
|
40
|
+
|
|
41
|
+
## Commands
|
|
42
|
+
|
|
43
|
+
| Command | Description |
|
|
44
|
+
|---------|-------------|
|
|
45
|
+
| `kagemusha init` | Interactive setup |
|
|
46
|
+
| `kagemusha run` | Full pipeline: capture + upload |
|
|
47
|
+
| `kagemusha capture` | Capture screenshots only |
|
|
48
|
+
| `kagemusha preview` | Preview in browser |
|
|
49
|
+
| `kagemusha validate` | Validate config files |
|
|
50
|
+
| `kagemusha compare` | VRT diff detection (coming soon) |
|
|
51
|
+
| `kagemusha publish` | Publish to Intercom/Zendesk (coming soon) |
|
|
52
|
+
|
|
53
|
+
## Config
|
|
54
|
+
|
|
55
|
+
`kagemusha init` generates these files:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
kagemusha.config.yaml # App URL, auth, save destination
|
|
59
|
+
.kagemusha/definitions/*.json # One file per screenshot
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Screenshot definition example
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"id": "dashboard",
|
|
67
|
+
"name": "dashboard",
|
|
68
|
+
"url": "/dashboard",
|
|
69
|
+
"capture": { "mode": "fullPage" },
|
|
70
|
+
"hideElements": [".intercom-launcher"],
|
|
71
|
+
"decorations": [
|
|
72
|
+
{
|
|
73
|
+
"type": "rect",
|
|
74
|
+
"target": { "x": 32, "y": 120, "width": 310, "height": 120 },
|
|
75
|
+
"style": { "color": "#FF0000", "strokeWidth": 2 }
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## GitHub Actions
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
name: Kagemusha
|
|
85
|
+
on:
|
|
86
|
+
pull_request:
|
|
87
|
+
types: [closed]
|
|
88
|
+
branches: [main]
|
|
89
|
+
|
|
90
|
+
jobs:
|
|
91
|
+
screenshots:
|
|
92
|
+
if: github.event.pull_request.merged == true
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
steps:
|
|
95
|
+
- uses: actions/checkout@v4
|
|
96
|
+
- uses: actions/setup-node@v4
|
|
97
|
+
with:
|
|
98
|
+
node-version: 20
|
|
99
|
+
- run: npm ci
|
|
100
|
+
- run: npx kagemusha run
|
|
101
|
+
env:
|
|
102
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
103
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Try it locally
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd example
|
|
110
|
+
bun install
|
|
111
|
+
bun run serve # Start sample app
|
|
112
|
+
bunx kagemusha init # Set up kagemusha
|
|
113
|
+
bunx kagemusha preview # See screenshots
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Roadmap
|
|
117
|
+
|
|
118
|
+
- [x] Screenshot capture with Playwright
|
|
119
|
+
- [x] Annotations (rect, arrow, label)
|
|
120
|
+
- [x] S3 upload
|
|
121
|
+
- [x] Auto-discover pages
|
|
122
|
+
- [ ] Visual regression testing (VRT)
|
|
123
|
+
- [ ] Intercom / Zendesk integration
|
|
124
|
+
- [ ] AI-powered text updates
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;CACd;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC3E"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { annotateScreenshots } from "../lib/annotate.js";
|
|
3
|
+
import { findProjectRoot, loadConfig, loadDefinitions } from "../lib/config.js";
|
|
4
|
+
import { captureScreenshots } from "../lib/screenshot.js";
|
|
5
|
+
export async function captureCommand(options) {
|
|
6
|
+
console.log(chalk.bold("\n🥷 Kagemusha — Capture screenshots\n"));
|
|
7
|
+
const projectRoot = findProjectRoot();
|
|
8
|
+
const config = loadConfig(projectRoot);
|
|
9
|
+
let definitions = loadDefinitions(projectRoot);
|
|
10
|
+
if (options.ids) {
|
|
11
|
+
const ids = options.ids.split(",").map((s) => s.trim());
|
|
12
|
+
definitions = definitions.filter((d) => ids.includes(d.id));
|
|
13
|
+
}
|
|
14
|
+
if (definitions.length === 0) {
|
|
15
|
+
console.log(chalk.yellow("No screenshot definitions found."));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.log(chalk.blue(`📸 Capturing ${definitions.length} screenshot(s)...`));
|
|
19
|
+
const results = await captureScreenshots(config, definitions, projectRoot);
|
|
20
|
+
console.log(chalk.blue("🎨 Drawing annotations..."));
|
|
21
|
+
await annotateScreenshots(definitions, results, projectRoot);
|
|
22
|
+
console.log(chalk.bold.green(`\n✅ Done! Screenshots saved to screenshots/\n`));
|
|
23
|
+
for (const r of results) {
|
|
24
|
+
console.log(chalk.gray(` ${r.id} → ${r.rawPath}`));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/commands/capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAO1D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;IAElE,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE/C,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACxD,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAC9D,OAAO;IACR,CAAC;IAED,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,CAAC,gBAAgB,WAAW,CAAC,MAAM,mBAAmB,CAAC,CACjE,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAE3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACrD,MAAM,mBAAmB,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAE7D,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,+CAA+C,CAAC,CACjE,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwQjD"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import inquirer from "inquirer";
|
|
5
|
+
import { stringify as toYaml } from "yaml";
|
|
6
|
+
import { discoverPages } from "../lib/crawl.js";
|
|
7
|
+
export async function initCommand() {
|
|
8
|
+
console.log(chalk.bold("\n🥷 Kagemusha — Setup\n"));
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
if (fs.existsSync(path.join(cwd, "kagemusha.config.yaml"))) {
|
|
11
|
+
const { overwrite } = await inquirer.prompt({
|
|
12
|
+
type: "confirm",
|
|
13
|
+
name: "overwrite",
|
|
14
|
+
message: "kagemusha.config.yaml already exists. Overwrite?",
|
|
15
|
+
default: false,
|
|
16
|
+
});
|
|
17
|
+
if (!overwrite) {
|
|
18
|
+
console.log(chalk.yellow("Aborted."));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Step 1: Basic config
|
|
23
|
+
const { baseUrl } = await inquirer.prompt({
|
|
24
|
+
type: "input",
|
|
25
|
+
name: "baseUrl",
|
|
26
|
+
message: "Target URL (the app to take screenshots of):",
|
|
27
|
+
default: "http://localhost:3000",
|
|
28
|
+
});
|
|
29
|
+
const { needsAuth } = await inquirer.prompt({
|
|
30
|
+
type: "confirm",
|
|
31
|
+
name: "needsAuth",
|
|
32
|
+
message: "Does the app require login?",
|
|
33
|
+
default: true,
|
|
34
|
+
});
|
|
35
|
+
let loginUrl = "/login";
|
|
36
|
+
let emailSelector = "#email";
|
|
37
|
+
let passwordSelector = "#password";
|
|
38
|
+
let submitSelector = "button[type='submit']";
|
|
39
|
+
if (needsAuth) {
|
|
40
|
+
const authAnswers = await inquirer.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: "input",
|
|
43
|
+
name: "loginUrl",
|
|
44
|
+
message: "Login page path:",
|
|
45
|
+
default: "/login",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "input",
|
|
49
|
+
name: "emailSelector",
|
|
50
|
+
message: "Email input selector:",
|
|
51
|
+
default: "#email",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: "input",
|
|
55
|
+
name: "passwordSelector",
|
|
56
|
+
message: "Password input selector:",
|
|
57
|
+
default: "#password",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: "input",
|
|
61
|
+
name: "submitSelector",
|
|
62
|
+
message: "Login button selector:",
|
|
63
|
+
default: "button[type='submit']",
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
loginUrl = authAnswers.loginUrl;
|
|
67
|
+
emailSelector = authAnswers.emailSelector;
|
|
68
|
+
passwordSelector = authAnswers.passwordSelector;
|
|
69
|
+
submitSelector = authAnswers.submitSelector;
|
|
70
|
+
}
|
|
71
|
+
const { destination } = await inquirer.prompt({
|
|
72
|
+
type: "list",
|
|
73
|
+
name: "destination",
|
|
74
|
+
message: "Where to save screenshots?",
|
|
75
|
+
choices: [
|
|
76
|
+
{ name: "Local (./screenshots)", value: "local" },
|
|
77
|
+
{ name: "S3", value: "s3" },
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
let outputDir = "./screenshots";
|
|
81
|
+
let cdnBucket = "";
|
|
82
|
+
let cdnBaseUrl = "";
|
|
83
|
+
if (destination === "local") {
|
|
84
|
+
const { dir } = await inquirer.prompt({
|
|
85
|
+
type: "input",
|
|
86
|
+
name: "dir",
|
|
87
|
+
message: "Output directory for screenshots:",
|
|
88
|
+
default: "./screenshots",
|
|
89
|
+
});
|
|
90
|
+
outputDir = dir;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const s3Answers = await inquirer.prompt([
|
|
94
|
+
{
|
|
95
|
+
type: "input",
|
|
96
|
+
name: "cdnBucket",
|
|
97
|
+
message: "S3 bucket name:",
|
|
98
|
+
default: "kagemusha-screenshots",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: "input",
|
|
102
|
+
name: "cdnBaseUrl",
|
|
103
|
+
message: "S3 public URL base:",
|
|
104
|
+
default: "https://kagemusha-screenshots.s3.ap-northeast-1.amazonaws.com",
|
|
105
|
+
},
|
|
106
|
+
]);
|
|
107
|
+
cdnBucket = s3Answers.cdnBucket;
|
|
108
|
+
cdnBaseUrl = s3Answers.cdnBaseUrl;
|
|
109
|
+
}
|
|
110
|
+
// Build config
|
|
111
|
+
const config = {
|
|
112
|
+
app: { baseUrl },
|
|
113
|
+
screenshot: {
|
|
114
|
+
defaultViewport: { width: 1280, height: 720, deviceScaleFactor: 2 },
|
|
115
|
+
defaultDiffThreshold: 0.5,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
if (destination === "local") {
|
|
119
|
+
config.publish = {
|
|
120
|
+
destination: "local",
|
|
121
|
+
outputDir,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
config.publish = {
|
|
126
|
+
destination: "s3",
|
|
127
|
+
cdnBucket,
|
|
128
|
+
cdnBaseUrl,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (needsAuth) {
|
|
132
|
+
config.auth = {
|
|
133
|
+
loginUrl,
|
|
134
|
+
steps: [
|
|
135
|
+
{
|
|
136
|
+
action: "type",
|
|
137
|
+
selector: emailSelector,
|
|
138
|
+
text: "${KAGEMUSHA_DEMO_EMAIL}",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
action: "type",
|
|
142
|
+
selector: passwordSelector,
|
|
143
|
+
text: "${KAGEMUSHA_DEMO_PASSWORD}",
|
|
144
|
+
},
|
|
145
|
+
{ action: "click", selector: submitSelector },
|
|
146
|
+
{ action: "waitForNavigation" },
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// Write config
|
|
151
|
+
fs.writeFileSync(path.join(cwd, "kagemusha.config.yaml"), toYaml(config, { lineWidth: 120 }));
|
|
152
|
+
console.log(chalk.green("\n✓ Created kagemusha.config.yaml"));
|
|
153
|
+
// Step 2: Discover pages and create screenshot definitions
|
|
154
|
+
fs.mkdirSync(path.join(cwd, ".kagemusha/definitions"), { recursive: true });
|
|
155
|
+
console.log(chalk.blue(`\n🔍 Scanning ${baseUrl} for pages...\n`));
|
|
156
|
+
let pages = [];
|
|
157
|
+
try {
|
|
158
|
+
pages = await discoverPages(baseUrl);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
console.log(chalk.yellow(" Could not auto-discover pages.\n"));
|
|
162
|
+
}
|
|
163
|
+
let selectedPaths = [];
|
|
164
|
+
if (pages.length > 0) {
|
|
165
|
+
console.log(chalk.green(` Found ${pages.length} page(s)\n`));
|
|
166
|
+
const { selected } = await inquirer.prompt({
|
|
167
|
+
type: "checkbox",
|
|
168
|
+
name: "selected",
|
|
169
|
+
message: "Select pages to capture (space to toggle):",
|
|
170
|
+
choices: pages.map((p) => ({
|
|
171
|
+
name: `${p.path} ${chalk.gray(p.title)}`,
|
|
172
|
+
value: p.path,
|
|
173
|
+
checked: true,
|
|
174
|
+
})),
|
|
175
|
+
});
|
|
176
|
+
selectedPaths = selected;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.log(chalk.yellow(" No pages found. Add them manually.\n"));
|
|
180
|
+
let addMore = true;
|
|
181
|
+
while (addMore) {
|
|
182
|
+
const { manualPath } = await inquirer.prompt({
|
|
183
|
+
type: "input",
|
|
184
|
+
name: "manualPath",
|
|
185
|
+
message: "Page path (e.g. /index.html):",
|
|
186
|
+
});
|
|
187
|
+
selectedPaths.push(manualPath);
|
|
188
|
+
const { more } = await inquirer.prompt({
|
|
189
|
+
type: "confirm",
|
|
190
|
+
name: "more",
|
|
191
|
+
message: "Add another page?",
|
|
192
|
+
default: false,
|
|
193
|
+
});
|
|
194
|
+
addMore = more;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const pagePath of selectedPaths) {
|
|
198
|
+
const id = deriveIdFromPath(pagePath);
|
|
199
|
+
const definition = {
|
|
200
|
+
id,
|
|
201
|
+
name: id,
|
|
202
|
+
url: pagePath,
|
|
203
|
+
capture: { mode: "fullPage" },
|
|
204
|
+
hideElements: [],
|
|
205
|
+
decorations: [],
|
|
206
|
+
};
|
|
207
|
+
const defPath = path.join(cwd, ".kagemusha/definitions", `${id}.json`);
|
|
208
|
+
fs.writeFileSync(defPath, `${JSON.stringify(definition, null, 2)}\n`);
|
|
209
|
+
console.log(chalk.green(` ✓ ${id} → ${defPath}`));
|
|
210
|
+
}
|
|
211
|
+
console.log("");
|
|
212
|
+
// Step 3: GitHub Actions workflow
|
|
213
|
+
const { createWorkflow } = await inquirer.prompt({
|
|
214
|
+
type: "confirm",
|
|
215
|
+
name: "createWorkflow",
|
|
216
|
+
message: "Generate GitHub Actions workflow?",
|
|
217
|
+
default: true,
|
|
218
|
+
});
|
|
219
|
+
if (createWorkflow) {
|
|
220
|
+
const workflowDir = path.join(cwd, ".github/workflows");
|
|
221
|
+
fs.mkdirSync(workflowDir, { recursive: true });
|
|
222
|
+
fs.writeFileSync(path.join(workflowDir, "kagemusha.yml"), generateWorkflowTemplate());
|
|
223
|
+
console.log(chalk.green("✓ Created .github/workflows/kagemusha.yml"));
|
|
224
|
+
}
|
|
225
|
+
console.log(chalk.bold.green("\n✅ Setup complete!\n"));
|
|
226
|
+
console.log(chalk.gray("Next steps:"));
|
|
227
|
+
console.log(chalk.gray(" npx kagemusha preview — Preview screenshots locally"));
|
|
228
|
+
console.log(chalk.gray(" npx kagemusha validate — Validate config files"));
|
|
229
|
+
console.log(chalk.gray(" npx kagemusha run — Run full pipeline\n"));
|
|
230
|
+
}
|
|
231
|
+
function generateWorkflowTemplate() {
|
|
232
|
+
return `name: Kagemusha - Screenshot Update
|
|
233
|
+
|
|
234
|
+
on:
|
|
235
|
+
pull_request:
|
|
236
|
+
types: [closed]
|
|
237
|
+
branches: [main]
|
|
238
|
+
workflow_dispatch:
|
|
239
|
+
|
|
240
|
+
jobs:
|
|
241
|
+
update-screenshots:
|
|
242
|
+
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
|
243
|
+
runs-on: ubuntu-latest
|
|
244
|
+
steps:
|
|
245
|
+
- uses: actions/checkout@v4
|
|
246
|
+
with:
|
|
247
|
+
fetch-depth: 0
|
|
248
|
+
- uses: actions/setup-node@v4
|
|
249
|
+
with:
|
|
250
|
+
node-version: 20
|
|
251
|
+
- run: npm ci
|
|
252
|
+
- run: npx playwright install chromium
|
|
253
|
+
|
|
254
|
+
- run: npx kagemusha run
|
|
255
|
+
env:
|
|
256
|
+
KAGEMUSHA_DEMO_EMAIL: \${{ secrets.KAGEMUSHA_DEMO_EMAIL }}
|
|
257
|
+
KAGEMUSHA_DEMO_PASSWORD: \${{ secrets.KAGEMUSHA_DEMO_PASSWORD }}
|
|
258
|
+
AWS_ACCESS_KEY_ID: \${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
259
|
+
AWS_SECRET_ACCESS_KEY: \${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
function deriveIdFromPath(urlPath) {
|
|
263
|
+
return (urlPath
|
|
264
|
+
.replace(/^\//, "")
|
|
265
|
+
.replace(/\.\w+$/, "")
|
|
266
|
+
.replace(/[/\\]/g, "-")
|
|
267
|
+
.replace(/[^a-zA-Z0-9-]/g, "") || "page");
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC3E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { chromium } from "playwright-chromium";
|
|
3
|
+
import { annotateScreenshots } from "../lib/annotate.js";
|
|
4
|
+
import { findProjectRoot, loadConfig, loadDefinitions } from "../lib/config.js";
|
|
5
|
+
import { captureScreenshots } from "../lib/screenshot.js";
|
|
6
|
+
export async function previewCommand(options) {
|
|
7
|
+
console.log(chalk.bold("\n🥷 Kagemusha — Preview\n"));
|
|
8
|
+
const projectRoot = findProjectRoot();
|
|
9
|
+
const config = loadConfig(projectRoot);
|
|
10
|
+
let definitions = loadDefinitions(projectRoot);
|
|
11
|
+
if (options.id) {
|
|
12
|
+
definitions = definitions.filter((d) => d.id === options.id);
|
|
13
|
+
if (definitions.length === 0) {
|
|
14
|
+
console.log(chalk.red(`Definition not found: ${options.id}`));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
console.log(chalk.blue(`📸 Capturing ${definitions.length} screenshot(s)...`));
|
|
19
|
+
const results = await captureScreenshots(config, definitions, projectRoot);
|
|
20
|
+
const annotated = await annotateScreenshots(definitions, results, projectRoot);
|
|
21
|
+
console.log(chalk.green("\n✅ Screenshots captured. Opening preview...\n"));
|
|
22
|
+
// Open annotated screenshots in browser
|
|
23
|
+
const browser = await chromium.launch({ headless: false });
|
|
24
|
+
const context = await browser.newContext();
|
|
25
|
+
for (const result of annotated) {
|
|
26
|
+
const page = await context.newPage();
|
|
27
|
+
await page.goto(`file://${result.annotatedPath}`);
|
|
28
|
+
}
|
|
29
|
+
console.log(chalk.gray("Press Ctrl+C to close preview.\n"));
|
|
30
|
+
// Keep process alive until user closes
|
|
31
|
+
await new Promise(() => { });
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAM1D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAEtD,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAEvC,IAAI,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC9D,OAAO;QACR,CAAC;IACF,CAAC;IAED,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,CAAC,gBAAgB,WAAW,CAAC,MAAM,mBAAmB,CAAC,CACjE,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAC1C,WAAW,EACX,OAAO,EACP,WAAW,CACX,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC,CAAC;IAE3E,wCAAwC;IACxC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;IAE3C,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC,CAAC;IAE5D,uCAAuC;IACvC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAMA,UAAU,UAAU;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DnE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { annotateScreenshots } from "../lib/annotate.js";
|
|
3
|
+
import { findProjectRoot, loadConfig, loadDefinitions } from "../lib/config.js";
|
|
4
|
+
import { captureScreenshots } from "../lib/screenshot.js";
|
|
5
|
+
import { uploadToS3 } from "../lib/upload.js";
|
|
6
|
+
export async function runCommand(options) {
|
|
7
|
+
console.log(chalk.bold("\n🥷 Kagemusha — Running pipeline\n"));
|
|
8
|
+
const projectRoot = findProjectRoot();
|
|
9
|
+
const config = loadConfig(projectRoot);
|
|
10
|
+
let definitions = loadDefinitions(projectRoot);
|
|
11
|
+
if (options.ids) {
|
|
12
|
+
const ids = options.ids.split(",").map((s) => s.trim());
|
|
13
|
+
definitions = definitions.filter((d) => ids.includes(d.id));
|
|
14
|
+
}
|
|
15
|
+
if (definitions.length === 0) {
|
|
16
|
+
console.log(chalk.yellow("No screenshot definitions to process. Skipping."));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.log(chalk.gray(` Found ${definitions.length} definition(s) to process\n`));
|
|
20
|
+
// Step 1: Capture
|
|
21
|
+
console.log(chalk.blue("📸 Capturing screenshots..."));
|
|
22
|
+
const captureResults = await captureScreenshots(config, definitions, projectRoot);
|
|
23
|
+
console.log(chalk.green(` ✓ Captured ${captureResults.length} screenshot(s)\n`));
|
|
24
|
+
// Step 2: Annotate
|
|
25
|
+
console.log(chalk.blue("🎨 Drawing annotations..."));
|
|
26
|
+
const annotatedResults = await annotateScreenshots(definitions, captureResults, projectRoot);
|
|
27
|
+
console.log(chalk.green(` ✓ Annotated ${annotatedResults.length} screenshot(s)\n`));
|
|
28
|
+
// Step 3: Publish
|
|
29
|
+
if (config.publish?.destination === "s3") {
|
|
30
|
+
console.log(chalk.blue("☁️ Uploading to S3..."));
|
|
31
|
+
const uploadResults = await uploadToS3(config, annotatedResults, projectRoot);
|
|
32
|
+
console.log(chalk.green(` ✓ Uploaded ${uploadResults.length} screenshot(s)\n`));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log(chalk.green(` Screenshots saved locally\n`));
|
|
36
|
+
}
|
|
37
|
+
console.log(chalk.bold.green("✅ Pipeline complete!\n"));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAM9C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB;IACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAE/D,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE/C,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACxD,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,MAAM,CAAC,iDAAiD,CAAC,CAC/D,CAAC;QACF,OAAO;IACR,CAAC;IAED,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,CAAC,WAAW,WAAW,CAAC,MAAM,6BAA6B,CAAC,CACtE,CAAC;IAEF,kBAAkB;IAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAC9C,MAAM,EACN,WAAW,EACX,WAAW,CACX,CAAC;IACF,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,KAAK,CAAC,gBAAgB,cAAc,CAAC,MAAM,kBAAkB,CAAC,CACpE,CAAC;IAEF,mBAAmB;IACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;IACrD,MAAM,gBAAgB,GAAG,MAAM,mBAAmB,CACjD,WAAW,EACX,cAAc,EACd,WAAW,CACX,CAAC;IACF,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,KAAK,CAAC,iBAAiB,gBAAgB,CAAC,MAAM,kBAAkB,CAAC,CACvE,CAAC;IAEF,kBAAkB;IAClB,IAAI,MAAM,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,MAAM,UAAU,CACrC,MAAM,EACN,gBAAgB,EAChB,WAAW,CACX,CAAC;QACF,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,KAAK,CAAC,gBAAgB,aAAa,CAAC,MAAM,kBAAkB,CAAC,CACnE,CAAC;IACH,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AASA,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAwDrD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { findProjectRoot, loadConfig, loadDefinitions, validateConfig, validateDefinition, } from "../lib/config.js";
|
|
3
|
+
export async function validateCommand() {
|
|
4
|
+
console.log(chalk.bold("\n🥷 Kagemusha — Validate\n"));
|
|
5
|
+
let hasErrors = false;
|
|
6
|
+
try {
|
|
7
|
+
const projectRoot = findProjectRoot();
|
|
8
|
+
// Validate config
|
|
9
|
+
console.log(chalk.blue("Checking kagemusha.config.yaml..."));
|
|
10
|
+
const config = loadConfig(projectRoot);
|
|
11
|
+
const configErrors = validateConfig(config);
|
|
12
|
+
if (configErrors.length > 0) {
|
|
13
|
+
hasErrors = true;
|
|
14
|
+
for (const err of configErrors) {
|
|
15
|
+
console.log(chalk.red(` ✗ ${err}`));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(chalk.green(" ✓ Config is valid"));
|
|
20
|
+
}
|
|
21
|
+
// Validate definitions
|
|
22
|
+
const definitions = loadDefinitions(projectRoot);
|
|
23
|
+
console.log(chalk.blue(`\nChecking ${definitions.length} definition(s)...`));
|
|
24
|
+
for (const def of definitions) {
|
|
25
|
+
const errors = validateDefinition(def);
|
|
26
|
+
if (errors.length > 0) {
|
|
27
|
+
hasErrors = true;
|
|
28
|
+
console.log(chalk.red(` ✗ ${def.id ?? "(no id)"}`));
|
|
29
|
+
for (const err of errors) {
|
|
30
|
+
console.log(chalk.red(` - ${err}`));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(chalk.green(` ✓ ${def.id}`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (definitions.length === 0) {
|
|
38
|
+
console.log(chalk.yellow(" No definitions found in .kagemusha/definitions/"));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
hasErrors = true;
|
|
43
|
+
console.log(chalk.red(`\n✗ ${err.message}`));
|
|
44
|
+
}
|
|
45
|
+
if (hasErrors) {
|
|
46
|
+
console.log(chalk.red("\n❌ Validation failed\n"));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log(chalk.bold.green("\n✅ All checks passed!\n"));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACN,eAAe,EACf,UAAU,EACV,eAAe,EACf,cAAc,EACd,kBAAkB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,eAAe;IACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAEvD,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,IAAI,CAAC;QACJ,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;QAEtC,kBAAkB;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;QACvC,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,SAAS,GAAG,IAAI,CAAC;YACjB,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC;YACtC,CAAC;QACF,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,uBAAuB;QACvB,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,CAAC,MAAM,mBAAmB,CAAC,CAC/D,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,SAAS,GAAG,IAAI,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;gBACrD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;oBAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC;gBACxC,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3C,CAAC;QACF,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CACV,KAAK,CAAC,MAAM,CAAC,mDAAmD,CAAC,CACjE,CAAC;QACH,CAAC;IACF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,SAAS,GAAG,IAAI,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAQ,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;SAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAC3D,CAAC;AACF,CAAC"}
|