@hiver/skills 1.0.2 → 1.0.4
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/collections/common/skills/discuss-problem/SKILL.md +2 -2
- package/collections/extension/skills/build-component/references/icons/brand-icons.png +0 -0
- package/collections/extension/skills/build-component/references/icons/mui-icons.png +0 -0
- package/collections/extension/skills/build-component/references/icons.md +79 -6
- package/collections/extension/skills/build-component/typography/variants.md +62 -2
- package/collections/web/skills/build-component/references/icons/brand-icons.png +0 -0
- package/collections/web/skills/build-component/references/icons/mui-icons.png +0 -0
- package/collections/web/skills/build-component/references/icons.md +79 -6
- package/collections/web/skills/build-component/typography/variants.md +62 -2
- package/dist/cli.js +277 -102
- package/package.json +1 -1
|
@@ -36,8 +36,8 @@ Help the user to grill down on a problem to its core discussing all sorts of the
|
|
|
36
36
|
|
|
37
37
|
1. Take input from the user related to the problem they want to discuss or grill down
|
|
38
38
|
2. If the problem is related to building a new feature, check with the user if prototype designs are available
|
|
39
|
-
3. If Figma designs are available, use the Figma MCP tool to get the prototype details and analyze them
|
|
40
|
-
4. Keep asking if the user has more Figma designs available until all designs are provided; keep using the Figma MCP tool to load them into memory
|
|
39
|
+
3. If Figma designs are available, use the claude Figma desktop MCP tool to get the prototype details and analyze them
|
|
40
|
+
4. Keep asking if the user has more Figma designs available until all designs are provided; keep using the claude Figma desktop MCP tool to load them into memory
|
|
41
41
|
5. Analyze the problem statement in context of the current codebase — use read and search tools to explore, never write tools
|
|
42
42
|
6. Ask the right questions until you are clear on the problem statement
|
|
43
43
|
7. Go through the codebase and figure out how the problem can be solved — discussion only
|
|
Binary file
|
|
Binary file
|
|
@@ -1,8 +1,81 @@
|
|
|
1
1
|
# Icons
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
How to import from `@hiver/hiver-ui-kit`:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { brandIcons, icons } from '@hiver/hiver-ui-kit';
|
|
7
|
+
// <brandIcons.Star />
|
|
8
|
+
// <icons.AccountCircle />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Resolution priority
|
|
12
|
+
|
|
13
|
+
When a Figma design contains an icon, resolve it in this order:
|
|
14
|
+
|
|
15
|
+
1. **User-provided SVG asset** — if the user supplied an `.svg` file, import it directly:
|
|
16
|
+
```js
|
|
17
|
+
import iconName from 'path/to/icon.svg';
|
|
18
|
+
<img src={iconName} alt="description" />
|
|
19
|
+
```
|
|
20
|
+
2. **`brandIcons`** — Hiver-designed icons (see "Brand icon catalog" below).
|
|
21
|
+
3. **`icons`** — curated MUI icons re-exported from hui-kit (see "MUI icon catalog" below).
|
|
22
|
+
4. **`@mui/icons-material`** — **last resort only**, when the icon is not in the design system **and** the user has not provided an asset.
|
|
23
|
+
5. **Never** import icons from FontAwesome, Heroicons, or any other third-party icon library.
|
|
24
|
+
|
|
25
|
+
## How to match a Figma icon to a code name
|
|
26
|
+
|
|
27
|
+
1. **Prefer the Figma layer/component name** if the design exposes one (e.g. a layer named `Brand/Star` → `brandIcons.Star`).
|
|
28
|
+
2. **Otherwise, match visually** against the catalog sheets embedded below. Each icon is rendered with its exact export name underneath.
|
|
29
|
+
3. The export name is what you use in code — including any typos preserved from the design system (see Notes).
|
|
30
|
+
|
|
31
|
+
## Brand icon catalog (`brandIcons`)
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
**Hiver Logo**
|
|
36
|
+
- `Logo`
|
|
37
|
+
|
|
38
|
+
**Brand icons** (box 20×20, live area 18×18, stroke 1.4)
|
|
39
|
+
- `SharedMailbox`, `Analytics`, `EmailTemplates`, `Settings`, `HiverAlerts`, `Activity`, `AutoAssignment`, `Workload`, `Lable`, `Permalink`
|
|
40
|
+
- `Star`, `Edit`, `Filters`, `HiverChat`, `AircallPhone`, `Aavatar`, `Unassigned`, `Mine`, `Team`, `Pending`
|
|
41
|
+
- `Closed`, `Tags`, `Crown`, `Dashboard`, `DashboardInactive`, `SharedInboxNav`, `SharedInboxNavInactive`, `SharedLabel`, `SharedLabelInactive`, `KnowledgeBase`
|
|
42
|
+
- `KnowledgeBaseInactive`, `Connector`, `ConnectorInactive`, `SettingsNav`, `SettingsNavInactive`, `UserRole`, `UserRoleInactive`
|
|
43
|
+
|
|
44
|
+
**Activity icons** (box 20×20, live area 16×16, stroke 1.4)
|
|
45
|
+
- `Status`, `Tag`, `Inbox`, `AlertTriangle`, `EnvelopeDownload`, `ActivityStar`, `EnvelopeUpload`, `Envelope`, `ActivityEdit`, `CloseCircle`, `CheckAction`, `UserCheck`
|
|
46
|
+
|
|
47
|
+
**Settings icons** (box 24×24, live area 22×22, stroke 1.4)
|
|
48
|
+
- `AdminPanel`, `Sliders`, `Compass`, `SwitchAccount`, `Gift`, `MessageCircle`, `LifeBuoy`
|
|
49
|
+
|
|
50
|
+
## MUI icon catalog (`icons`)
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
- `AccountCircle`, `Add`, `Alarm`, `Close`, `Phone`, `ArchiveOutlined`, `ArrowBack`, `ArrowBackIos`, `ArrowDropDown`, `ArrowDropUp`, `ArrowForward`
|
|
55
|
+
- `ArrowOutward`, `CalendarToday`, `CalendarTodayOutlined`, `CalendarTodayOutlinedIcon`, `Cancel`, `CancelOutlined`, `CheckCircle`, `ChevronRightOutlined`, `CodeSharp`, `DeleteOutline`, `DownloadOutlined`
|
|
56
|
+
- `DragIndicator`, `EditOutlined`, `Error`, `ErrorOutline`, `GroupsOutlined`, `InfoOutlined`, `LabelOutlined`, `Link`, `LockOutlined`, `MailOutlined`, `MicNone`
|
|
57
|
+
- `MoreVert`, `NotificationsOutlined`, `OpenInNew`, `Pause`, `PersonOutline`, `PersonOutlined`, `PlayArrow`, `Public`, `Search`, `Settings`, `SettingsOutlined`
|
|
58
|
+
- `StickyNote2Outlined`, `ThumbDownAlt`, `ThumbDownOffAlt`, `ThumbUpAlt`, `ThumbUpOffAlt`, `TimerOutlined`, `TrackChanges`, `UnarchiveOutlined`, `Voicemail`, `Warning`, `WarningAmber`
|
|
59
|
+
- `ArrowRightAlt`, `Delete`, `Email`, `Favorite`
|
|
60
|
+
|
|
61
|
+
## Notes — Figma → code gotchas
|
|
62
|
+
|
|
63
|
+
- **Typos preserved in exports** — these match the Figma names, so map literally; do not auto-correct:
|
|
64
|
+
- `Lable` (not `Label`)
|
|
65
|
+
- `Aavatar` (not `Avatar`)
|
|
66
|
+
- **`Edit` collision** — three similar icons:
|
|
67
|
+
- `brandIcons.Edit` — pen-on-paper brand icon (yellow accent)
|
|
68
|
+
- `brandIcons.ActivityEdit` — green envelope with a pen, activity style
|
|
69
|
+
- `icons.EditOutlined` — plain MUI outlined pencil
|
|
70
|
+
- **`Settings` collision** — five similar names:
|
|
71
|
+
- `brandIcons.Settings`, `brandIcons.SettingsNav`, `brandIcons.SettingsNavInactive`
|
|
72
|
+
- `icons.Settings`, `icons.SettingsOutlined`
|
|
73
|
+
Pick by Figma category section and visual.
|
|
74
|
+
- **`Star` collision**:
|
|
75
|
+
- `brandIcons.Star` — yellow filled brand star
|
|
76
|
+
- `brandIcons.ActivityStar` — purple activity star
|
|
77
|
+
- **`Tag` vs `Tags`**:
|
|
78
|
+
- `brandIcons.Tags` — brand (plural, box 20×20 live 18×18)
|
|
79
|
+
- `brandIcons.Tag` — activity (singular, box 20×20 live 16×16)
|
|
80
|
+
- **Inactive variants** — many brand icons have `*Inactive` siblings (`DashboardInactive`, `SharedInboxNavInactive`, `SharedLabelInactive`, `KnowledgeBaseInactive`, `ConnectorInactive`, `SettingsNavInactive`, `UserRoleInactive`). Use the inactive variant for the unselected/disabled state of a nav item.
|
|
81
|
+
- **`UserCheck`** — present in `brandIcons` exports but not visible on the current Figma sheet. Use it if a design clearly needs it; otherwise prefer the activity-style icons documented above.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Typography reference (`@hiver/hiver-ui-kit`)
|
|
2
2
|
|
|
3
|
-
Map Figma text styles to `<Typography variant="...">`.
|
|
3
|
+
Map Figma text styles to `<Typography variant="...">`. Match by fontSize + fontWeight (regular 400, medium 500, semiBold 600, bold 700).
|
|
4
|
+
|
|
5
|
+
**Font families:**
|
|
6
|
+
- Legacy variants (`h1_*`–`h5_*`, `body0_5_*`–`body4_*`, `caption1_*`, `caption2_*`, `overline_medium`, `overline_semiBold`, `buttonLarge`/`buttonMedium`/`buttonSmall`, `chip`) use **Open Sans**.
|
|
7
|
+
- 2026 tokens (`body_lg_*`–`body_xs_*`, `heading_lg_*`–`heading_sm_*`, `display_lg_*`/`display_md_*`, `caption_regular`/`caption_medium`, `overline_regular`) use **Inter**.
|
|
4
8
|
|
|
5
9
|
## Heading variants
|
|
6
10
|
|
|
@@ -68,12 +72,68 @@ Map Figma text styles to `<Typography variant="...">`. Font family is **Open San
|
|
|
68
72
|
| `buttonSmall` | 12 | 500 | 20px | 0.4px |
|
|
69
73
|
| `chip` | 12 | 500 | 12px | 0.4px |
|
|
70
74
|
|
|
75
|
+
## Typography 2026 tokens (Inter)
|
|
76
|
+
|
|
77
|
+
Canonical 2026 design tokens. Use these for new UI built against the 2026 design system. Font family is **Inter**.
|
|
78
|
+
|
|
79
|
+
### Display
|
|
80
|
+
|
|
81
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
82
|
+
|---------|----------|------------|------------|---------------|
|
|
83
|
+
| `display_lg_semiBold` | 28 | 600 | 36px | 0.01em |
|
|
84
|
+
| `display_lg_bold` | 28 | 700 | 36px | 0.01em |
|
|
85
|
+
| `display_md_semiBold` | 24 | 600 | 32px | 0.01em |
|
|
86
|
+
| `display_md_bold` | 24 | 700 | 32px | 0.01em |
|
|
87
|
+
|
|
88
|
+
### Heading
|
|
89
|
+
|
|
90
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
91
|
+
|---------|----------|------------|------------|---------------|
|
|
92
|
+
| `heading_lg_medium` | 20 | 500 | 28px | -0.005em |
|
|
93
|
+
| `heading_lg_semiBold` | 20 | 600 | 28px | -0.005em |
|
|
94
|
+
| `heading_md_medium` | 18 | 500 | 28px | -0.005em |
|
|
95
|
+
| `heading_md_semiBold` | 18 | 600 | 28px | -0.005em |
|
|
96
|
+
| `heading_sm_medium` | 16 | 500 | 22px | -0.005em |
|
|
97
|
+
| `heading_sm_semiBold` | 16 | 600 | 22px | -0.005em |
|
|
98
|
+
|
|
99
|
+
### Body
|
|
100
|
+
|
|
101
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
102
|
+
|---------|----------|------------|------------|---------------|
|
|
103
|
+
| `body_lg_regular` | 16 | 400 | 24px | -0.005em |
|
|
104
|
+
| `body_lg_medium` | 16 | 500 | 24px | -0.005em |
|
|
105
|
+
| `body_lg_semiBold` | 16 | 600 | 24px | -0.005em |
|
|
106
|
+
| `body_md_regular` | 14 | 400 | 20px | -0.005em |
|
|
107
|
+
| `body_md_medium` | 14 | 500 | 20px | -0.005em |
|
|
108
|
+
| `body_md_semiBold` | 14 | 600 | 20px | -0.005em |
|
|
109
|
+
| `body_sm_regular` | 13 | 400 | 19px | -0.005em |
|
|
110
|
+
| `body_sm_medium` | 13 | 500 | 19px | -0.005em |
|
|
111
|
+
| `body_sm_semiBold` | 13 | 600 | 19px | -0.005em |
|
|
112
|
+
| `body_xs_regular` | 12 | 400 | 18px | -0.005em |
|
|
113
|
+
| `body_xs_medium` | 12 | 500 | 18px | -0.005em |
|
|
114
|
+
| `body_xs_semiBold` | 12 | 600 | 18px | -0.005em |
|
|
115
|
+
|
|
116
|
+
### Caption & overline (2026)
|
|
117
|
+
|
|
118
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing | Notes |
|
|
119
|
+
|---------|----------|------------|------------|---------------|-------|
|
|
120
|
+
| `caption_regular` | 12 | 400 | 14px | 0.01em | |
|
|
121
|
+
| `caption_medium` | 12 | 500 | 14px | 0.01em | |
|
|
122
|
+
| `overline_regular` | 12 | 400 | 14px | 0.01em | UPPERCASE |
|
|
123
|
+
|
|
124
|
+
> Note: a 2026 `overline_medium` token also exists in the theme (Inter, 12 / 500 / 14px / 0.01em / UPPERCASE) and shares its name with the legacy Open Sans `overline_medium` (11 / 500 / 18px). The 2026 spread is applied after the legacy block, so the Inter version wins at runtime — use accordingly.
|
|
125
|
+
|
|
71
126
|
## Usage
|
|
72
127
|
|
|
73
128
|
```jsx
|
|
74
129
|
<Typography variant="h2_medium">Section title</Typography>
|
|
75
130
|
<Typography variant="body1_regular">Body text</Typography>
|
|
76
131
|
<Typography variant="caption1_medium" color="text.secondary">Caption</Typography>
|
|
132
|
+
|
|
133
|
+
// 2026 tokens
|
|
134
|
+
<Typography variant="heading_lg_semiBold">Page title</Typography>
|
|
135
|
+
<Typography variant="body_md_regular">Body text</Typography>
|
|
136
|
+
<Typography variant="display_lg_bold">Hero</Typography>
|
|
77
137
|
```
|
|
78
138
|
|
|
79
|
-
**Figma → variant:** Compare Figma text style fontSize and weight (Regular/Medium/Semi Bold/Bold) to the tables above and pick the closest match.
|
|
139
|
+
**Figma → variant:** Compare Figma text style fontSize and weight (Regular/Medium/Semi Bold/Bold) to the tables above and pick the closest match. For new 2026 designs, prefer the Inter tokens.
|
|
@@ -1,8 +1,81 @@
|
|
|
1
1
|
# Icons
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
How to import from `@hiver/hiver-ui-kit`:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { brandIcons, icons } from '@hiver/hiver-ui-kit';
|
|
7
|
+
// <brandIcons.Star />
|
|
8
|
+
// <icons.AccountCircle />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Resolution priority
|
|
12
|
+
|
|
13
|
+
When a Figma design contains an icon, resolve it in this order:
|
|
14
|
+
|
|
15
|
+
1. **User-provided SVG asset** — if the user supplied an `.svg` file, import it directly:
|
|
16
|
+
```js
|
|
17
|
+
import iconName from 'path/to/icon.svg';
|
|
18
|
+
<img src={iconName} alt="description" />
|
|
19
|
+
```
|
|
20
|
+
2. **`brandIcons`** — Hiver-designed icons (see "Brand icon catalog" below).
|
|
21
|
+
3. **`icons`** — curated MUI icons re-exported from hui-kit (see "MUI icon catalog" below).
|
|
22
|
+
4. **`@mui/icons-material`** — **last resort only**, when the icon is not in the design system **and** the user has not provided an asset.
|
|
23
|
+
5. **Never** import icons from FontAwesome, Heroicons, or any other third-party icon library.
|
|
24
|
+
|
|
25
|
+
## How to match a Figma icon to a code name
|
|
26
|
+
|
|
27
|
+
1. **Prefer the Figma layer/component name** if the design exposes one (e.g. a layer named `Brand/Star` → `brandIcons.Star`).
|
|
28
|
+
2. **Otherwise, match visually** against the catalog sheets embedded below. Each icon is rendered with its exact export name underneath.
|
|
29
|
+
3. The export name is what you use in code — including any typos preserved from the design system (see Notes).
|
|
30
|
+
|
|
31
|
+
## Brand icon catalog (`brandIcons`)
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
**Hiver Logo**
|
|
36
|
+
- `Logo`
|
|
37
|
+
|
|
38
|
+
**Brand icons** (box 20×20, live area 18×18, stroke 1.4)
|
|
39
|
+
- `SharedMailbox`, `Analytics`, `EmailTemplates`, `Settings`, `HiverAlerts`, `Activity`, `AutoAssignment`, `Workload`, `Lable`, `Permalink`
|
|
40
|
+
- `Star`, `Edit`, `Filters`, `HiverChat`, `AircallPhone`, `Aavatar`, `Unassigned`, `Mine`, `Team`, `Pending`
|
|
41
|
+
- `Closed`, `Tags`, `Crown`, `Dashboard`, `DashboardInactive`, `SharedInboxNav`, `SharedInboxNavInactive`, `SharedLabel`, `SharedLabelInactive`, `KnowledgeBase`
|
|
42
|
+
- `KnowledgeBaseInactive`, `Connector`, `ConnectorInactive`, `SettingsNav`, `SettingsNavInactive`, `UserRole`, `UserRoleInactive`
|
|
43
|
+
|
|
44
|
+
**Activity icons** (box 20×20, live area 16×16, stroke 1.4)
|
|
45
|
+
- `Status`, `Tag`, `Inbox`, `AlertTriangle`, `EnvelopeDownload`, `ActivityStar`, `EnvelopeUpload`, `Envelope`, `ActivityEdit`, `CloseCircle`, `CheckAction`, `UserCheck`
|
|
46
|
+
|
|
47
|
+
**Settings icons** (box 24×24, live area 22×22, stroke 1.4)
|
|
48
|
+
- `AdminPanel`, `Sliders`, `Compass`, `SwitchAccount`, `Gift`, `MessageCircle`, `LifeBuoy`
|
|
49
|
+
|
|
50
|
+
## MUI icon catalog (`icons`)
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
- `AccountCircle`, `Add`, `Alarm`, `Close`, `Phone`, `ArchiveOutlined`, `ArrowBack`, `ArrowBackIos`, `ArrowDropDown`, `ArrowDropUp`, `ArrowForward`
|
|
55
|
+
- `ArrowOutward`, `CalendarToday`, `CalendarTodayOutlined`, `CalendarTodayOutlinedIcon`, `Cancel`, `CancelOutlined`, `CheckCircle`, `ChevronRightOutlined`, `CodeSharp`, `DeleteOutline`, `DownloadOutlined`
|
|
56
|
+
- `DragIndicator`, `EditOutlined`, `Error`, `ErrorOutline`, `GroupsOutlined`, `InfoOutlined`, `LabelOutlined`, `Link`, `LockOutlined`, `MailOutlined`, `MicNone`
|
|
57
|
+
- `MoreVert`, `NotificationsOutlined`, `OpenInNew`, `Pause`, `PersonOutline`, `PersonOutlined`, `PlayArrow`, `Public`, `Search`, `Settings`, `SettingsOutlined`
|
|
58
|
+
- `StickyNote2Outlined`, `ThumbDownAlt`, `ThumbDownOffAlt`, `ThumbUpAlt`, `ThumbUpOffAlt`, `TimerOutlined`, `TrackChanges`, `UnarchiveOutlined`, `Voicemail`, `Warning`, `WarningAmber`
|
|
59
|
+
- `ArrowRightAlt`, `Delete`, `Email`, `Favorite`
|
|
60
|
+
|
|
61
|
+
## Notes — Figma → code gotchas
|
|
62
|
+
|
|
63
|
+
- **Typos preserved in exports** — these match the Figma names, so map literally; do not auto-correct:
|
|
64
|
+
- `Lable` (not `Label`)
|
|
65
|
+
- `Aavatar` (not `Avatar`)
|
|
66
|
+
- **`Edit` collision** — three similar icons:
|
|
67
|
+
- `brandIcons.Edit` — pen-on-paper brand icon (yellow accent)
|
|
68
|
+
- `brandIcons.ActivityEdit` — green envelope with a pen, activity style
|
|
69
|
+
- `icons.EditOutlined` — plain MUI outlined pencil
|
|
70
|
+
- **`Settings` collision** — five similar names:
|
|
71
|
+
- `brandIcons.Settings`, `brandIcons.SettingsNav`, `brandIcons.SettingsNavInactive`
|
|
72
|
+
- `icons.Settings`, `icons.SettingsOutlined`
|
|
73
|
+
Pick by Figma category section and visual.
|
|
74
|
+
- **`Star` collision**:
|
|
75
|
+
- `brandIcons.Star` — yellow filled brand star
|
|
76
|
+
- `brandIcons.ActivityStar` — purple activity star
|
|
77
|
+
- **`Tag` vs `Tags`**:
|
|
78
|
+
- `brandIcons.Tags` — brand (plural, box 20×20 live 18×18)
|
|
79
|
+
- `brandIcons.Tag` — activity (singular, box 20×20 live 16×16)
|
|
80
|
+
- **Inactive variants** — many brand icons have `*Inactive` siblings (`DashboardInactive`, `SharedInboxNavInactive`, `SharedLabelInactive`, `KnowledgeBaseInactive`, `ConnectorInactive`, `SettingsNavInactive`, `UserRoleInactive`). Use the inactive variant for the unselected/disabled state of a nav item.
|
|
81
|
+
- **`UserCheck`** — present in `brandIcons` exports but not visible on the current Figma sheet. Use it if a design clearly needs it; otherwise prefer the activity-style icons documented above.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Typography reference (`@hiver/hiver-ui-kit`)
|
|
2
2
|
|
|
3
|
-
Map Figma text styles to `<Typography variant="...">`.
|
|
3
|
+
Map Figma text styles to `<Typography variant="...">`. Match by fontSize + fontWeight (regular 400, medium 500, semiBold 600, bold 700).
|
|
4
|
+
|
|
5
|
+
**Font families:**
|
|
6
|
+
- Legacy variants (`h1_*`–`h5_*`, `body0_5_*`–`body4_*`, `caption1_*`, `caption2_*`, `overline_medium`, `overline_semiBold`, `buttonLarge`/`buttonMedium`/`buttonSmall`, `chip`) use **Open Sans**.
|
|
7
|
+
- 2026 tokens (`body_lg_*`–`body_xs_*`, `heading_lg_*`–`heading_sm_*`, `display_lg_*`/`display_md_*`, `caption_regular`/`caption_medium`, `overline_regular`) use **Inter**.
|
|
4
8
|
|
|
5
9
|
## Heading variants
|
|
6
10
|
|
|
@@ -68,12 +72,68 @@ Map Figma text styles to `<Typography variant="...">`. Font family is **Open San
|
|
|
68
72
|
| `buttonSmall` | 12 | 500 | 20px | 0.4px |
|
|
69
73
|
| `chip` | 12 | 500 | 12px | 0.4px |
|
|
70
74
|
|
|
75
|
+
## Typography 2026 tokens (Inter)
|
|
76
|
+
|
|
77
|
+
Canonical 2026 design tokens. Use these for new UI built against the 2026 design system. Font family is **Inter**.
|
|
78
|
+
|
|
79
|
+
### Display
|
|
80
|
+
|
|
81
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
82
|
+
|---------|----------|------------|------------|---------------|
|
|
83
|
+
| `display_lg_semiBold` | 28 | 600 | 36px | 0.01em |
|
|
84
|
+
| `display_lg_bold` | 28 | 700 | 36px | 0.01em |
|
|
85
|
+
| `display_md_semiBold` | 24 | 600 | 32px | 0.01em |
|
|
86
|
+
| `display_md_bold` | 24 | 700 | 32px | 0.01em |
|
|
87
|
+
|
|
88
|
+
### Heading
|
|
89
|
+
|
|
90
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
91
|
+
|---------|----------|------------|------------|---------------|
|
|
92
|
+
| `heading_lg_medium` | 20 | 500 | 28px | -0.005em |
|
|
93
|
+
| `heading_lg_semiBold` | 20 | 600 | 28px | -0.005em |
|
|
94
|
+
| `heading_md_medium` | 18 | 500 | 28px | -0.005em |
|
|
95
|
+
| `heading_md_semiBold` | 18 | 600 | 28px | -0.005em |
|
|
96
|
+
| `heading_sm_medium` | 16 | 500 | 22px | -0.005em |
|
|
97
|
+
| `heading_sm_semiBold` | 16 | 600 | 22px | -0.005em |
|
|
98
|
+
|
|
99
|
+
### Body
|
|
100
|
+
|
|
101
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing |
|
|
102
|
+
|---------|----------|------------|------------|---------------|
|
|
103
|
+
| `body_lg_regular` | 16 | 400 | 24px | -0.005em |
|
|
104
|
+
| `body_lg_medium` | 16 | 500 | 24px | -0.005em |
|
|
105
|
+
| `body_lg_semiBold` | 16 | 600 | 24px | -0.005em |
|
|
106
|
+
| `body_md_regular` | 14 | 400 | 20px | -0.005em |
|
|
107
|
+
| `body_md_medium` | 14 | 500 | 20px | -0.005em |
|
|
108
|
+
| `body_md_semiBold` | 14 | 600 | 20px | -0.005em |
|
|
109
|
+
| `body_sm_regular` | 13 | 400 | 19px | -0.005em |
|
|
110
|
+
| `body_sm_medium` | 13 | 500 | 19px | -0.005em |
|
|
111
|
+
| `body_sm_semiBold` | 13 | 600 | 19px | -0.005em |
|
|
112
|
+
| `body_xs_regular` | 12 | 400 | 18px | -0.005em |
|
|
113
|
+
| `body_xs_medium` | 12 | 500 | 18px | -0.005em |
|
|
114
|
+
| `body_xs_semiBold` | 12 | 600 | 18px | -0.005em |
|
|
115
|
+
|
|
116
|
+
### Caption & overline (2026)
|
|
117
|
+
|
|
118
|
+
| Variant | fontSize | fontWeight | lineHeight | letterSpacing | Notes |
|
|
119
|
+
|---------|----------|------------|------------|---------------|-------|
|
|
120
|
+
| `caption_regular` | 12 | 400 | 14px | 0.01em | |
|
|
121
|
+
| `caption_medium` | 12 | 500 | 14px | 0.01em | |
|
|
122
|
+
| `overline_regular` | 12 | 400 | 14px | 0.01em | UPPERCASE |
|
|
123
|
+
|
|
124
|
+
> Note: a 2026 `overline_medium` token also exists in the theme (Inter, 12 / 500 / 14px / 0.01em / UPPERCASE) and shares its name with the legacy Open Sans `overline_medium` (11 / 500 / 18px). The 2026 spread is applied after the legacy block, so the Inter version wins at runtime — use accordingly.
|
|
125
|
+
|
|
71
126
|
## Usage
|
|
72
127
|
|
|
73
128
|
```jsx
|
|
74
129
|
<Typography variant="h2_medium">Section title</Typography>
|
|
75
130
|
<Typography variant="body1_regular">Body text</Typography>
|
|
76
131
|
<Typography variant="caption1_medium" color="text.secondary">Caption</Typography>
|
|
132
|
+
|
|
133
|
+
// 2026 tokens
|
|
134
|
+
<Typography variant="heading_lg_semiBold">Page title</Typography>
|
|
135
|
+
<Typography variant="body_md_regular">Body text</Typography>
|
|
136
|
+
<Typography variant="display_lg_bold">Hero</Typography>
|
|
77
137
|
```
|
|
78
138
|
|
|
79
|
-
**Figma → variant:** Compare Figma text style fontSize and weight (Regular/Medium/Semi Bold/Bold) to the tables above and pick the closest match.
|
|
139
|
+
**Figma → variant:** Compare Figma text style fontSize and weight (Regular/Medium/Semi Bold/Bold) to the tables above and pick the closest match. For new 2026 designs, prefer the Inter tokens.
|
package/dist/cli.js
CHANGED
|
@@ -239,6 +239,15 @@ function getAgentMeta(collectionName, agentName) {
|
|
|
239
239
|
dependencies: Array.isArray(fm.dependencies) ? fm.dependencies : []
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
|
+
function findCollectionsContaining(name, type) {
|
|
243
|
+
const matches = [];
|
|
244
|
+
for (const col of listCollections()) {
|
|
245
|
+
const { skills, agents } = scanCollection(col);
|
|
246
|
+
if (type === "skill" && skills.includes(name)) matches.push(col);
|
|
247
|
+
if (type === "agent" && agents.includes(name)) matches.push(col);
|
|
248
|
+
}
|
|
249
|
+
return matches;
|
|
250
|
+
}
|
|
242
251
|
function resolveDependencies(selected, selectedCollections) {
|
|
243
252
|
const installedNames = /* @__PURE__ */ new Set([
|
|
244
253
|
...selected.skills.map((s) => s.name),
|
|
@@ -341,34 +350,8 @@ function Add({ directSkills }) {
|
|
|
341
350
|
const [selectedType, setSelectedType] = useState3(null);
|
|
342
351
|
const [toInstall, setToInstall] = useState3({ skills: [], agents: [] });
|
|
343
352
|
const [results, setResults] = useState3({ skills: 0, agents: 0, deps: [] });
|
|
353
|
+
const [directMissing, setDirectMissing] = useState3([]);
|
|
344
354
|
const destRoot = process.cwd();
|
|
345
|
-
useEffect(() => {
|
|
346
|
-
if (directSkills && directSkills.length > 0 && targetKey) {
|
|
347
|
-
installByName(directSkills, targets[targetKey], destRoot).then((res) => {
|
|
348
|
-
setResults(res);
|
|
349
|
-
setStep(STEPS.DONE);
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
}, [targetKey]);
|
|
353
|
-
async function installByName(names, targetConfig, dest) {
|
|
354
|
-
const collections = listCollections();
|
|
355
|
-
let skillCount = 0;
|
|
356
|
-
let agentCount = 0;
|
|
357
|
-
for (const name of names) {
|
|
358
|
-
for (const col of collections) {
|
|
359
|
-
const { skills, agents } = scanCollection(col);
|
|
360
|
-
if (skills.includes(name)) {
|
|
361
|
-
if (await installSkill(col, name, targetConfig, dest)) skillCount++;
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
if (agents.includes(name)) {
|
|
365
|
-
if (await installAgent(col, name, targetConfig, dest)) agentCount++;
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
return { skills: skillCount, agents: agentCount, deps: [] };
|
|
371
|
-
}
|
|
372
355
|
function getAvailableTypes(col) {
|
|
373
356
|
const { skills, agents } = scanCollection(col);
|
|
374
357
|
const types = [];
|
|
@@ -378,11 +361,29 @@ function Add({ directSkills }) {
|
|
|
378
361
|
}
|
|
379
362
|
function handleTargetSelect(key) {
|
|
380
363
|
setTargetKey(key);
|
|
381
|
-
if (directSkills && directSkills.length > 0) return;
|
|
382
364
|
setStep(STEPS.COLLECTIONS);
|
|
383
365
|
}
|
|
384
366
|
function handleCollectionSelect(col) {
|
|
385
367
|
setSelectedCollection(col);
|
|
368
|
+
if (directSkills && directSkills.length > 0) {
|
|
369
|
+
const { skills, agents } = scanCollection(col);
|
|
370
|
+
const skillItems = [];
|
|
371
|
+
const agentItems = [];
|
|
372
|
+
const missing = [];
|
|
373
|
+
for (const name of directSkills) {
|
|
374
|
+
if (skills.includes(name)) skillItems.push({ collection: col, name });
|
|
375
|
+
else if (agents.includes(name)) agentItems.push({ collection: col, name });
|
|
376
|
+
else missing.push(`${name} (not in ${col})`);
|
|
377
|
+
}
|
|
378
|
+
setDirectMissing(missing);
|
|
379
|
+
setToInstall({ skills: skillItems, agents: agentItems });
|
|
380
|
+
if (skillItems.length === 0 && agentItems.length === 0) {
|
|
381
|
+
setStep(STEPS.DONE);
|
|
382
|
+
} else {
|
|
383
|
+
setStep(STEPS.INSTALLING);
|
|
384
|
+
}
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
386
387
|
setToInstall({ skills: [], agents: [] });
|
|
387
388
|
const types = getAvailableTypes(col);
|
|
388
389
|
if (types.length === 1) {
|
|
@@ -466,8 +467,24 @@ function Add({ directSkills }) {
|
|
|
466
467
|
);
|
|
467
468
|
}
|
|
468
469
|
if (step === STEPS.COLLECTIONS) {
|
|
469
|
-
|
|
470
|
+
let collections = listCollections();
|
|
471
|
+
if (directSkills && directSkills.length > 0) {
|
|
472
|
+
const union = /* @__PURE__ */ new Set();
|
|
473
|
+
for (const name of directSkills) {
|
|
474
|
+
for (const c of findCollectionsContaining(name, "skill")) union.add(c);
|
|
475
|
+
for (const c of findCollectionsContaining(name, "agent")) union.add(c);
|
|
476
|
+
}
|
|
477
|
+
collections = collections.filter((c) => union.has(c));
|
|
478
|
+
}
|
|
470
479
|
const items = collections.map((c) => ({ label: c, value: c }));
|
|
480
|
+
if (items.length === 0) {
|
|
481
|
+
setTimeout(() => exit(), 100);
|
|
482
|
+
return /* @__PURE__ */ jsxs4(ErrorMsg, { children: [
|
|
483
|
+
"None of: ",
|
|
484
|
+
directSkills.join(", "),
|
|
485
|
+
" found in any collection."
|
|
486
|
+
] });
|
|
487
|
+
}
|
|
471
488
|
return /* @__PURE__ */ jsx3(
|
|
472
489
|
Select,
|
|
473
490
|
{
|
|
@@ -530,6 +547,10 @@ function Add({ directSkills }) {
|
|
|
530
547
|
if (step === STEPS.DONE) {
|
|
531
548
|
setTimeout(() => exit(), 100);
|
|
532
549
|
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
550
|
+
directMissing.length > 0 && /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsxs4(ErrorMsg, { children: [
|
|
551
|
+
"Not found in any collection: ",
|
|
552
|
+
directMissing.join(", ")
|
|
553
|
+
] }) }),
|
|
533
554
|
results.deps.length > 0 && /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", marginBottom: 1, children: [
|
|
534
555
|
/* @__PURE__ */ jsx3(Info, { children: "Auto-installed dependencies:" }),
|
|
535
556
|
results.deps.map((d) => /* @__PURE__ */ jsxs4(Text4, { color: "cyan", children: [
|
|
@@ -690,88 +711,161 @@ function hasChanges(localContent, latestContent) {
|
|
|
690
711
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
691
712
|
var STEPS2 = {
|
|
692
713
|
TARGET: "target",
|
|
693
|
-
|
|
714
|
+
COLLECTION: "collection",
|
|
715
|
+
ITEMS: "items",
|
|
716
|
+
RESOLVE: "resolve",
|
|
694
717
|
CONFIRM: "confirm",
|
|
695
718
|
DONE: "done"
|
|
696
719
|
};
|
|
697
|
-
function
|
|
720
|
+
function detectType(name, targetConfig, destRoot) {
|
|
721
|
+
const skillPath = path3.join(destRoot, targetConfig.skillsDir, name, "SKILL.md");
|
|
722
|
+
if (fs3.existsSync(skillPath)) return "skill";
|
|
723
|
+
const agentPath = path3.join(destRoot, targetConfig.agentsDir, `${name}.md`);
|
|
724
|
+
if (fs3.existsSync(agentPath)) return "agent";
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
function Update({ directSkills }) {
|
|
698
728
|
const { exit } = useApp3();
|
|
699
729
|
const [step, setStep] = useState4(STEPS2.TARGET);
|
|
700
730
|
const [targetKey, setTargetKey] = useState4(null);
|
|
701
|
-
const [
|
|
731
|
+
const [selectedCollection, setSelectedCollection] = useState4(null);
|
|
732
|
+
const [queue, setQueue] = useState4([]);
|
|
702
733
|
const [currentIdx, setCurrentIdx] = useState4(0);
|
|
734
|
+
const [currentPatch, setCurrentPatch] = useState4(null);
|
|
703
735
|
const [updatedCount, setUpdatedCount] = useState4(0);
|
|
704
736
|
const [skippedCount, setSkippedCount] = useState4(0);
|
|
737
|
+
const [installedCount, setInstalledCount] = useState4(0);
|
|
738
|
+
const [missingNames, setMissingNames] = useState4([]);
|
|
739
|
+
const [directInfo, setDirectInfo] = useState4([]);
|
|
705
740
|
const destRoot = process.cwd();
|
|
706
|
-
function
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
741
|
+
function handleTargetSelect(key) {
|
|
742
|
+
setTargetKey(key);
|
|
743
|
+
if (directSkills && directSkills.length > 0) {
|
|
744
|
+
const targetConfig = targets[key];
|
|
745
|
+
const info = [];
|
|
746
|
+
const missing = [];
|
|
747
|
+
for (const name of directSkills) {
|
|
748
|
+
let type = detectType(name, targetConfig, destRoot);
|
|
749
|
+
let installed = type !== null;
|
|
750
|
+
if (!type) {
|
|
751
|
+
if (findCollectionsContaining(name, "skill").length > 0) type = "skill";
|
|
752
|
+
else if (findCollectionsContaining(name, "agent").length > 0) type = "agent";
|
|
753
|
+
}
|
|
754
|
+
if (!type) {
|
|
755
|
+
missing.push(name);
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
const cols = findCollectionsContaining(name, type);
|
|
759
|
+
if (cols.length === 0) {
|
|
760
|
+
missing.push(name);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
info.push({ name, type, installed, collections: cols });
|
|
764
|
+
}
|
|
765
|
+
setMissingNames(missing);
|
|
766
|
+
setDirectInfo(info);
|
|
767
|
+
if (info.length === 0) {
|
|
768
|
+
setStep(STEPS2.DONE);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
711
771
|
}
|
|
712
|
-
|
|
772
|
+
setStep(STEPS2.COLLECTION);
|
|
713
773
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const localContent = fs3.readFileSync(localFile, "utf-8");
|
|
726
|
-
const latestContent = fs3.readFileSync(latestFile, "utf-8");
|
|
727
|
-
if (hasChanges(localContent, latestContent)) {
|
|
728
|
-
changed.push({
|
|
729
|
-
name: skillName,
|
|
730
|
-
type: "skill",
|
|
731
|
-
collection: source.collection,
|
|
732
|
-
patch: computeDiff("SKILL.md", localContent, latestContent)
|
|
733
|
-
});
|
|
774
|
+
function handleCollectionSelect(collection) {
|
|
775
|
+
setSelectedCollection(collection);
|
|
776
|
+
if (directSkills && directSkills.length > 0) {
|
|
777
|
+
const items = [];
|
|
778
|
+
const skipped = [];
|
|
779
|
+
for (const entry of directInfo) {
|
|
780
|
+
if (entry.collections.includes(collection)) {
|
|
781
|
+
items.push({ name: entry.name, type: entry.type, installed: entry.installed });
|
|
782
|
+
} else {
|
|
783
|
+
skipped.push(`${entry.name} (not in ${collection})`);
|
|
784
|
+
}
|
|
734
785
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (hasChanges(localContent, latestContent)) {
|
|
745
|
-
changed.push({
|
|
746
|
-
name: agentName,
|
|
747
|
-
type: "agent",
|
|
748
|
-
collection: source.collection,
|
|
749
|
-
patch: computeDiff(`${agentName}.md`, localContent, latestContent)
|
|
750
|
-
});
|
|
786
|
+
if (skipped.length > 0) {
|
|
787
|
+
setMissingNames((prev) => [...prev, ...skipped]);
|
|
788
|
+
}
|
|
789
|
+
setQueue(items);
|
|
790
|
+
setCurrentIdx(0);
|
|
791
|
+
if (items.length === 0) {
|
|
792
|
+
setStep(STEPS2.DONE);
|
|
793
|
+
} else {
|
|
794
|
+
setStep(STEPS2.RESOLVE);
|
|
751
795
|
}
|
|
796
|
+
} else {
|
|
797
|
+
setStep(STEPS2.ITEMS);
|
|
752
798
|
}
|
|
753
|
-
|
|
754
|
-
|
|
799
|
+
}
|
|
800
|
+
function handleItemsSubmit(values) {
|
|
801
|
+
const items = values.map((v) => {
|
|
802
|
+
const [type, name] = v.split(":");
|
|
803
|
+
return { name, type, installed: true };
|
|
804
|
+
});
|
|
805
|
+
setQueue(items);
|
|
806
|
+
setCurrentIdx(0);
|
|
807
|
+
if (items.length === 0) {
|
|
755
808
|
setStep(STEPS2.DONE);
|
|
756
809
|
} else {
|
|
757
|
-
|
|
758
|
-
setStep(STEPS2.CONFIRM);
|
|
810
|
+
setStep(STEPS2.RESOLVE);
|
|
759
811
|
}
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
812
|
+
}
|
|
813
|
+
useEffect2(() => {
|
|
814
|
+
if (step !== STEPS2.RESOLVE) return;
|
|
815
|
+
const item = queue[currentIdx];
|
|
816
|
+
if (!item) {
|
|
817
|
+
setStep(STEPS2.DONE);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
processItem(item);
|
|
821
|
+
}, [step, currentIdx]);
|
|
822
|
+
async function processItem(item) {
|
|
823
|
+
const targetConfig = targets[targetKey];
|
|
824
|
+
const collection = selectedCollection;
|
|
825
|
+
if (!item.installed) {
|
|
826
|
+
if (item.type === "skill") {
|
|
827
|
+
await installSkill(collection, item.name, targetConfig, destRoot);
|
|
828
|
+
} else {
|
|
829
|
+
await installAgent(collection, item.name, targetConfig, destRoot);
|
|
830
|
+
}
|
|
831
|
+
setInstalledCount((c) => c + 1);
|
|
832
|
+
advance();
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
let localFile;
|
|
836
|
+
let latestFile;
|
|
837
|
+
if (item.type === "skill") {
|
|
838
|
+
localFile = path3.join(destRoot, targetConfig.skillsDir, item.name, "SKILL.md");
|
|
839
|
+
latestFile = path3.join(getCollectionsDir(), collection, "skills", item.name, "SKILL.md");
|
|
840
|
+
} else {
|
|
841
|
+
localFile = path3.join(destRoot, targetConfig.agentsDir, `${item.name}.md`);
|
|
842
|
+
latestFile = path3.join(getCollectionsDir(), collection, "agents", `${item.name}.md`);
|
|
843
|
+
}
|
|
844
|
+
if (!fs3.existsSync(localFile) || !fs3.existsSync(latestFile)) {
|
|
845
|
+
advance();
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const localContent = fs3.readFileSync(localFile, "utf-8");
|
|
849
|
+
const latestContent = fs3.readFileSync(latestFile, "utf-8");
|
|
850
|
+
if (!hasChanges(localContent, latestContent)) {
|
|
851
|
+
setSkippedCount((c) => c + 1);
|
|
852
|
+
advance();
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const filename = item.type === "skill" ? "SKILL.md" : `${item.name}.md`;
|
|
856
|
+
setCurrentPatch(computeDiff(filename, localContent, latestContent));
|
|
857
|
+
setStep(STEPS2.CONFIRM);
|
|
764
858
|
}
|
|
765
859
|
function handleConfirm(yes) {
|
|
766
|
-
const item =
|
|
860
|
+
const item = queue[currentIdx];
|
|
767
861
|
const targetConfig = targets[targetKey];
|
|
768
862
|
if (yes) {
|
|
769
863
|
if (item.type === "skill") {
|
|
770
|
-
const src = path3.join(getCollectionsDir(),
|
|
864
|
+
const src = path3.join(getCollectionsDir(), selectedCollection, "skills", item.name);
|
|
771
865
|
const dest = path3.join(destRoot, targetConfig.skillsDir, item.name);
|
|
772
866
|
fs3.copySync(src, dest, { overwrite: true });
|
|
773
867
|
} else {
|
|
774
|
-
const src = path3.join(getCollectionsDir(),
|
|
868
|
+
const src = path3.join(getCollectionsDir(), selectedCollection, "agents", `${item.name}.md`);
|
|
775
869
|
const dest = path3.join(destRoot, targetConfig.agentsDir, `${item.name}.md`);
|
|
776
870
|
fs3.copySync(src, dest, { overwrite: true });
|
|
777
871
|
}
|
|
@@ -779,39 +873,119 @@ function Update() {
|
|
|
779
873
|
} else {
|
|
780
874
|
setSkippedCount((c) => c + 1);
|
|
781
875
|
}
|
|
782
|
-
|
|
876
|
+
advance();
|
|
877
|
+
}
|
|
878
|
+
function advance() {
|
|
879
|
+
setCurrentPatch(null);
|
|
880
|
+
if (currentIdx + 1 < queue.length) {
|
|
783
881
|
setCurrentIdx((i) => i + 1);
|
|
882
|
+
setStep(STEPS2.RESOLVE);
|
|
784
883
|
} else {
|
|
785
884
|
setStep(STEPS2.DONE);
|
|
786
885
|
}
|
|
787
886
|
}
|
|
788
887
|
if (step === STEPS2.TARGET) {
|
|
789
|
-
return /* @__PURE__ */ jsx7(
|
|
888
|
+
return /* @__PURE__ */ jsx7(
|
|
889
|
+
Select,
|
|
890
|
+
{
|
|
891
|
+
items: targetList,
|
|
892
|
+
onSelect: handleTargetSelect,
|
|
893
|
+
onBack: () => exit(),
|
|
894
|
+
message: "Which target to update?"
|
|
895
|
+
}
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
if (step === STEPS2.COLLECTION) {
|
|
899
|
+
let collectionNames;
|
|
900
|
+
if (directSkills && directSkills.length > 0) {
|
|
901
|
+
const union = /* @__PURE__ */ new Set();
|
|
902
|
+
for (const entry of directInfo) {
|
|
903
|
+
for (const c of entry.collections) union.add(c);
|
|
904
|
+
}
|
|
905
|
+
collectionNames = listCollections().filter((c) => union.has(c));
|
|
906
|
+
} else {
|
|
907
|
+
collectionNames = listCollections();
|
|
908
|
+
}
|
|
909
|
+
const items = collectionNames.map((c) => ({ label: c, value: c }));
|
|
910
|
+
return /* @__PURE__ */ jsx7(
|
|
911
|
+
Select,
|
|
912
|
+
{
|
|
913
|
+
items,
|
|
914
|
+
onSelect: handleCollectionSelect,
|
|
915
|
+
onBack: () => setStep(STEPS2.TARGET),
|
|
916
|
+
message: "Pick collection to update from:"
|
|
917
|
+
}
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
if (step === STEPS2.ITEMS) {
|
|
921
|
+
const targetConfig = targets[targetKey];
|
|
922
|
+
const installed = listInstalled(targetConfig, destRoot);
|
|
923
|
+
const { skills, agents } = scanCollection(selectedCollection);
|
|
924
|
+
const items = [
|
|
925
|
+
...installed.skills.filter((name) => skills.includes(name)).map((name) => ({
|
|
926
|
+
label: `${name} (skill)`,
|
|
927
|
+
value: `skill:${name}`,
|
|
928
|
+
checked: false
|
|
929
|
+
})),
|
|
930
|
+
...installed.agents.filter((name) => agents.includes(name)).map((name) => ({
|
|
931
|
+
label: `${name} (agent)`,
|
|
932
|
+
value: `agent:${name}`,
|
|
933
|
+
checked: false
|
|
934
|
+
}))
|
|
935
|
+
];
|
|
936
|
+
if (items.length === 0) {
|
|
937
|
+
setTimeout(() => exit(), 100);
|
|
938
|
+
return /* @__PURE__ */ jsxs7(Info, { children: [
|
|
939
|
+
'No installed skills/agents from "',
|
|
940
|
+
selectedCollection,
|
|
941
|
+
'" under ',
|
|
942
|
+
targetConfig.skillsDir,
|
|
943
|
+
"/."
|
|
944
|
+
] });
|
|
945
|
+
}
|
|
946
|
+
return /* @__PURE__ */ jsx7(
|
|
947
|
+
MultiSelect,
|
|
948
|
+
{
|
|
949
|
+
items,
|
|
950
|
+
onSubmit: handleItemsSubmit,
|
|
951
|
+
onBack: () => setStep(STEPS2.COLLECTION),
|
|
952
|
+
message: `Select skills/agents from "${selectedCollection}" to update:`
|
|
953
|
+
}
|
|
954
|
+
);
|
|
790
955
|
}
|
|
791
|
-
if (step === STEPS2.
|
|
792
|
-
return /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "Checking
|
|
956
|
+
if (step === STEPS2.RESOLVE) {
|
|
957
|
+
return /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "Checking..." });
|
|
793
958
|
}
|
|
794
959
|
if (step === STEPS2.CONFIRM) {
|
|
795
|
-
const item =
|
|
960
|
+
const item = queue[currentIdx];
|
|
796
961
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
797
962
|
/* @__PURE__ */ jsxs7(Warning, { children: [
|
|
798
963
|
item.name,
|
|
799
|
-
": local differs from
|
|
964
|
+
": local differs from ",
|
|
965
|
+
selectedCollection
|
|
800
966
|
] }),
|
|
801
|
-
/* @__PURE__ */ jsx7(DiffView, { patch:
|
|
967
|
+
/* @__PURE__ */ jsx7(DiffView, { patch: currentPatch }),
|
|
802
968
|
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Confirm, { message: `Update ${item.name}?`, onConfirm: handleConfirm }) })
|
|
803
969
|
] });
|
|
804
970
|
}
|
|
805
971
|
if (step === STEPS2.DONE) {
|
|
806
972
|
setTimeout(() => exit(), 100);
|
|
807
|
-
if (
|
|
808
|
-
return /* @__PURE__ */ jsx7(Success, { children: "
|
|
809
|
-
}
|
|
810
|
-
return /* @__PURE__ */ jsxs7(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
973
|
+
if (queue.length === 0 && missingNames.length === 0) {
|
|
974
|
+
return /* @__PURE__ */ jsx7(Success, { children: "Nothing to update." });
|
|
975
|
+
}
|
|
976
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
977
|
+
missingNames.length > 0 && /* @__PURE__ */ jsxs7(ErrorMsg, { children: [
|
|
978
|
+
"Skipped: ",
|
|
979
|
+
missingNames.join(", ")
|
|
980
|
+
] }),
|
|
981
|
+
/* @__PURE__ */ jsxs7(Success, { children: [
|
|
982
|
+
updatedCount,
|
|
983
|
+
" updated, ",
|
|
984
|
+
installedCount,
|
|
985
|
+
" installed, ",
|
|
986
|
+
skippedCount,
|
|
987
|
+
" skipped"
|
|
988
|
+
] })
|
|
815
989
|
] });
|
|
816
990
|
}
|
|
817
991
|
return null;
|
|
@@ -914,7 +1088,7 @@ function Help() {
|
|
|
914
1088
|
const commands = [
|
|
915
1089
|
{ name: "add [skills...]", desc: "Install skills/agents (interactive if no args)" },
|
|
916
1090
|
{ name: "list", desc: "List all available skills and agents" },
|
|
917
|
-
{ name: "update", desc: "Update installed skills
|
|
1091
|
+
{ name: "update [skills...]", desc: "Update installed skills (interactive if no args)" },
|
|
918
1092
|
{ name: "remove <skills>", desc: "Remove installed skills/agents" },
|
|
919
1093
|
{ name: "help", desc: "Show this help message" }
|
|
920
1094
|
];
|
|
@@ -923,6 +1097,7 @@ function Help() {
|
|
|
923
1097
|
"npx @hiver/skills add discuss-problem create-prd",
|
|
924
1098
|
"npx @hiver/skills list",
|
|
925
1099
|
"npx @hiver/skills update",
|
|
1100
|
+
"npx @hiver/skills update build-component",
|
|
926
1101
|
"npx @hiver/skills remove discuss-problem"
|
|
927
1102
|
];
|
|
928
1103
|
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, marginBottom: 1, children: [
|
|
@@ -959,7 +1134,7 @@ function App() {
|
|
|
959
1134
|
case "list":
|
|
960
1135
|
return /* @__PURE__ */ jsx9(List, {});
|
|
961
1136
|
case "update":
|
|
962
|
-
return /* @__PURE__ */ jsx9(Update, {});
|
|
1137
|
+
return /* @__PURE__ */ jsx9(Update, { directSkills: restArgs.length > 0 ? restArgs : null });
|
|
963
1138
|
case "remove":
|
|
964
1139
|
if (restArgs.length === 0) {
|
|
965
1140
|
return /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
|