@wix/agent-skills 1.19.0 → 1.19.1
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/package.json +1 -1
- package/skills/wix-app/SKILL.md +33 -31
- package/skills/wix-app/references/DASHBOARD_PAGE.md +6 -10
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +16 -7
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +53 -131
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +1 -2
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +83 -73
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +3 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +9 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +5 -2
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +1 -1
- package/skills/wix-app/scripts/pkg-root.cjs +73 -0
- package/skills/wix-app/scripts/scan-a11y-code.cjs +310 -40
- package/skills/wix-app/scripts/scan-a11y-eslint.cjs +118 -24
- package/skills/wix-app/scripts/scan-a11y-render.cjs +551 -0
- package/skills/wix-app/scripts/scan-a11y-review.cjs +373 -0
- package/skills/wix-base44-connector/SKILL.md +24 -22
- package/skills/wix-base44-connector/scripts/utils.cjs +39 -3
- package/skills/wix-docs/SKILL.md +47 -20
- package/skills/wix-headless/entry/bootstrap.mjs +106 -50
- package/skills/wix-headless/entry/skill.md +5 -3
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +25 -5
- package/skills/wix-headless-fast/SKILL.md +25 -7
- package/skills/wix-headless-fast/entry/skill.md +23 -14
- package/skills/wix-headless-fast/install/fast-path.mjs +48 -5
- package/skills/wix-headless-fast/install/pin-agents-md.mjs +57 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +3 -3
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +204 -35
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +146 -36
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +8 -2
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +95 -20
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +21 -2
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +104 -18
- package/skills/wix-manage/SKILL.md +13 -7
- package/skills/wix-manage/references/google-ads/billing-and-payment.md +3 -3
- package/skills/wix-manage/references/google-ads/create-performance-max-campaign.md +8 -8
- package/skills/wix-manage/references/google-ads/get-campaign-suggestions.md +4 -4
- package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +1 -1
- package/skills/wix-manage/references/google-ads/install-and-create-account.md +9 -9
- package/skills/wix-manage/references/google-ads/query-campaign-analytics.md +7 -7
- package/skills/wix-manage/references/seo/manage-content-plan.md +181 -135
- package/skills/wix-manage/references/seo/manage-google-search-console.md +272 -0
- package/skills/wix-manage/references/sites/upload-static-site.md +53 -0
- package/skills/wix-manage/references/stores/change-store-currency.md +1 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed-with-install.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +3 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +1 -1
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +1 -1
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +0 -80
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +0 -140
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +0 -112
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +0 -100
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +0 -130
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +0 -48
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +0 -66
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +0 -103
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +0 -56
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +0 -23
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# Accessibility Implementation and Review
|
|
2
2
|
|
|
3
|
-
Use this reference while authoring Editor React Component props and JSX
|
|
4
|
-
|
|
3
|
+
Use this reference while authoring Editor React Component props and JSX, then
|
|
4
|
+
run the review command once the JSX is complete.
|
|
5
5
|
|
|
6
6
|
## Contents
|
|
7
7
|
|
|
8
8
|
- [Implementation Contract](#implementation-contract)
|
|
9
9
|
- [Review Scope](#review-scope)
|
|
10
|
-
- [Automated
|
|
10
|
+
- [Automated Review](#automated-review)
|
|
11
11
|
- [Finding Triage](#finding-triage)
|
|
12
12
|
- [Manual Review](#manual-review)
|
|
13
13
|
- [Pre-Fix Checks for Non-Interactive Controls](#pre-fix-checks-for-non-interactive-controls)
|
|
@@ -15,29 +15,42 @@ after every JSX edit.
|
|
|
15
15
|
|
|
16
16
|
## Implementation Contract
|
|
17
17
|
|
|
18
|
-
###
|
|
18
|
+
### Own Accessibility per Part
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
`
|
|
20
|
+
Use the platform `A11y` type instead of individual public props such as
|
|
21
|
+
`ariaLabel`, `ariaDescribedBy`, or `role`. For each part:
|
|
22
|
+
|
|
23
|
+
- Prefer a native element.
|
|
24
|
+
- Keep roles, heading levels, keyboard and focus behavior, relationships, live
|
|
25
|
+
regions, and widget state in component code.
|
|
26
|
+
- Read `a11y.ariaLabel` only when a control has no visible name.
|
|
27
|
+
|
|
28
|
+
Every `a11y` field that reaches the DOM becomes an editor control. Read only the
|
|
29
|
+
field the part needs and write it as its HTML attribute,
|
|
30
|
+
`aria-label={a11y?.ariaLabel}`. Never spread the whole object.
|
|
22
31
|
|
|
23
32
|
```tsx
|
|
24
|
-
import type { A11y
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
id: string;
|
|
29
|
-
className?: string;
|
|
30
|
-
direction?: Direction;
|
|
31
|
-
a11y?: A11y;
|
|
33
|
+
import type { A11y } from '@wix/editor-react-types';
|
|
34
|
+
|
|
35
|
+
type ToggleProps = {
|
|
36
|
+
elementProps?: { toggle?: { className?: string; a11y?: A11y } };
|
|
32
37
|
};
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
function Toggle({ elementProps }: ToggleProps) {
|
|
40
|
+
const { a11y: toggleA11y, ...toggleProps } = elementProps?.toggle ?? {};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<button {...toggleProps} aria-label={toggleA11y?.ariaLabel ?? ARIA_LABELS.toggle}>
|
|
44
|
+
<ChevronIcon aria-hidden="true" />
|
|
45
|
+
</button>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
35
48
|
```
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
Keep the root's typed `a11y?: A11y` prop even when it reads no field. Destructure
|
|
51
|
+
`a11y` out of an `elementProps` entry before spreading the entry; a spread entry
|
|
52
|
+
records the nested object as a whole. Image alt text comes from the `Image`
|
|
53
|
+
type's `alt` field, not from `a11y`.
|
|
41
54
|
|
|
42
55
|
### Provide Accessible Names
|
|
43
56
|
|
|
@@ -53,6 +66,7 @@ Never hardcode an `aria-label` string directly in JSX.
|
|
|
53
66
|
```tsx
|
|
54
67
|
// constants.ts
|
|
55
68
|
export const ARIA_LABELS = {
|
|
69
|
+
toggle: 'Toggle details',
|
|
56
70
|
playButton: 'Play animation',
|
|
57
71
|
pauseButton: 'Pause animation',
|
|
58
72
|
} as const;
|
|
@@ -80,36 +94,47 @@ including an icon plus visible text, usually do not need another ARIA label.
|
|
|
80
94
|
|
|
81
95
|
## Review Scope
|
|
82
96
|
|
|
83
|
-
Run this review after
|
|
97
|
+
Run this review once the JSX is complete and again after each fix pass, at
|
|
98
|
+
most two passes. Do not rerun after a clean result unless JSX changed.
|
|
84
99
|
|
|
85
|
-
| Request |
|
|
100
|
+
| Request | Pass to the command |
|
|
86
101
|
| --- | --- |
|
|
87
|
-
| Specific file | That file
|
|
88
|
-
| A component name or "this component" |
|
|
89
|
-
| Full audit |
|
|
102
|
+
| Specific file | That file; its component folder is rendered |
|
|
103
|
+
| A component name or "this component" | The component folder |
|
|
104
|
+
| Full audit | `src/extensions/site/components/` |
|
|
90
105
|
|
|
91
|
-
|
|
106
|
+
`*.generated.ts` is regenerated from JSX and CSS and is never scanned.
|
|
92
107
|
Imported shared components are inspection context, not automatic edit scope.
|
|
93
108
|
Report a confirmed shared-component issue instead of changing a broadly reused
|
|
94
109
|
primitive unless the requested fix requires that shared change and its impact is
|
|
95
110
|
understood.
|
|
96
111
|
|
|
97
|
-
## Automated
|
|
112
|
+
## Automated Review
|
|
98
113
|
|
|
99
114
|
`<SKILL_ROOT>` is the absolute directory containing the active `SKILL.md`. Run
|
|
100
|
-
|
|
101
|
-
project. Pass `.tsx` or `.jsx` paths relative to the current directory.
|
|
115
|
+
from the consumer Wix package so dependencies resolve from that project.
|
|
102
116
|
|
|
103
117
|
```bash
|
|
104
|
-
node <SKILL_ROOT>/scripts/scan-a11y-
|
|
105
|
-
node <SKILL_ROOT>/scripts/scan-a11y-code.cjs <file1> [file2] ...
|
|
118
|
+
node <SKILL_ROOT>/scripts/scan-a11y-review.cjs <component-dir | files...>
|
|
106
119
|
```
|
|
107
120
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
One command, one report. It runs the jsx-a11y ESLint rules, a semantic scanner
|
|
122
|
+
that follows imports and checks the per-part `a11y` contract, and a render
|
|
123
|
+
audit: the component is rendered with `defaultProps` in Node (an SSR check),
|
|
124
|
+
loaded into jsdom with its CSS Modules, and audited with axe-core.
|
|
125
|
+
`component.preview.tsx` must render without falling back to the placeholder.
|
|
126
|
+
|
|
127
|
+
The JSON report has `summary.line`, then `findings` grouped by rule with a
|
|
128
|
+
count, locations or DOM target, the scanner message, and the axe help link,
|
|
129
|
+
then `notChecked`. Exit `0` means every scanner ran and found nothing, `1`
|
|
130
|
+
means findings, `2` means the review is inconclusive; never treat `2` as clean.
|
|
131
|
+
Exit `2` with `render FAILED (missing-deps)` means `jsdom` or `axe-core` is not
|
|
132
|
+
installed: install them (SKILL.md step 2) and rerun. Exit `2` with
|
|
133
|
+
`render FAILED (loader)` means the audit could not load a module the component
|
|
134
|
+
imports; that is a scanner limit, not a component defect. Change the import
|
|
135
|
+
only if `tsc` also rejects it; otherwise stop and report the loader limit in the
|
|
136
|
+
final summary as a check that could not run. Color contrast, target size, and
|
|
137
|
+
keyboard behavior need a browser and remain manual.
|
|
113
138
|
|
|
114
139
|
## Finding Triage
|
|
115
140
|
|
|
@@ -154,39 +179,23 @@ evidence supports.
|
|
|
154
179
|
|
|
155
180
|
## Manual Review
|
|
156
181
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- Hidden or collapsed state agrees across visuals, focusability, and the
|
|
176
|
-
accessibility tree.
|
|
177
|
-
- Invisible content cannot receive focus unless the interaction requires it.
|
|
178
|
-
- Disabled and inert states behave consistently for keyboard and assistive
|
|
179
|
-
technology users.
|
|
180
|
-
|
|
181
|
-
### Interaction and Structure
|
|
182
|
-
|
|
183
|
-
- Interactive-looking elements use native semantics or complete role, focus,
|
|
184
|
-
and keyboard behavior.
|
|
185
|
-
- `onClick` on a non-interactive tag is checked, including conditional spreads.
|
|
186
|
-
- Nested interactive children and existing focus management are inspected
|
|
187
|
-
before semantics are added to a wrapper.
|
|
188
|
-
- Lists, headings, landmarks, tabs, menus, dialogs, and breadcrumbs keep their
|
|
189
|
-
intended structure.
|
|
182
|
+
In the default rendered state the command checks names, alt text, ARIA
|
|
183
|
+
validity, nesting, list and heading structure, hidden-but-focusable content,
|
|
184
|
+
the `a11y` contract, and SSR safety. Verify what it cannot see:
|
|
185
|
+
|
|
186
|
+
- Every meaningful non-default state (expanded, selected, playing, error,
|
|
187
|
+
empty, hover/focus) keeps correct names, focusability, hidden state, and
|
|
188
|
+
structure; the command audits only the default render.
|
|
189
|
+
- Wrappers and polymorphic components preserve their documented semantics;
|
|
190
|
+
extension overrides preserve generated accessibility fields.
|
|
191
|
+
- Accessible names describe the action, and visually hidden text that carries
|
|
192
|
+
meaning stays in the accessibility tree.
|
|
193
|
+
- State hidden through `--display` or transforms agrees with focusability and
|
|
194
|
+
the accessibility tree; disabled and inert states behave consistently.
|
|
195
|
+
- Custom widgets (tabs, menus, dialogs, sliders) implement their keyboard
|
|
196
|
+
pattern: arrow keys, Home/End, Escape, roving `tabIndex`.
|
|
197
|
+
- Interactive controls have a hit area of at least 24×24 CSS px and visible
|
|
198
|
+
focus.
|
|
190
199
|
- The root implements the direction contract, and every `ReactNode` slot
|
|
191
200
|
isolates nested content with `dir="ltr"`.
|
|
192
201
|
|
|
@@ -211,12 +220,13 @@ Prefer a native element when it preserves product behavior.
|
|
|
211
220
|
|
|
212
221
|
The accessibility review is complete only when:
|
|
213
222
|
|
|
214
|
-
-
|
|
215
|
-
|
|
216
|
-
- confirmed issues are fixed when safe;
|
|
217
|
-
- the
|
|
218
|
-
-
|
|
223
|
+
- the last run exited `0` or `1`; exit `2` is acceptable only for a reported
|
|
224
|
+
`loader` limit;
|
|
225
|
+
- every finding is triaged and confirmed issues are fixed when safe;
|
|
226
|
+
- the command was rerun after the last fix pass; and
|
|
227
|
+
- the manual review is complete.
|
|
219
228
|
|
|
229
|
+
After two fix passes, stop and report the remaining findings with their triage.
|
|
220
230
|
Preserve visual and runtime behavior. Fix the semantic owner: root, named inner
|
|
221
231
|
part, shared primitive, or call site. Then return to the main workflow for the
|
|
222
232
|
Wix build, manifest generation, TypeScript check, and relevant project tests.
|
|
@@ -42,8 +42,9 @@ export type PlanCardProps = {
|
|
|
42
42
|
|
|
43
43
|
Rules:
|
|
44
44
|
|
|
45
|
-
-
|
|
46
|
-
`
|
|
45
|
+
- Follow `ACCESSIBILITY.md`. Expose only `ariaLabel`, for a control without a
|
|
46
|
+
visible name, through the typed `a11y` contract. Keep semantics and state in
|
|
47
|
+
code. Do not add one-off ARIA props or spread the whole object.
|
|
47
48
|
- Expose only content and behavior that the site owner controls. Keep derived
|
|
48
49
|
values internal.
|
|
49
50
|
- Add only callbacks required by the component specification. Use supported SDK
|
|
@@ -195,6 +195,12 @@ and do not expose a visual prop solely for that purpose.
|
|
|
195
195
|
}
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
The same override risk applies to paintable properties. A layout-only inner
|
|
199
|
+
wrapper must stay visually transparent; if it isn't, promote it to its own
|
|
200
|
+
named part instead of hardcoding an opaque style on an unexposed node, since
|
|
201
|
+
that style would otherwise mask the parent part's own
|
|
202
|
+
`background`/`border`/`box-shadow`.
|
|
203
|
+
|
|
198
204
|
## Interaction and Motion
|
|
199
205
|
|
|
200
206
|
- Set `pointer-events: auto` on the root and each interactive element.
|
|
@@ -254,3 +260,6 @@ contract; the contrast relationship is.
|
|
|
254
260
|
- [ ] Visual containers have deliberate hierarchy rather than bare scaffolding.
|
|
255
261
|
- [ ] Every explicit foreground has a known contrasting background; transparent
|
|
256
262
|
components inherit foregrounds from their host.
|
|
263
|
+
- [ ] No unexposed descendant inside a named part paints its own opaque
|
|
264
|
+
`background`/`border`/`box-shadow`; a wrapper needing its own surface is
|
|
265
|
+
promoted to a named part instead.
|
|
@@ -24,14 +24,17 @@ would plausibly control independently in the editor. It receives:
|
|
|
24
24
|
|
|
25
25
|
- one prefixed global class: `'<component-name>-<part-name>'`
|
|
26
26
|
- one CSS Module class
|
|
27
|
-
- one matching `elementProps` entry, spread onto the element
|
|
27
|
+
- one matching `elementProps` entry, spread onto the element. Declare `a11y` on
|
|
28
|
+
the entry only when the part reads `ariaLabel`, and destructure it out before
|
|
29
|
+
spreading (see `ACCESSIBILITY.md`)
|
|
28
30
|
|
|
29
31
|
Apply this filter to every candidate:
|
|
30
32
|
|
|
31
33
|
- A state or variant (`selected`, `active`, `open`, `disabled`) is not a part.
|
|
32
34
|
Implement it as a prefixed design-state modifier on the affected part.
|
|
33
35
|
- A hidden and shown version of the same element is one part, not two.
|
|
34
|
-
- A grouping or layout-only wrapper is not a part.
|
|
36
|
+
- A grouping or layout-only wrapper is not a part. A wrapper that isn't
|
|
37
|
+
visually transparent is no longer layout-only — promote it to a named part.
|
|
35
38
|
- A static child whose styling and data are fully owned by its parent is not a
|
|
36
39
|
part. For example, an image whose source and appearance both belong to its
|
|
37
40
|
carousel slide can remain module-class-only.
|
|
@@ -86,4 +86,4 @@ export const ProfileCard: React.FC<ProfileCardProps> = (props) => {
|
|
|
86
86
|
- [ ] Direction and accessibility contracts are wired to the correct elements.
|
|
87
87
|
- [ ] Public handlers use supported SDK names; internal handlers stay internal.
|
|
88
88
|
- [ ] CSS changed by the request keeps editable selectors flat and scoped.
|
|
89
|
-
- [ ] The accessibility review
|
|
89
|
+
- [ ] The accessibility review command passes, or its remaining findings are triaged.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Prints the install directory of a package — the folder holding its
|
|
3
|
+
// package.json — resolved from the current working directory.
|
|
4
|
+
//
|
|
5
|
+
// node pkg-root.cjs @wix/patterns
|
|
6
|
+
//
|
|
7
|
+
// Takes the package name as an argument and knows nothing about any particular
|
|
8
|
+
// package, so it stays correct as the packages it is pointed at change.
|
|
9
|
+
//
|
|
10
|
+
// Three steps, because one is not enough in the repos this runs in:
|
|
11
|
+
// 1. Activate Yarn PnP if a .pnp.cjs exists at or above cwd. A bare
|
|
12
|
+
// require.resolve throws in a Yarn Berry project even when the package is
|
|
13
|
+
// installed, and in a monorepo the .pnp.cjs sits at the repo root rather
|
|
14
|
+
// than beside the project being built.
|
|
15
|
+
// 2. require.resolve, which handles npm, pnpm and workspace layouts.
|
|
16
|
+
// 3. Failing that, walk up looking for node_modules/<pkg> directly, which
|
|
17
|
+
// covers a partially-installed tree where resolution fails but the files
|
|
18
|
+
// are on disk.
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
const pkg = process.argv[2];
|
|
23
|
+
if (!pkg) {
|
|
24
|
+
console.error('usage: pkg-root.cjs <package-name>');
|
|
25
|
+
process.exit(2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function activatePnp() {
|
|
29
|
+
let dir = process.cwd();
|
|
30
|
+
for (;;) {
|
|
31
|
+
const pnp = path.join(dir, '.pnp.cjs');
|
|
32
|
+
if (fs.existsSync(pnp)) {
|
|
33
|
+
try {
|
|
34
|
+
require(pnp).setup();
|
|
35
|
+
} catch {
|
|
36
|
+
// An unusable .pnp.cjs is not fatal: the plain resolve below may still
|
|
37
|
+
// succeed against a node_modules tree.
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const parent = path.dirname(dir);
|
|
42
|
+
if (parent === dir) return;
|
|
43
|
+
dir = parent;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
activatePnp();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
console.log(
|
|
51
|
+
path.dirname(
|
|
52
|
+
require.resolve(`${pkg}/package.json`, { paths: [process.cwd()] }),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
process.exit(0);
|
|
56
|
+
} catch {
|
|
57
|
+
// fall through to the directory walk
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let dir = process.cwd();
|
|
61
|
+
for (;;) {
|
|
62
|
+
const candidate = path.join(dir, 'node_modules', ...pkg.split('/'));
|
|
63
|
+
if (fs.existsSync(path.join(candidate, 'package.json'))) {
|
|
64
|
+
console.log(candidate);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
const parent = path.dirname(dir);
|
|
68
|
+
if (parent === dir) {
|
|
69
|
+
console.error(`${pkg} not found from ${process.cwd()}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
dir = parent;
|
|
73
|
+
}
|