aiblueprint-cli 1.4.74 → 1.4.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/agents-config/skills/use-style/SKILL.md +54 -0
- package/agents-config/skills/use-style/examples/anthropic.html +400 -0
- package/agents-config/skills/use-style/examples/dusk.html +368 -0
- package/agents-config/skills/use-style/examples/gumroad.html +396 -0
- package/agents-config/skills/use-style/examples/linear.html +389 -0
- package/agents-config/skills/use-style/examples/new-york-times.html +417 -0
- package/agents-config/skills/use-style/examples/raycast.html +402 -0
- package/agents-config/skills/use-style/examples/split-auth.html +366 -0
- package/agents-config/skills/use-style/examples/stripe.html +386 -0
- package/agents-config/skills/use-style/examples/vercel.html +379 -0
- package/agents-config/skills/use-style/styles/anthropic.md +266 -0
- package/agents-config/skills/use-style/styles/dusk.md +269 -0
- package/agents-config/skills/use-style/styles/grid.md +284 -0
- package/agents-config/skills/use-style/styles/gumroad.md +273 -0
- package/agents-config/skills/use-style/styles/linear.md +355 -0
- package/agents-config/skills/use-style/styles/new-york-times.md +277 -0
- package/agents-config/skills/use-style/styles/raycast.md +285 -0
- package/agents-config/skills/use-style/styles/split-auth.md +281 -0
- package/agents-config/skills/use-style/styles/stripe.md +372 -0
- package/agents-config/skills/use-style/styles/vercel-simple.md +322 -0
- package/dist/cli.js +100 -19
- package/package.json +1 -1
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Vercel Simple Style
|
|
2
|
+
|
|
3
|
+
Minimal dark-mode developer UI. High contrast, line-driven structure, no decoration.
|
|
4
|
+
|
|
5
|
+
**Reference vibe:** Vercel dashboard, blog, and data tools (take-home pay, country index).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core vibe
|
|
10
|
+
|
|
11
|
+
- **Developer-first.** Utilitarian, not marketing-soft.
|
|
12
|
+
- **Pure dark canvas.** Black background, white primary text, gray hierarchy.
|
|
13
|
+
- **Line over depth.** 1px borders define structure; no shadows or blur.
|
|
14
|
+
- **Restrained radius.** `0` on data/tool surfaces, `6-8px` on nav buttons and cards in app shells.
|
|
15
|
+
- **Monospace for data.** Labels, nav, tables, inputs, metadata.
|
|
16
|
+
- **Sans for prose.** Blog posts, long descriptions, dashboard titles (Geist / Inter stack).
|
|
17
|
+
- **Generous whitespace.** Wide section gaps, airy row padding.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Color
|
|
22
|
+
|
|
23
|
+
Portable palette. Map to project tokens when available.
|
|
24
|
+
|
|
25
|
+
| Role | Hex | CSS var (suggested) | Usage |
|
|
26
|
+
|------|-----|---------------------|-------|
|
|
27
|
+
| Canvas | `#000000` | `--vs-bg` | Page background |
|
|
28
|
+
| Surface | `#111111` | `--vs-surface` | Summary boxes, sidebar panels, inset blocks |
|
|
29
|
+
| Surface raised | `#1a1a1a` | `--vs-surface-raised` | Hover rows, secondary panels |
|
|
30
|
+
| Ink | `#ffffff` | `--vs-fg` | Headlines, primary values, active tab text |
|
|
31
|
+
| Muted ink | `#888888` | `--vs-muted-fg` | Descriptions, metadata, inactive tabs |
|
|
32
|
+
| Subtle ink | `#a1a1aa` | `--vs-subtle-fg` | Breadcrumbs, timestamps, helper text |
|
|
33
|
+
| Border | `#333333` | `--vs-border` | Boxes, dividers, input outlines |
|
|
34
|
+
| Border strong | `#444444` | `--vs-border-strong` | Active/hover borders |
|
|
35
|
+
| Data bar | `#666666` | `--vs-bar` | Progress / comparison bars |
|
|
36
|
+
| Link | `#0070f3` | `--vs-link` | Text links, copy actions |
|
|
37
|
+
| Success | `#50e3c2` | `--vs-success` | Stable / success states |
|
|
38
|
+
| Error | `#ee0000` | `--vs-error` | Failed states |
|
|
39
|
+
|
|
40
|
+
### Tailwind mapping (when no project tokens)
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
:root {
|
|
44
|
+
--vs-bg: #000;
|
|
45
|
+
--vs-surface: #111;
|
|
46
|
+
--vs-fg: #fff;
|
|
47
|
+
--vs-muted-fg: #888;
|
|
48
|
+
--vs-border: #333;
|
|
49
|
+
--vs-link: #0070f3;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Tailwind | Value |
|
|
54
|
+
|----------|-------|
|
|
55
|
+
| `bg-black` | Canvas |
|
|
56
|
+
| `bg-[#111]` | Surface |
|
|
57
|
+
| `text-white` | Primary |
|
|
58
|
+
| `text-[#888]` | Muted |
|
|
59
|
+
| `border-[#333]` | Structure |
|
|
60
|
+
|
|
61
|
+
**Rule:** Keep 90% of the UI monochromatic. Color accents only for links, status, and flag/icon glyphs.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Typography
|
|
66
|
+
|
|
67
|
+
### Font stacks
|
|
68
|
+
|
|
69
|
+
| Role | Stack |
|
|
70
|
+
|------|-------|
|
|
71
|
+
| Sans (prose / dashboard) | `Geist, Inter, ui-sans-serif, system-ui, sans-serif` |
|
|
72
|
+
| Mono (data / tools) | `Geist Mono, ui-monospace, SFMono-Regular, Menlo, monospace` |
|
|
73
|
+
|
|
74
|
+
Load Geist via `@fontsource/geist-sans` / `@fontsource/geist-mono`, or `next/font/local` in Next.js.
|
|
75
|
+
|
|
76
|
+
### Scale
|
|
77
|
+
|
|
78
|
+
| Level | Font | Pattern |
|
|
79
|
+
|-------|------|---------|
|
|
80
|
+
| Page title | Sans or Mono | `text-2xl md:text-3xl font-medium tracking-tight text-white` |
|
|
81
|
+
| Section label | Mono | `text-[10px] sm:text-xs uppercase tracking-wider text-[#888]` |
|
|
82
|
+
| Body | Sans | `text-sm md:text-base leading-relaxed text-[#888]` |
|
|
83
|
+
| Data / nav / button | Mono | `font-mono text-xs uppercase tracking-wide` |
|
|
84
|
+
| Large input value | Mono | `font-mono text-2xl md:text-3xl tabular-nums text-white` |
|
|
85
|
+
| Metadata | Sans or Mono | `text-xs text-[#888]` |
|
|
86
|
+
|
|
87
|
+
### Section labels
|
|
88
|
+
|
|
89
|
+
All-caps, small, muted gray. Examples: `TAX`, `TOOLS`, `SORT BY`, `YOUR GROSS ANNUAL SALARY`.
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
<p className="font-mono text-xs uppercase tracking-wider text-[#888]">Tools</p>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Layout tokens
|
|
98
|
+
|
|
99
|
+
| Token | Value |
|
|
100
|
+
|-------|-------|
|
|
101
|
+
| `VS_SHELL` | `mx-auto w-full max-w-5xl px-4 sm:px-6 md:px-8` |
|
|
102
|
+
| `VS_SHELL_WIDE` | `max-w-7xl` (dashboard) |
|
|
103
|
+
| `VS_SECTION` | `py-12 md:py-16 lg:py-20` |
|
|
104
|
+
| `VS_STACK` | `px-4 py-4 sm:px-5 sm:py-5 md:px-6 md:py-6` |
|
|
105
|
+
| `VS_GAP_SECTION` | `mb-12 md:mb-16` |
|
|
106
|
+
|
|
107
|
+
### Page shell (tool / index)
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
+---------------------------------------- viewport --+
|
|
111
|
+
| VS_SHELL |
|
|
112
|
+
| - Section label (mono, uppercase, muted) |
|
|
113
|
+
| - Page title |
|
|
114
|
+
| - Description (muted sans) |
|
|
115
|
+
| - Search / controls |
|
|
116
|
+
| - Bordered grid or list |
|
|
117
|
+
+----------------------------------------------------+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<div className="min-h-screen bg-black text-white">
|
|
122
|
+
<main className={VS_SHELL}>
|
|
123
|
+
<section className={VS_SECTION}>...</section>
|
|
124
|
+
</main>
|
|
125
|
+
</div>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### App shell (dashboard)
|
|
129
|
+
|
|
130
|
+
Sidebar + main. Sidebar is narrow, icon + label, muted inactive links.
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
<div className="flex min-h-screen bg-black">
|
|
134
|
+
<aside className="w-56 border-r border-[#333]">...</aside>
|
|
135
|
+
<main className="flex-1 p-6 md:p-8">...</main>
|
|
136
|
+
</div>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Borders & radius
|
|
142
|
+
|
|
143
|
+
| Context | Radius | Border |
|
|
144
|
+
|---------|--------|--------|
|
|
145
|
+
| Data tools, country lists, tables | `rounded-none` | `border border-[#333]` |
|
|
146
|
+
| Cards, project tiles, blog feature | `rounded-lg` (8px) | `border border-[#333]` |
|
|
147
|
+
| Primary button | `rounded-md` (6px) | filled or outline |
|
|
148
|
+
| Inputs | `rounded-none` or `rounded-md` | `border border-[#333] bg-transparent` |
|
|
149
|
+
|
|
150
|
+
Dividers: `border-t border-[#333]`, full width inside the container.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Component patterns
|
|
155
|
+
|
|
156
|
+
### Search input
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
<input
|
|
160
|
+
className="w-full border border-[#333] bg-transparent px-4 py-3 font-mono text-sm text-white placeholder:text-[#888] focus:border-[#444] focus:outline-none"
|
|
161
|
+
placeholder="Search countries..."
|
|
162
|
+
/>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Link row (index grid)
|
|
166
|
+
|
|
167
|
+
Bordered box, icon left, title white, arrow right.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
<a className="flex items-center justify-between border border-[#333] px-4 py-3 transition-colors hover:border-[#444] hover:bg-[#111]">
|
|
171
|
+
<span className="flex items-center gap-3 font-mono text-sm text-white">...</span>
|
|
172
|
+
<span className="font-mono text-[#888]">{"->"}</span>
|
|
173
|
+
</a>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Tab / sort toggle
|
|
177
|
+
|
|
178
|
+
Inactive: gray border + gray text. Active: white border + white text.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<button className={cn(
|
|
182
|
+
"border px-3 py-1.5 font-mono text-xs uppercase tracking-wide",
|
|
183
|
+
active ? "border-white text-white" : "border-[#333] text-[#888]"
|
|
184
|
+
)}>...</button>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Data table row
|
|
188
|
+
|
|
189
|
+
Row inside a bordered container. Primary number is white + mono tabular. Secondary detail is muted and small.
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
<div className="flex items-center gap-4 border-b border-[#333] px-4 py-4 last:border-b-0">
|
|
193
|
+
<span className="w-28 font-mono text-sm">Germany</span>
|
|
194
|
+
<div className="h-2 flex-1 bg-[#333]">
|
|
195
|
+
<div className="h-full bg-[#666]" style={{ width: `${pct}%` }} />
|
|
196
|
+
</div>
|
|
197
|
+
<span className="font-mono tabular-nums text-white">52,340</span>
|
|
198
|
+
</div>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Progress bars: track `#333`, fill `#666`. Flat, no gradient.
|
|
202
|
+
|
|
203
|
+
### Summary / highlight box
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<div className="border border-[#333] bg-[#111] px-5 py-4 font-mono text-sm">
|
|
207
|
+
<span className="text-[#888]">Best value: </span>
|
|
208
|
+
<span className="text-white">Bulgaria</span>
|
|
209
|
+
</div>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Card (dashboard / blog)
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<div className="rounded-lg border border-[#333] bg-black p-4 transition-colors hover:border-[#444]">
|
|
216
|
+
<div className="mb-3 flex items-start justify-between">...</div>
|
|
217
|
+
<h3 className="text-sm font-medium text-white">Project name</h3>
|
|
218
|
+
<p className="mt-1 text-xs text-[#888]">project.vercel.app</p>
|
|
219
|
+
</div>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Buttons
|
|
223
|
+
|
|
224
|
+
| Variant | Classes |
|
|
225
|
+
|---------|---------|
|
|
226
|
+
| Primary | `rounded-md bg-white px-4 py-2 text-sm font-medium text-black hover:bg-white/90` |
|
|
227
|
+
| Secondary | `rounded-md border border-[#333] bg-black px-4 py-2 text-sm text-white hover:border-[#444]` |
|
|
228
|
+
| Ghost link | `text-[#0070f3] hover:underline` |
|
|
229
|
+
|
|
230
|
+
### Two-column grid
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
|
234
|
+
{items.map(...)}
|
|
235
|
+
</div>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Each cell is its own bordered box, not a `gap-px` mosaic unless every cell sets explicit `bg-black`.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Grid patterns
|
|
243
|
+
|
|
244
|
+
### Bordered list stack
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
<div className="border border-[#333] divide-y divide-[#333]">
|
|
248
|
+
{rows.map(...)}
|
|
249
|
+
</div>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Full-width tool card
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
<a className="block border border-[#333] px-5 py-5 transition-colors hover:bg-[#111]">
|
|
256
|
+
<p className="font-mono text-base text-white">Europe: Take-Home Pay Comparison</p>
|
|
257
|
+
<p className="mt-1 text-sm text-[#888]">Calculate, visualize, and compare...</p>
|
|
258
|
+
</a>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Charts (data viz)
|
|
264
|
+
|
|
265
|
+
Match the line-driven, monochrome tool aesthetic:
|
|
266
|
+
|
|
267
|
+
- Series in grayscale: `#fff`, `#888`, `#666`, `#333`. Add **one** accent only when a series must stand out - `#0070f3` (link blue) or `#50e3c2` (success).
|
|
268
|
+
- **Sharp bars** (`borderRadius: 0`) - same square geometry as the data tools. Flat fills, no gradients.
|
|
269
|
+
- Gridlines `#333`; axis text **mono** (`Geist Mono`), muted `#888`.
|
|
270
|
+
- Tooltip: `#111` background, white text, square or 6px corners.
|
|
271
|
+
- Bars/progress reuse the data-bar token: track `#333`, fill `#666` (or `#fff` for the active series).
|
|
272
|
+
- Doughnut: segments separated by a `#000` stroke; legend in mono uppercase.
|
|
273
|
+
|
|
274
|
+
```js
|
|
275
|
+
const FG="#fff", S2="#888", S3="#666", S4="#333", ACCENT="#0070f3", GRID="#333";
|
|
276
|
+
Chart.defaults.font.family = "Geist Mono, ui-monospace, monospace";
|
|
277
|
+
Chart.defaults.color = "#888";
|
|
278
|
+
// bars: backgroundColor:[S3, FG], borderRadius:0
|
|
279
|
+
// grid: { color: GRID }, border: { color: GRID }
|
|
280
|
+
// tooltip: { backgroundColor:"#111", cornerRadius:0 }
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Motion & effects
|
|
286
|
+
|
|
287
|
+
- No drop shadows, glass blur, gradient backgrounds, or glow halos.
|
|
288
|
+
- Hover: border lighten (`#333` to `#444`), subtle bg (`#111`), or text color shift.
|
|
289
|
+
- `transition-colors duration-150` on interactive elements.
|
|
290
|
+
- No scale/lift animations on cards.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Mode selection
|
|
295
|
+
|
|
296
|
+
| Surface type | Font | Radius |
|
|
297
|
+
|--------------|------|--------|
|
|
298
|
+
| Data tools, tax calculators, index pages | Mono primary | Sharp (`0`) |
|
|
299
|
+
| Dashboard, blog, marketing docs | Sans primary, mono for metadata | Soft (`6-8px`) |
|
|
300
|
+
|
|
301
|
+
When unsure, default to mono + sharp for new tool UIs, and sans + `rounded-lg` for app shells and content pages.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Anti-patterns
|
|
306
|
+
|
|
307
|
+
| Avoid | Why |
|
|
308
|
+
|-------|-----|
|
|
309
|
+
| `rounded-xl`, `rounded-2xl`, `rounded-full` on data/tool UI | Breaks the utilitarian look |
|
|
310
|
+
| `shadow-lg`, `ring-*`, `backdrop-blur-*` | Depth replaces line hierarchy |
|
|
311
|
+
| Gradient backgrounds | Keep flat black / `#111` surfaces |
|
|
312
|
+
| Bright saturated fills on large areas | Reserve color for links and status |
|
|
313
|
+
| `gap-px` + `bg-border` without per-cell bg | Unintended gray gutters |
|
|
314
|
+
| Pill-shaped tabs on tool pages | Use rectangular bordered toggles |
|
|
315
|
+
| Light mode by default | The style is dark-first |
|
|
316
|
+
| Decorative hero imagery on a tool index | Text + bordered grid only |
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Project overrides
|
|
321
|
+
|
|
322
|
+
If the repo defines `.agents/styles/vercel-simple.md` or `.agents/styles/vercel-simple-theme.md`, prefer those tokens and components over this portable spec.
|
package/dist/cli.js
CHANGED
|
@@ -35971,8 +35971,10 @@ function getContainerCandidates(options, includeCodex = true) {
|
|
|
35971
35971
|
}
|
|
35972
35972
|
]);
|
|
35973
35973
|
}
|
|
35974
|
-
function getInstructionFileCandidates(options,
|
|
35974
|
+
function getInstructionFileCandidates(options, scope) {
|
|
35975
35975
|
const folders = resolveFolders(options);
|
|
35976
|
+
const cursorDir = path17.join(folders.rootDir, ".cursor");
|
|
35977
|
+
const linkToolInstructionsWhenMissing = scope === "global";
|
|
35976
35978
|
return uniqueByPath([
|
|
35977
35979
|
{
|
|
35978
35980
|
label: "agents-instructions",
|
|
@@ -35984,11 +35986,17 @@ function getInstructionFileCandidates(options, includeCodex = true) {
|
|
|
35984
35986
|
path: path17.join(folders.claudeDir, "CLAUDE.md"),
|
|
35985
35987
|
linkWhenMissing: true
|
|
35986
35988
|
},
|
|
35987
|
-
|
|
35989
|
+
{
|
|
35988
35990
|
label: "codex-instructions",
|
|
35989
35991
|
path: path17.join(folders.codexDir, "AGENTS.md"),
|
|
35990
|
-
linkWhenMissing:
|
|
35991
|
-
|
|
35992
|
+
linkWhenMissing: linkToolInstructionsWhenMissing,
|
|
35993
|
+
linkWhenParentExists: true
|
|
35994
|
+
},
|
|
35995
|
+
{
|
|
35996
|
+
label: "cursor-instructions",
|
|
35997
|
+
path: path17.join(cursorDir, "AGENTS.md"),
|
|
35998
|
+
linkWhenParentExists: true
|
|
35999
|
+
}
|
|
35992
36000
|
]);
|
|
35993
36001
|
}
|
|
35994
36002
|
function getRepositoryContainerCandidates(options) {
|
|
@@ -36656,6 +36664,8 @@ async function importInstructionFiles(candidates, destinationPath, result, dryRu
|
|
|
36656
36664
|
async function shouldLinkMissingInstruction(candidate) {
|
|
36657
36665
|
if (candidate.linkWhenMissing)
|
|
36658
36666
|
return true;
|
|
36667
|
+
if (candidate.linkWhenParentExists)
|
|
36668
|
+
return import_fs_extra13.default.pathExists(path17.dirname(candidate.path));
|
|
36659
36669
|
return false;
|
|
36660
36670
|
}
|
|
36661
36671
|
async function linkInstructionFile(candidate, destinationPath, result, dryRun = false) {
|
|
@@ -36849,12 +36859,12 @@ async function ensureClaudeInstructionSymlink(result, agentsPath, claudePath, dr
|
|
|
36849
36859
|
to: agentsPath
|
|
36850
36860
|
});
|
|
36851
36861
|
}
|
|
36852
|
-
async function writeRepositoryInstructionIndex(result, folders, dryRun = false) {
|
|
36862
|
+
async function writeRepositoryInstructionIndex(result, folders, dryRun = false, includeRules = true) {
|
|
36853
36863
|
const rulesDir = path17.join(folders.agentsDir, "rules");
|
|
36854
36864
|
const agentsPath = path17.join(folders.rootDir, "AGENTS.md");
|
|
36855
36865
|
const claudePath = path17.join(folders.rootDir, "CLAUDE.md");
|
|
36856
36866
|
const rulesDirExists = await pathExistsOrSymlink(rulesDir);
|
|
36857
|
-
const rules = dryRun || rulesDirExists ? dryRun ? await collectPlannedRuleIndexEntries(result, folders.rootDir) : await collectRuleIndexEntries(rulesDir, folders.rootDir) : [];
|
|
36867
|
+
const rules = includeRules && (dryRun || rulesDirExists) ? dryRun ? await collectPlannedRuleIndexEntries(result, folders.rootDir) : await collectRuleIndexEntries(rulesDir, folders.rootDir) : [];
|
|
36858
36868
|
const agentsExists = await pathExistsOrSymlink(agentsPath);
|
|
36859
36869
|
const claudeExists = await pathExistsOrSymlink(claudePath);
|
|
36860
36870
|
if (rules.length === 0 && !agentsExists && !claudeExists) {
|
|
@@ -36967,7 +36977,9 @@ async function unifyAgentsConfiguration(options = {}) {
|
|
|
36967
36977
|
const dryRun = Boolean(options.dryRun);
|
|
36968
36978
|
const folders = resolveFolders(options);
|
|
36969
36979
|
const includeCodex = scope !== "repository";
|
|
36970
|
-
const
|
|
36980
|
+
const defaultCategories = scope === "repository" ? ["instructions", "skills", "agents", "rules"] : ["instructions", "skills", "agents"];
|
|
36981
|
+
const selectedCategories = new Set((options.categories ?? defaultCategories).filter((category) => defaultCategories.includes(category)));
|
|
36982
|
+
const instructionCandidates = getInstructionFileCandidates(options, scope);
|
|
36971
36983
|
const candidates = scope === "repository" ? getRepositoryContainerCandidates(options) : getContainerCandidates(options);
|
|
36972
36984
|
const result = {
|
|
36973
36985
|
rootDir: folders.rootDir,
|
|
@@ -36988,13 +37000,17 @@ async function unifyAgentsConfiguration(options = {}) {
|
|
|
36988
37000
|
instructions: path17.join(folders.agentsDir, "AGENTS.md"),
|
|
36989
37001
|
rules: path17.join(folders.agentsDir, "rules")
|
|
36990
37002
|
};
|
|
36991
|
-
|
|
37003
|
+
if (selectedCategories.has("instructions")) {
|
|
37004
|
+
await importInstructionFiles(instructionCandidates, destinationByCategory.instructions, result, dryRun);
|
|
37005
|
+
}
|
|
36992
37006
|
const categories = scope === "repository" ? ["skills", "agents", "rules"] : ["skills", "agents"];
|
|
36993
|
-
if (scope === "repository" && await pathExistsOrSymlink(destinationByCategory.rules)) {
|
|
37007
|
+
if (scope === "repository" && selectedCategories.has("rules") && await pathExistsOrSymlink(destinationByCategory.rules)) {
|
|
36994
37008
|
await migrateExistingRuleExtensions(destinationByCategory.rules, result, dryRun);
|
|
36995
37009
|
}
|
|
36996
37010
|
const activeCategories = new Set;
|
|
36997
37011
|
for (const category of categories) {
|
|
37012
|
+
if (!selectedCategories.has(category))
|
|
37013
|
+
continue;
|
|
36998
37014
|
const isActive = await importCategoryEntries(category, candidates, destinationByCategory[category], result, dryRun);
|
|
36999
37015
|
if (isActive) {
|
|
37000
37016
|
activeCategories.add(category);
|
|
@@ -37005,14 +37021,16 @@ async function unifyAgentsConfiguration(options = {}) {
|
|
|
37005
37021
|
continue;
|
|
37006
37022
|
await linkContainer(candidate, destinationByCategory[candidate.category], result, dryRun);
|
|
37007
37023
|
}
|
|
37008
|
-
|
|
37009
|
-
|
|
37024
|
+
if (selectedCategories.has("instructions")) {
|
|
37025
|
+
for (const candidate of instructionCandidates) {
|
|
37026
|
+
await linkInstructionFile(candidate, destinationByCategory.instructions, result, dryRun);
|
|
37027
|
+
}
|
|
37010
37028
|
}
|
|
37011
|
-
if (scope === "repository") {
|
|
37012
|
-
if (!dryRun && await pathExistsOrSymlink(destinationByCategory.rules)) {
|
|
37029
|
+
if (scope === "repository" && (selectedCategories.has("instructions") || selectedCategories.has("rules"))) {
|
|
37030
|
+
if (!dryRun && selectedCategories.has("rules") && await pathExistsOrSymlink(destinationByCategory.rules)) {
|
|
37013
37031
|
await migrateExistingRuleExtensions(destinationByCategory.rules, result, dryRun);
|
|
37014
37032
|
}
|
|
37015
|
-
await writeRepositoryInstructionIndex(result, folders, dryRun);
|
|
37033
|
+
await writeRepositoryInstructionIndex(result, folders, dryRun, selectedCategories.has("rules"));
|
|
37016
37034
|
}
|
|
37017
37035
|
return result;
|
|
37018
37036
|
}
|
|
@@ -37021,6 +37039,46 @@ async function previewAgentsConfiguration(options = {}) {
|
|
|
37021
37039
|
}
|
|
37022
37040
|
|
|
37023
37041
|
// src/commands/agents-unify.ts
|
|
37042
|
+
var CATEGORY_LABELS = {
|
|
37043
|
+
instructions: "AGENTS.md",
|
|
37044
|
+
skills: "Skills",
|
|
37045
|
+
agents: "Agents",
|
|
37046
|
+
rules: "Rules and memories"
|
|
37047
|
+
};
|
|
37048
|
+
function defaultCategoriesForScope(scope) {
|
|
37049
|
+
return scope === "repository" ? ["instructions", "skills", "agents", "rules"] : ["instructions", "skills", "agents"];
|
|
37050
|
+
}
|
|
37051
|
+
function selectableCategoriesForScope(scope) {
|
|
37052
|
+
return defaultCategoriesForScope(scope);
|
|
37053
|
+
}
|
|
37054
|
+
async function resolveSelectedCategories(params) {
|
|
37055
|
+
const scope = params.scope ?? "global";
|
|
37056
|
+
const selectableCategories = selectableCategoriesForScope(scope);
|
|
37057
|
+
const requestedCategories = params.categories?.filter((category) => selectableCategories.includes(category));
|
|
37058
|
+
const initialValues = requestedCategories ?? selectableCategories;
|
|
37059
|
+
if (!params.interactive) {
|
|
37060
|
+
if (params.categories && initialValues.length === 0) {
|
|
37061
|
+
throw new Error(`Selected categories do not apply to ${scope} scope`);
|
|
37062
|
+
}
|
|
37063
|
+
return requestedCategories;
|
|
37064
|
+
}
|
|
37065
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
37066
|
+
throw new Error("Interactive category selection requires a TTY");
|
|
37067
|
+
}
|
|
37068
|
+
const selected = await fe({
|
|
37069
|
+
message: "What do you want to unify?",
|
|
37070
|
+
options: selectableCategories.map((category) => ({
|
|
37071
|
+
value: category,
|
|
37072
|
+
label: CATEGORY_LABELS[category]
|
|
37073
|
+
})),
|
|
37074
|
+
initialValues,
|
|
37075
|
+
required: true
|
|
37076
|
+
});
|
|
37077
|
+
if (pD(selected)) {
|
|
37078
|
+
return null;
|
|
37079
|
+
}
|
|
37080
|
+
return selected;
|
|
37081
|
+
}
|
|
37024
37082
|
function countByCategory(result, key, category) {
|
|
37025
37083
|
return result[key].filter((entry) => entry.category === category).length;
|
|
37026
37084
|
}
|
|
@@ -37086,15 +37144,24 @@ AIBlueprint agents unify ${source_default.gray(`v${getVersion()}`)}
|
|
|
37086
37144
|
`));
|
|
37087
37145
|
console.log(source_default.gray(`Scope: ${params.scope ?? "global"}`));
|
|
37088
37146
|
console.log(source_default.gray(params.scope === "repository" ? "Centralizing project agent configuration into .agents" : "Centralizing reusable agent configuration into .agents, then rendering Codex agents"));
|
|
37089
|
-
const
|
|
37147
|
+
const selectedCategories = await resolveSelectedCategories(params);
|
|
37148
|
+
if (selectedCategories === null) {
|
|
37149
|
+
console.log(source_default.gray(`
|
|
37150
|
+
Unify cancelled`));
|
|
37151
|
+
return;
|
|
37152
|
+
}
|
|
37153
|
+
const commandParams = { ...params, categories: selectedCategories };
|
|
37154
|
+
const effectiveCategories = selectedCategories ?? defaultCategoriesForScope(params.scope ?? "global");
|
|
37155
|
+
console.log(source_default.gray(`Categories: ${effectiveCategories.map((category) => CATEGORY_LABELS[category]).join(", ")}`));
|
|
37156
|
+
const preview = await previewAgentsConfiguration(commandParams);
|
|
37090
37157
|
printAgentsUnifyPreview(preview);
|
|
37091
37158
|
if (!await confirmUnify()) {
|
|
37092
37159
|
console.log(source_default.gray(`
|
|
37093
37160
|
Unify cancelled`));
|
|
37094
37161
|
return;
|
|
37095
37162
|
}
|
|
37096
|
-
const result = await unifyAgentsConfiguration(
|
|
37097
|
-
const codexResult = params.scope === "repository" ? null : await renderCodexAgentsFromMarkdown(
|
|
37163
|
+
const result = await unifyAgentsConfiguration(commandParams);
|
|
37164
|
+
const codexResult = params.scope === "repository" || !effectiveCategories.includes("agents") ? null : await renderCodexAgentsFromMarkdown(commandParams);
|
|
37098
37165
|
console.log(source_default.green(`
|
|
37099
37166
|
Unify complete`));
|
|
37100
37167
|
console.log(source_default.gray(` Shared folder: ${result.agentsDir}`));
|
|
@@ -39315,6 +39382,18 @@ var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
|
39315
39382
|
var packageJson = JSON.parse(readFileSync3(join2(__dirname3, "../package.json"), "utf8"));
|
|
39316
39383
|
var program2 = new Command;
|
|
39317
39384
|
program2.name("aiblueprint").description("AIBlueprint CLI for setting up AI coding configurations").version(packageJson.version);
|
|
39385
|
+
function readUnifyCategories(options) {
|
|
39386
|
+
const categories = [];
|
|
39387
|
+
if (options.agentsMd)
|
|
39388
|
+
categories.push("instructions");
|
|
39389
|
+
if (options.skills)
|
|
39390
|
+
categories.push("skills");
|
|
39391
|
+
if (options.agents)
|
|
39392
|
+
categories.push("agents");
|
|
39393
|
+
if (options.rules)
|
|
39394
|
+
categories.push("rules");
|
|
39395
|
+
return categories.length > 0 ? categories : undefined;
|
|
39396
|
+
}
|
|
39318
39397
|
function registerAgentsCommands(cmd) {
|
|
39319
39398
|
cmd.option("-f, --folder <path>", "Root folder that contains .claude/, .codex/, .agents/ (default: $HOME)").option("--claudeCodeFolder <path>", "Override Claude Code folder (default: {folder}/.claude)").option("--codexFolder <path>", "Override Codex folder (default: {folder}/.codex)").option("--agentsFolder <path>", "Override shared agents folder (default: {folder}/.agents)").option("-s, --skip", "Skip interactive prompts and install all features");
|
|
39320
39399
|
cmd.command("setup").description("Setup AI coding configuration with AIBlueprint defaults").action((options, command) => {
|
|
@@ -39342,7 +39421,7 @@ function registerAgentsCommands(cmd) {
|
|
|
39342
39421
|
codexFolder: parentOptions.codexFolder
|
|
39343
39422
|
});
|
|
39344
39423
|
});
|
|
39345
|
-
cmd.command("unify [scope]").description("Unify agent configuration into .agents (scope: global or projects/repository; default: global)").action((scope, options, command) => {
|
|
39424
|
+
cmd.command("unify [scope]").description("Unify agent configuration into .agents (scope: global or projects/repository; default: global)").option("-i, --interactive", "Choose which categories to unify").option("--agents-md", "Unify instruction files into .agents/AGENTS.md").option("--skills", "Unify skills").option("--agents", "Unify Markdown agents").option("--rules", "Unify repository rules and memories").action((scope, options, command) => {
|
|
39346
39425
|
const parentOptions = command.parent.opts();
|
|
39347
39426
|
const requestedScope = scope ?? "global";
|
|
39348
39427
|
const selectedScope = requestedScope === "projects" || requestedScope === "project" ? "repository" : requestedScope;
|
|
@@ -39357,7 +39436,9 @@ function registerAgentsCommands(cmd) {
|
|
|
39357
39436
|
claudeCodeFolder: parentOptions.claudeCodeFolder,
|
|
39358
39437
|
codexFolder: parentOptions.codexFolder,
|
|
39359
39438
|
agentsFolder: parentOptions.agentsFolder,
|
|
39360
|
-
scope: selectedScope
|
|
39439
|
+
scope: selectedScope,
|
|
39440
|
+
categories: readUnifyCategories(options),
|
|
39441
|
+
interactive: options.interactive
|
|
39361
39442
|
});
|
|
39362
39443
|
});
|
|
39363
39444
|
cmd.command("codex-agents").description("Render shared Markdown agents from .agents/agents into Codex TOML custom agents").option("--overwrite", "Overwrite existing non-generated Codex agent files").action((options, command) => {
|