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.
@@ -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, includeCodex = true) {
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
- ...includeCodex ? [{
35989
+ {
35988
35990
  label: "codex-instructions",
35989
35991
  path: path17.join(folders.codexDir, "AGENTS.md"),
35990
- linkWhenMissing: true
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 instructionCandidates = getInstructionFileCandidates(options, includeCodex);
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
- await importInstructionFiles(instructionCandidates, destinationByCategory.instructions, result, dryRun);
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
- for (const candidate of instructionCandidates) {
37009
- await linkInstructionFile(candidate, destinationByCategory.instructions, result, dryRun);
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 preview = await previewAgentsConfiguration(params);
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(params);
37097
- const codexResult = params.scope === "repository" ? null : await renderCodexAgentsFromMarkdown(params);
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) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiblueprint-cli",
3
- "version": "1.4.74",
3
+ "version": "1.4.76",
4
4
  "description": "AIBlueprint CLI for setting up AI coding configurations",
5
5
  "author": "AIBlueprint",
6
6
  "license": "MIT",