mirror of
https://github.com/Manavarya09/design-extract.git
synced 2026-09-19 02:41:14 +08:00
feat(ci): distinct exit codes, a pinned and gating Action; release 13.3.0
Every failure exited 1, so a CI gate could not tell a design regression from a flaky preview deploy. - exit 0 ok, 1 drift over threshold, 2 extraction failed, 3 navigation timeout; wired into extraction, drift, ci and lint - the Action installs the designlang version it was tagged with, runs install-browser, fails on drift by default, annotates each changed token (escaped), says why a job failed, and lists Manavarya09 as author - fix changed-count being written as "0" twice when nothing changed - README: install-browser, live MCP tools, CLI reference - 13.3.0 changelog with the breaking changes called out
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
"name": "designlang",
|
||||
"source": "./",
|
||||
"description": "Thirteen slash commands wrapping the designlang CLI: /extract (full design language → DTCG, Tailwind, Figma), /site (crawl a whole site → one canonical design system + consistency grade), /grade (shareable HTML report card + SVG badge), /battle (head-to-head graded comparison), /remix (restyle in 6 vocabularies — brutalist, swiss, art-deco, cyberpunk, soft-ui, editorial), /pack (one downloadable design-system bundle), /theme-swap (OKLCH-correct recolour around a new brand primary), /brand (full editorial brand-guidelines book — 13 chapters, hand-off-ready), /pair (fuse two designs across configurable axes — colours from one site, typography from another), /studio (live token-editor with component preview + export), /verify (rebuild from tokens and pixel-diff vs live for a fidelity score), /fidelity (score a clone vs the original — visual pixel-diff + motion fidelity — with a ranked correction plan), /gallery (build a shareable static gallery of measured clones).",
|
||||
"version": "13.2.0",
|
||||
"version": "13.3.0",
|
||||
"author": {
|
||||
"name": "Manavarya Singh"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "designlang",
|
||||
"description": "Extract any website's design language and ship it. Fourteen slash commands — /extract, /site, /grade, /battle, /remix, /pack, /theme-swap, /brand, /pair, /studio, /verify, /fidelity, /gallery, /dna — wrap the designlang CLI to pull DTCG tokens, Tailwind/shadcn/Figma vars, motion + voice, synthesize a whole-site canonical design system with a consistency grade, generate shareable graded report cards, head-to-head battle pages, six-vocabulary remixes, downloadable design-system bundles, OKLCH-correct theme recolouring, full editorial brand-guidelines books, design crossovers between two sites, a live token-editor studio, a rebuild-and-pixel-diff fidelity check, a measured clone-vs-original fidelity score (visual + motion) with a ranked correction plan via /fidelity, a shareable static gallery of scored clones via /gallery, and — via /dna — a measured design space that places any site among real design systems by nearest neighbours, per-axis percentiles, and the features that make it look the way it does.",
|
||||
"version": "13.2.0",
|
||||
"version": "13.3.0",
|
||||
"author": {
|
||||
"name": "Manavarya Singh",
|
||||
"url": "https://github.com/Manavarya09"
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# Changelog
|
||||
|
||||
## [13.3.0] — 2026-09-15
|
||||
|
||||
**Ship it where people run it: releases, installs, agents and CI.**
|
||||
|
||||
Extraction was already strong; what failed people was everything around it.
|
||||
npm `latest` sat three months behind the repo, `npm install` downloaded a
|
||||
browser that CI and Docker can't, the MCP server couldn't extract a URL, and
|
||||
every failure exited `1`.
|
||||
|
||||
**Releases**
|
||||
|
||||
- **npm publishes from CI on every `vX.Y.Z` tag**, with provenance. A tag that
|
||||
doesn't match `package.json` fails the release.
|
||||
|
||||
**Install**
|
||||
|
||||
- **No browser download at `npm install`.** Run `designlang install-browser`
|
||||
(`--with-deps` on bare Linux) to fetch the Chromium matching the bundled
|
||||
Playwright.
|
||||
- **One launcher everywhere.** All 13 launch sites try the bundled Chromium,
|
||||
then system Chrome, then fail with an error that names the fix.
|
||||
|
||||
**MCP server v2**
|
||||
|
||||
- **Extract live URLs as jobs.** `extract_design` returns a job id;
|
||||
`get_job_status`, `list_jobs`, `cancel_job`.
|
||||
- **Read, diff, lint and export by job id:** `get_tokens`, `get_colors`,
|
||||
`get_typography`, `get_components`, `compute_drift`, `get_findings`, and
|
||||
`export` (dtcg, tailwind, shadcn, figma, css, design-md).
|
||||
- **Conformance.** An `initialize` without `protocolVersion` is served on the
|
||||
default revision instead of rejected (#182, #183); `serverInfo.version` is the
|
||||
package version (it said 7.0.0); `import 'designlang/mcp'` resolves (the export
|
||||
pointed at a missing file).
|
||||
- The folder-backed tools and resources are unchanged.
|
||||
|
||||
**Exit codes**
|
||||
|
||||
| Code | Meaning |
|
||||
|---|---|
|
||||
| `0` | Success |
|
||||
| `1` | Drift over threshold (`drift`, `ci`, `lint`) |
|
||||
| `2` | Extraction failed: page error, bad input, no browser |
|
||||
| `3` | Navigation timeout: retryable |
|
||||
|
||||
**GitHub Action**
|
||||
|
||||
- **Installs the designlang version it was tagged with**, then the browser.
|
||||
- **One PR annotation per changed token**, escaped, since values come from the
|
||||
audited site.
|
||||
- **Says why a job failed**: drift, extraction failure or timeout.
|
||||
- Fixed: with zero changes, `changed-count` was written as `0` twice, which broke
|
||||
the `changed` output.
|
||||
|
||||
**Breaking**
|
||||
|
||||
- The Action's `fail-on-change` now defaults to `true`. Pass `false` to keep
|
||||
report-only behaviour.
|
||||
- Extraction failures exit `2` or `3` instead of `1`.
|
||||
- A fresh install needs `designlang install-browser` or a system Chrome.
|
||||
|
||||
## [13.2.0] — 2026-08-31
|
||||
|
||||
**Depth pass on extraction: the inventories become systems.**
|
||||
|
||||
@@ -215,9 +215,15 @@ than no score at all:
|
||||
|
||||
```bash
|
||||
npm i -g designlang # global
|
||||
designlang install-browser # one-time: the Chromium designlang drives
|
||||
npx skills add Manavarya09/design-extract # as an agent skill (40+ agents)
|
||||
```
|
||||
|
||||
`npm install` no longer downloads a browser, so it works in CI, Docker and
|
||||
behind proxies. `install-browser` fetches the Chromium matching the bundled
|
||||
Playwright (add `--with-deps` on bare Linux). Without it, designlang falls back
|
||||
to an installed Google Chrome.
|
||||
|
||||
## Use in Claude Code (plugin)
|
||||
|
||||
designlang ships as a **Claude Code plugin** — eleven slash commands that wrap
|
||||
@@ -249,9 +255,17 @@ the commands are available:
|
||||
| `/gallery [dir]` | build a static shareable gallery of measured clones |
|
||||
| `/dna <url>` | place a design in the measured design space — nearest systems, per-axis percentiles, outliers |
|
||||
|
||||
> Prefer the raw MCP tools? The CLI also ships an MCP server — run
|
||||
> `designlang mcp --output-dir ./design-extract-output` to serve the latest
|
||||
> extraction's tokens to any MCP client.
|
||||
> Prefer raw MCP tools? The CLI ships an MCP server that extracts live URLs:
|
||||
>
|
||||
> ```bash
|
||||
> claude mcp add designlang -- npx -y designlang mcp
|
||||
> ```
|
||||
>
|
||||
> `extract_design(url)` returns a job id; poll `get_job_status`, then pass the
|
||||
> id to `get_tokens`, `get_colors`, `get_typography`, `get_components`,
|
||||
> `get_findings`, `compute_drift` (against a baseline job) or `export`
|
||||
> (dtcg, tailwind, shadcn, figma, css, design-md). Add `--output-dir <dir>` to
|
||||
> also serve an extraction already on disk as resources.
|
||||
|
||||
## Atlas Cloud for `--smart`
|
||||
|
||||
@@ -425,7 +439,8 @@ Commands:
|
||||
brands <urls...> Multi-brand comparison matrix
|
||||
sync <url> Sync local tokens with live site
|
||||
history <url> View design change history
|
||||
mcp Launch stdio MCP server (--output-dir <dir>)
|
||||
install-browser Download the Chromium designlang drives (--with-deps on bare Linux)
|
||||
mcp Launch stdio MCP server: extract live URLs as jobs (--output-dir <dir> also serves one on disk)
|
||||
lint <file> (v9) Audit a local token file (.json/.css) — CI-ready
|
||||
drift <url> --tokens <file> (v9) Check local tokens for drift against a live site
|
||||
visual-diff <before> <after> (v9) Side-by-side HTML diff of two URLs
|
||||
|
||||
+15
-8
@@ -719,9 +719,10 @@ program
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
const { exitCodeForError } = await import('../src/exit-codes.js');
|
||||
if (jsonMode) {
|
||||
process.stderr.write(JSON.stringify({ error: err.message }) + '\n');
|
||||
process.exit(1);
|
||||
process.exit(exitCodeForError(err));
|
||||
}
|
||||
spinner.fail('Extraction failed');
|
||||
if (err.code === 'BROWSER_UNAVAILABLE' || err.message.includes('playwright')) {
|
||||
@@ -731,7 +732,7 @@ program
|
||||
console.error(chalk.red(`\n ${err.message}\n`));
|
||||
if (opts.verbose) console.error(err.stack);
|
||||
}
|
||||
process.exit(1);
|
||||
process.exit(exitCodeForError(err));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2032,10 +2033,12 @@ program
|
||||
}
|
||||
if (!r.findings.length) console.log(chalk.green(' ✓ no issues found'));
|
||||
console.log('');
|
||||
process.exit(r.findings.some(f => f.severity === 'error') ? 1 : 0);
|
||||
const { EXIT } = await import('../src/exit-codes.js');
|
||||
process.exit(r.findings.some(f => f.severity === 'error') ? EXIT.DRIFT : EXIT.OK);
|
||||
} catch (err) {
|
||||
const { exitCodeForError } = await import('../src/exit-codes.js');
|
||||
process.stderr.write(chalk.red(`\n Error: ${err.message}\n\n`));
|
||||
process.exit(1);
|
||||
process.exit(exitCodeForError(err));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2056,10 +2059,12 @@ program
|
||||
if (opts.json) { process.stdout.write(JSON.stringify(r, null, 2) + '\n'); }
|
||||
else { console.log('\n' + formatDriftMarkdown(r) + '\n'); }
|
||||
const order = ['in-sync', 'minor-drift', 'notable-drift', 'major-drift'];
|
||||
if (order.indexOf(r.verdict) >= order.indexOf(opts.failOn)) process.exit(1);
|
||||
const { EXIT } = await import('../src/exit-codes.js');
|
||||
if (order.indexOf(r.verdict) >= order.indexOf(opts.failOn)) process.exit(EXIT.DRIFT);
|
||||
} catch (err) {
|
||||
const { exitCodeForError } = await import('../src/exit-codes.js');
|
||||
process.stderr.write(chalk.red(`\n Error: ${err.message}\n\n`));
|
||||
process.exit(1);
|
||||
process.exit(exitCodeForError(err));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2304,10 +2309,12 @@ program
|
||||
console.log('');
|
||||
console.log(r.md);
|
||||
}
|
||||
if (r.shouldFail) process.exit(1);
|
||||
const { EXIT } = await import('../src/exit-codes.js');
|
||||
if (r.shouldFail) process.exit(EXIT.DRIFT);
|
||||
} catch (err) {
|
||||
const { exitCodeForError } = await import('../src/exit-codes.js');
|
||||
spinner.fail(err.message);
|
||||
process.exit(1);
|
||||
process.exit(exitCodeForError(err));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+21
-10
@@ -1,6 +1,6 @@
|
||||
# designlang — Design Regression Guard
|
||||
|
||||
GitHub Action that runs `designlang` on every pull request, diffs the extracted design tokens against a committed baseline, and comments the changes.
|
||||
GitHub Action that runs `designlang` on every pull request, diffs the extracted design tokens against a committed baseline, annotates each changed token on the PR, and fails the job on drift.
|
||||
|
||||
## Example workflow
|
||||
|
||||
@@ -20,14 +20,15 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: '20' }
|
||||
- uses: Manavarya09/design-extract/github-action@v1
|
||||
with: { node-version: '22' }
|
||||
- uses: Manavarya09/design-extract/github-action@v13.3.0
|
||||
with:
|
||||
url: https://preview-${{ github.event.number }}.yoursite.dev
|
||||
baseline: ./design-tokens.baseline.json
|
||||
fail-on-change: false
|
||||
```
|
||||
|
||||
Pin to a release tag. The action installs the designlang version it was tagged with, so a gate on `@v13.3.0` never changes behaviour under you.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Required | Default | Description |
|
||||
@@ -35,7 +36,7 @@ jobs:
|
||||
| `url` | ✅ | — | URL to extract from. Typically a PR preview deploy. |
|
||||
| `baseline` | ✅ | — | Path to the committed baseline tokens file. |
|
||||
| `comment` | | `true` | Post a PR comment with the diff. |
|
||||
| `fail-on-change` | | `false` | Fail the job if any token changed. |
|
||||
| `fail-on-change` | | `true` | Fail the job if any token changed. Set `false` to report without gating. |
|
||||
| `full` | | `false` | Pass `--full` to `designlang`. |
|
||||
| `extra-args` | | — | Extra CLI args. |
|
||||
|
||||
@@ -44,11 +45,21 @@ jobs:
|
||||
- `changed` — `true`/`false`
|
||||
- `changed-count` — number of changed tokens
|
||||
- `diff-path` — path to the generated diff markdown
|
||||
- `version` — the designlang version that ran
|
||||
|
||||
## Publishing
|
||||
## Why a job failed
|
||||
|
||||
```bash
|
||||
git tag v1 && git push --tags
|
||||
```
|
||||
A failed job always says which of these it was, so a flaky preview deploy is never mistaken for a design regression:
|
||||
|
||||
Then list on the GitHub Marketplace via the repo's Actions tab.
|
||||
| designlang exit | Meaning |
|
||||
|---|---|
|
||||
| `0` | Extracted; compared against the baseline |
|
||||
| `1` | Drift over threshold (`designlang drift` / `ci` / `lint`) |
|
||||
| `2` | Extraction failed: page error, bad input, no browser |
|
||||
| `3` | Navigation timeout: retryable, the design was not checked |
|
||||
|
||||
The action's own "Fail on change" step exits `1` when tokens changed.
|
||||
|
||||
## Upgrading from `@v1`
|
||||
|
||||
`fail-on-change` now defaults to `true`. Pass `fail-on-change: false` to keep report-only behaviour.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: "designlang — Design Regression Guard"
|
||||
description: "Diff a site's design tokens against a baseline and comment the delta on the pull request."
|
||||
author: "masyv"
|
||||
description: "Extract a live URL, diff its design tokens against a committed baseline, annotate the pull request and fail on drift."
|
||||
author: "Manavarya09"
|
||||
branding:
|
||||
icon: "layers"
|
||||
color: "orange"
|
||||
@@ -16,8 +16,8 @@ inputs:
|
||||
description: "Whether to post a PR comment with the diff (true/false)."
|
||||
default: "true"
|
||||
fail-on-change:
|
||||
description: "Fail the job if any token changed."
|
||||
default: "false"
|
||||
description: "Fail the job if any token changed. Set to false to report without gating."
|
||||
default: "true"
|
||||
full:
|
||||
description: "Pass --full to designlang (screenshots, responsive, interactions)."
|
||||
default: "false"
|
||||
@@ -31,17 +31,38 @@ inputs:
|
||||
outputs:
|
||||
changed:
|
||||
description: "true/false — whether any tokens changed since the baseline."
|
||||
value: ${{ steps.diff.outputs.changed }}
|
||||
changed-count:
|
||||
description: "Number of changed tokens."
|
||||
value: ${{ steps.diff.outputs.changed-count }}
|
||||
diff-path:
|
||||
description: "Path to the generated diff markdown."
|
||||
value: ${{ steps.diff.outputs.diff-path }}
|
||||
version:
|
||||
description: "The designlang version that ran."
|
||||
value: ${{ steps.install.outputs.version }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Pinned to the designlang release this action was tagged with, so a gate on
|
||||
# @vX.Y.Z never changes behaviour under you.
|
||||
- name: Install designlang
|
||||
id: install
|
||||
shell: bash
|
||||
run: npm install -g designlang
|
||||
env:
|
||||
ACTION_PATH: ${{ github.action_path }}
|
||||
run: |
|
||||
VERSION="$(node -p "require(process.env.ACTION_PATH + '/../package.json').version")"
|
||||
if npm view "designlang@$VERSION" version >/dev/null 2>&1; then
|
||||
npm install -g "designlang@$VERSION"
|
||||
else
|
||||
echo "::warning::designlang@$VERSION is not on npm (untagged ref?); using the latest release"
|
||||
npm install -g designlang
|
||||
VERSION="$(designlang --version)"
|
||||
fi
|
||||
designlang install-browser --with-deps
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Extract tokens
|
||||
shell: bash
|
||||
@@ -54,20 +75,38 @@ runs:
|
||||
ARGS="--out .designlang-run"
|
||||
if [ "$FULL" = "true" ]; then ARGS="$ARGS --full"; fi
|
||||
if [ -n "$EXTRA" ]; then ARGS="$ARGS $EXTRA"; fi
|
||||
set +e
|
||||
designlang "$URL" $ARGS
|
||||
CODE=$?
|
||||
set -e
|
||||
if [ "$CODE" -eq 3 ]; then
|
||||
echo "::error::designlang timed out loading the page (exit 3). This is retryable; the design was not checked."
|
||||
elif [ "$CODE" -ne 0 ]; then
|
||||
echo "::error::designlang could not extract the page (exit $CODE). The design was not checked."
|
||||
fi
|
||||
exit "$CODE"
|
||||
|
||||
- name: Diff tokens against baseline
|
||||
id: diff
|
||||
shell: bash
|
||||
env:
|
||||
BASELINE: ${{ inputs.baseline }}
|
||||
ACTION_PATH: ${{ github.action_path }}
|
||||
run: |
|
||||
NEW=$(ls .designlang-run/*-design-tokens.json | head -n 1)
|
||||
node "${{ github.action_path }}/diff-tokens.cjs" "$BASELINE" "$NEW" > .designlang-run/diff.md || true
|
||||
CHANGED=$(grep -c '^- ' .designlang-run/diff.md || echo 0)
|
||||
node "$ACTION_PATH/diff-tokens.cjs" "$BASELINE" "$NEW" > .designlang-run/diff.md || true
|
||||
CHANGED=$(grep -c '^- ' .designlang-run/diff.md || true)
|
||||
echo "changed=$([ "$CHANGED" -gt 0 ] && echo true || echo false)" >> "$GITHUB_OUTPUT"
|
||||
echo "changed-count=$CHANGED" >> "$GITHUB_OUTPUT"
|
||||
echo "diff-path=.designlang-run/diff.md" >> "$GITHUB_OUTPUT"
|
||||
# One annotation per token. Values come from the audited site, so escape
|
||||
# them the way the Actions toolkit does before emitting a command.
|
||||
grep '^- ' .designlang-run/diff.md | head -n 50 | while IFS= read -r line; do
|
||||
msg="${line#- }"
|
||||
msg="${msg//'%'/%25}"
|
||||
msg="${msg//$'\r'/%0D}"
|
||||
echo "::warning title=designlang drift::$msg"
|
||||
done
|
||||
|
||||
- name: Comment on PR
|
||||
if: ${{ inputs.comment == 'true' && github.event_name == 'pull_request' }}
|
||||
@@ -87,6 +126,8 @@ runs:
|
||||
- name: Fail on change
|
||||
if: ${{ inputs.fail-on-change == 'true' && steps.diff.outputs.changed == 'true' }}
|
||||
shell: bash
|
||||
env:
|
||||
COUNT: ${{ steps.diff.outputs.changed-count }}
|
||||
run: |
|
||||
echo "::error::Design tokens changed vs baseline."
|
||||
echo "::error::$COUNT design token(s) changed vs baseline. Update the baseline if the change is intended."
|
||||
exit 1
|
||||
|
||||
Generated
+2
-3
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"name": "designlang",
|
||||
"version": "13.2.0",
|
||||
"version": "13.3.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "designlang",
|
||||
"version": "13.2.0",
|
||||
"hasInstallScript": true,
|
||||
"version": "13.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "designlang",
|
||||
"version": "13.2.0",
|
||||
"version": "13.3.0",
|
||||
"description": "Extract the complete design language from any website and ship it — clone to a working Next.js starter, guard tokens with a CI drift bot, or browse everything in a local studio. Outputs W3C DTCG tokens, motion tokens, typed anatomy stubs, Tailwind config, and ready-to-paste v0 / Lovable / Cursor / Claude-Artifacts prompts.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Exit codes a CI pipeline can branch on. "The design drifted" and "the tool
|
||||
// could not extract" used to share exit 1, so a gate could not tell a real
|
||||
// regression from a flaky preview deploy.
|
||||
|
||||
export const EXIT = Object.freeze({
|
||||
OK: 0,
|
||||
DRIFT: 1, // a drift/lint gate crossed its threshold
|
||||
EXTRACTION_FAILED: 2, // browser missing, page error, bad input
|
||||
NAVIGATION_TIMEOUT: 3, // retryable: try --wait or a later run
|
||||
});
|
||||
|
||||
export function exitCodeForError(err) {
|
||||
if (err?.name === 'TimeoutError' || /Timeout \d+ms exceeded/.test(err?.message || '')) return EXIT.NAVIGATION_TIMEOUT;
|
||||
return EXIT.EXTRACTION_FAILED;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { EXIT, exitCodeForError } from '../src/exit-codes.js';
|
||||
|
||||
describe('exit codes', () => {
|
||||
it('keeps drift and extraction failure distinct', () => {
|
||||
assert.deepEqual(EXIT, { OK: 0, DRIFT: 1, EXTRACTION_FAILED: 2, NAVIGATION_TIMEOUT: 3 });
|
||||
});
|
||||
|
||||
it('classifies a Playwright navigation timeout as retryable', () => {
|
||||
const byName = Object.assign(new Error('page.goto: Timeout 30000ms exceeded.'), { name: 'TimeoutError' });
|
||||
assert.equal(exitCodeForError(byName), EXIT.NAVIGATION_TIMEOUT);
|
||||
assert.equal(exitCodeForError(new Error('page.goto: Timeout 30000ms exceeded.')), EXIT.NAVIGATION_TIMEOUT);
|
||||
});
|
||||
|
||||
it('classifies everything else as an extraction failure', () => {
|
||||
assert.equal(exitCodeForError(Object.assign(new Error('No browser available.'), { code: 'BROWSER_UNAVAILABLE' })), EXIT.EXTRACTION_FAILED);
|
||||
assert.equal(exitCodeForError(new Error('net::ERR_NAME_NOT_RESOLVED')), EXIT.EXTRACTION_FAILED);
|
||||
assert.equal(exitCodeForError(undefined), EXIT.EXTRACTION_FAILED);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user