@rokkit/cli 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46,13 +46,13 @@ export function fetchAgents(names: string[], { cwd, force, baseUrl, fetchImpl }?
46
46
  export function runAgentsList({ agentsDir, cwd }?: {
47
47
  agentsDir?: string;
48
48
  cwd?: string;
49
- }): Promise<void>;
49
+ }): void;
50
50
  /**
51
51
  * Resolve which agents to install, then copy (or fetch with --remote) and report.
52
52
  * @param {string[]} names
53
53
  * @param {{ all?: boolean, force?: boolean, remote?: boolean, agentsDir?: string, cwd?: string, fetchImpl?: typeof fetch }} [opts]
54
54
  */
55
- export function runAgentsAdd(names: string[], { all, force, remote, agentsDir, cwd, fetchImpl }?: {
55
+ export function runAgentsAdd(names: string[], opts?: {
56
56
  all?: boolean;
57
57
  force?: boolean;
58
58
  remote?: boolean;
@@ -37,22 +37,407 @@ export function generateChartConfig({ chartColors, chartShades }: {
37
37
  chartColors: string;
38
38
  chartShades: string;
39
39
  }): Record<string, unknown>;
40
- /**
41
- * Build the Zen-Sumi OKLCH starter (ink-on-paper, dual-palette dark mode).
42
- * @param {{ themes?: string[], defaultTheme?: string, switcher?: string,
43
- * includeChart?: boolean, chartColors?: string, chartShades?: string,
44
- * storageKey?: string }} [opts]
45
- * @returns {Record<string, unknown>}
46
- */
47
- export function generateZenSumiConfig(opts?: {
48
- themes?: string[];
49
- defaultTheme?: string;
50
- switcher?: string;
51
- includeChart?: boolean;
52
- chartColors?: string;
53
- chartShades?: string;
54
- storageKey?: string;
55
- }): Record<string, unknown>;
40
+ export function generateZenSumiConfig(opts?: {}): {
41
+ chart: Record<string, unknown>;
42
+ storageKey: any;
43
+ themes: any;
44
+ defaultTheme: any;
45
+ switcher: any;
46
+ palettes: {
47
+ kami: {
48
+ 50: string;
49
+ 100: string;
50
+ 200: string;
51
+ 300: string;
52
+ 400: string;
53
+ 500: string;
54
+ 600: string;
55
+ 700: string;
56
+ 800: string;
57
+ 900: string;
58
+ 950: string;
59
+ };
60
+ sumi: {
61
+ 50: string;
62
+ 100: string;
63
+ 200: string;
64
+ 300: string;
65
+ 400: string;
66
+ 500: string;
67
+ 600: string;
68
+ 700: string;
69
+ 800: string;
70
+ 900: string;
71
+ 950: string;
72
+ };
73
+ shu: {
74
+ 50: string;
75
+ 100: string;
76
+ 200: string;
77
+ 300: string;
78
+ 400: string;
79
+ 500: string;
80
+ 600: string;
81
+ 700: string;
82
+ 800: string;
83
+ 900: string;
84
+ 950: string;
85
+ };
86
+ hisui: {
87
+ 50: string;
88
+ 100: string;
89
+ 200: string;
90
+ 300: string;
91
+ 400: string;
92
+ 500: string;
93
+ 600: string;
94
+ 700: string;
95
+ 800: string;
96
+ 900: string;
97
+ 950: string;
98
+ };
99
+ kohaku: {
100
+ 50: string;
101
+ 100: string;
102
+ 200: string;
103
+ 300: string;
104
+ 400: string;
105
+ 500: string;
106
+ 600: string;
107
+ 700: string;
108
+ 800: string;
109
+ 900: string;
110
+ 950: string;
111
+ };
112
+ };
113
+ colorSpace: string;
114
+ tokens: string;
115
+ skin: {
116
+ surface: {
117
+ light: string;
118
+ dark: string;
119
+ };
120
+ ink: {
121
+ light: string;
122
+ dark: string;
123
+ };
124
+ primary: string;
125
+ accent: string;
126
+ success: string;
127
+ warning: string;
128
+ danger: string;
129
+ error: string;
130
+ info: string;
131
+ };
132
+ shape: {
133
+ radius: string;
134
+ };
135
+ typography: {
136
+ display: string;
137
+ sans: string;
138
+ mono: string;
139
+ };
140
+ } | {
141
+ chart?: undefined;
142
+ storageKey: any;
143
+ themes: any;
144
+ defaultTheme: any;
145
+ switcher: any;
146
+ palettes: {
147
+ kami: {
148
+ 50: string;
149
+ 100: string;
150
+ 200: string;
151
+ 300: string;
152
+ 400: string;
153
+ 500: string;
154
+ 600: string;
155
+ 700: string;
156
+ 800: string;
157
+ 900: string;
158
+ 950: string;
159
+ };
160
+ sumi: {
161
+ 50: string;
162
+ 100: string;
163
+ 200: string;
164
+ 300: string;
165
+ 400: string;
166
+ 500: string;
167
+ 600: string;
168
+ 700: string;
169
+ 800: string;
170
+ 900: string;
171
+ 950: string;
172
+ };
173
+ shu: {
174
+ 50: string;
175
+ 100: string;
176
+ 200: string;
177
+ 300: string;
178
+ 400: string;
179
+ 500: string;
180
+ 600: string;
181
+ 700: string;
182
+ 800: string;
183
+ 900: string;
184
+ 950: string;
185
+ };
186
+ hisui: {
187
+ 50: string;
188
+ 100: string;
189
+ 200: string;
190
+ 300: string;
191
+ 400: string;
192
+ 500: string;
193
+ 600: string;
194
+ 700: string;
195
+ 800: string;
196
+ 900: string;
197
+ 950: string;
198
+ };
199
+ kohaku: {
200
+ 50: string;
201
+ 100: string;
202
+ 200: string;
203
+ 300: string;
204
+ 400: string;
205
+ 500: string;
206
+ 600: string;
207
+ 700: string;
208
+ 800: string;
209
+ 900: string;
210
+ 950: string;
211
+ };
212
+ };
213
+ colorSpace: string;
214
+ tokens: string;
215
+ skin: {
216
+ surface: {
217
+ light: string;
218
+ dark: string;
219
+ };
220
+ ink: {
221
+ light: string;
222
+ dark: string;
223
+ };
224
+ primary: string;
225
+ accent: string;
226
+ success: string;
227
+ warning: string;
228
+ danger: string;
229
+ error: string;
230
+ info: string;
231
+ };
232
+ shape: {
233
+ radius: string;
234
+ };
235
+ typography: {
236
+ display: string;
237
+ sans: string;
238
+ mono: string;
239
+ };
240
+ } | {
241
+ chart: Record<string, unknown>;
242
+ storageKey?: undefined;
243
+ themes: any;
244
+ defaultTheme: any;
245
+ switcher: any;
246
+ palettes: {
247
+ kami: {
248
+ 50: string;
249
+ 100: string;
250
+ 200: string;
251
+ 300: string;
252
+ 400: string;
253
+ 500: string;
254
+ 600: string;
255
+ 700: string;
256
+ 800: string;
257
+ 900: string;
258
+ 950: string;
259
+ };
260
+ sumi: {
261
+ 50: string;
262
+ 100: string;
263
+ 200: string;
264
+ 300: string;
265
+ 400: string;
266
+ 500: string;
267
+ 600: string;
268
+ 700: string;
269
+ 800: string;
270
+ 900: string;
271
+ 950: string;
272
+ };
273
+ shu: {
274
+ 50: string;
275
+ 100: string;
276
+ 200: string;
277
+ 300: string;
278
+ 400: string;
279
+ 500: string;
280
+ 600: string;
281
+ 700: string;
282
+ 800: string;
283
+ 900: string;
284
+ 950: string;
285
+ };
286
+ hisui: {
287
+ 50: string;
288
+ 100: string;
289
+ 200: string;
290
+ 300: string;
291
+ 400: string;
292
+ 500: string;
293
+ 600: string;
294
+ 700: string;
295
+ 800: string;
296
+ 900: string;
297
+ 950: string;
298
+ };
299
+ kohaku: {
300
+ 50: string;
301
+ 100: string;
302
+ 200: string;
303
+ 300: string;
304
+ 400: string;
305
+ 500: string;
306
+ 600: string;
307
+ 700: string;
308
+ 800: string;
309
+ 900: string;
310
+ 950: string;
311
+ };
312
+ };
313
+ colorSpace: string;
314
+ tokens: string;
315
+ skin: {
316
+ surface: {
317
+ light: string;
318
+ dark: string;
319
+ };
320
+ ink: {
321
+ light: string;
322
+ dark: string;
323
+ };
324
+ primary: string;
325
+ accent: string;
326
+ success: string;
327
+ warning: string;
328
+ danger: string;
329
+ error: string;
330
+ info: string;
331
+ };
332
+ shape: {
333
+ radius: string;
334
+ };
335
+ typography: {
336
+ display: string;
337
+ sans: string;
338
+ mono: string;
339
+ };
340
+ } | {
341
+ chart?: undefined;
342
+ storageKey?: undefined;
343
+ themes: any;
344
+ defaultTheme: any;
345
+ switcher: any;
346
+ palettes: {
347
+ kami: {
348
+ 50: string;
349
+ 100: string;
350
+ 200: string;
351
+ 300: string;
352
+ 400: string;
353
+ 500: string;
354
+ 600: string;
355
+ 700: string;
356
+ 800: string;
357
+ 900: string;
358
+ 950: string;
359
+ };
360
+ sumi: {
361
+ 50: string;
362
+ 100: string;
363
+ 200: string;
364
+ 300: string;
365
+ 400: string;
366
+ 500: string;
367
+ 600: string;
368
+ 700: string;
369
+ 800: string;
370
+ 900: string;
371
+ 950: string;
372
+ };
373
+ shu: {
374
+ 50: string;
375
+ 100: string;
376
+ 200: string;
377
+ 300: string;
378
+ 400: string;
379
+ 500: string;
380
+ 600: string;
381
+ 700: string;
382
+ 800: string;
383
+ 900: string;
384
+ 950: string;
385
+ };
386
+ hisui: {
387
+ 50: string;
388
+ 100: string;
389
+ 200: string;
390
+ 300: string;
391
+ 400: string;
392
+ 500: string;
393
+ 600: string;
394
+ 700: string;
395
+ 800: string;
396
+ 900: string;
397
+ 950: string;
398
+ };
399
+ kohaku: {
400
+ 50: string;
401
+ 100: string;
402
+ 200: string;
403
+ 300: string;
404
+ 400: string;
405
+ 500: string;
406
+ 600: string;
407
+ 700: string;
408
+ 800: string;
409
+ 900: string;
410
+ 950: string;
411
+ };
412
+ };
413
+ colorSpace: string;
414
+ tokens: string;
415
+ skin: {
416
+ surface: {
417
+ light: string;
418
+ dark: string;
419
+ };
420
+ ink: {
421
+ light: string;
422
+ dark: string;
423
+ };
424
+ primary: string;
425
+ accent: string;
426
+ success: string;
427
+ warning: string;
428
+ danger: string;
429
+ error: string;
430
+ info: string;
431
+ };
432
+ shape: {
433
+ radius: string;
434
+ };
435
+ typography: {
436
+ display: string;
437
+ sans: string;
438
+ mono: string;
439
+ };
440
+ };
56
441
  /**
57
442
  * Build a Rokkit config object from the user's init choices.
58
443
  * Emits the named-token `skin` shape (skin + colorSpace + tokens), plus
@@ -63,7 +448,7 @@ export function generateZenSumiConfig(opts?: {
63
448
  * storageKey?: string }} opts
64
449
  * @returns {Record<string, unknown>}
65
450
  */
66
- export function generateConfig({ palette, customColors, icons, iconPath, iconStyle, themes, defaultTheme, switcher, includeChart, chartColors, chartShades, storageKey }: {
451
+ export function generateConfig(opts: {
67
452
  palette: string;
68
453
  customColors?: Record<string, string>;
69
454
  icons?: string;
@@ -39,7 +39,7 @@ export function installSkills(names: string[], { cwd, force, skillsDir }?: {
39
39
  export function runSkillsList({ skillsDir, cwd }?: {
40
40
  skillsDir?: string;
41
41
  cwd?: string;
42
- }): Promise<void>;
42
+ }): void;
43
43
  /**
44
44
  * Resolve which skills to install, then copy and report.
45
45
  * @param {string[]} names
@@ -1,33 +1,14 @@
1
- /**
2
- * Advisory validation run by `doctor`: config shape rules for the named-token
3
- * system, and a scan for surface/border tokens misused as text colour.
4
- */
5
- /**
6
- * Validate a parsed rokkit config for the named-token system. All advisory (warn).
7
- * @param {Record<string, unknown> | null} config
8
- * @returns {Array<{ id: string, label: string, status: 'warn', fixable: false, fix: string }>}
9
- */
10
- export function validateConfigShape(config: Record<string, unknown> | null): Array<{
1
+ export function validateConfigShape(config: any): {
11
2
  id: string;
12
3
  label: string;
13
- status: "warn";
14
- fixable: false;
4
+ status: string;
5
+ fixable: boolean;
15
6
  fix: string;
16
- }>;
17
- /**
18
- * Advisory lint: scan src/ for surface/border tokens used as text colour.
19
- * @param {{ list?: (dir: string) => string[], exists: (p: string) => boolean, read: (p: string) => string, resolve: (p: string) => string }} fs
20
- * @returns {Array<{ id: string, label: string, status: 'warn', fixable: false, fix: string }>}
21
- */
22
- export function checkTextTokenUsage(fs: {
23
- list?: (dir: string) => string[];
24
- exists: (p: string) => boolean;
25
- read: (p: string) => string;
26
- resolve: (p: string) => string;
27
- }): Array<{
7
+ }[];
8
+ export function checkTextTokenUsage(fs: any): {
28
9
  id: string;
29
10
  label: string;
30
- status: "warn";
31
- fixable: false;
11
+ status: string;
12
+ fixable: boolean;
32
13
  fix: string;
33
- }>;
14
+ }[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Command line utilities for icon bundling and conversion.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@mdi/svg": "^7.4.47",
30
- "@rokkit/unocss": "1.4.0",
30
+ "@rokkit/unocss": "1.4.1",
31
31
  "sade": "^1.8.1",
32
32
  "@iconify/tools": "5.0.3",
33
33
  "@iconify/types": "^2.0.0",
package/src/agents.js CHANGED
@@ -77,29 +77,36 @@ export async function fetchAgents(
77
77
  ) {
78
78
  const targetRoot = resolve(cwd, '.claude', 'agents')
79
79
  const results = []
80
+ // Sequential on purpose: the outcomes should print in the order the user
81
+ // listed the agents, and every write targets the same directory anyway.
80
82
  for (const name of names) {
81
- const dest = join(targetRoot, `${name}.md`)
82
- if (existsSync(dest) && !force) {
83
- results.push({ name, status: 'skipped' })
84
- continue
85
- }
86
- const res = await fetchImpl(`${baseUrl}/${name}.md`)
87
- if (!res.ok) {
88
- results.push({ name, status: 'unknown' })
89
- continue
90
- }
91
- mkdirSync(targetRoot, { recursive: true })
92
- writeFileSync(dest, await res.text())
93
- results.push({ name, status: 'added' })
83
+ results.push(await fetchAgent(name, { targetRoot, force, baseUrl, fetchImpl }))
94
84
  }
95
85
  return results
96
86
  }
97
87
 
88
+ /**
89
+ * Fetch and write one agent. Reports its outcome rather than throwing, so one
90
+ * missing name doesn't abandon the rest of the batch.
91
+ * @param {string} name
92
+ * @param {{ targetRoot: string, force: boolean, baseUrl: string, fetchImpl: typeof fetch }} ctx
93
+ * @returns {Promise<{ name: string, status: 'added' | 'skipped' | 'unknown' }>}
94
+ */
95
+ async function fetchAgent(name, { targetRoot, force, baseUrl, fetchImpl }) {
96
+ const dest = join(targetRoot, `${name}.md`)
97
+ if (existsSync(dest) && !force) return { name, status: 'skipped' }
98
+ const res = await fetchImpl(`${baseUrl}/${name}.md`)
99
+ if (!res.ok) return { name, status: 'unknown' }
100
+ mkdirSync(targetRoot, { recursive: true })
101
+ writeFileSync(dest, await res.text())
102
+ return { name, status: 'added' }
103
+ }
104
+
98
105
  /**
99
106
  * Print the catalog, marking already-installed agents.
100
107
  * @param {{ agentsDir?: string, cwd?: string }} [opts]
101
108
  */
102
- export async function runAgentsList({ agentsDir, cwd = process.cwd() } = {}) {
109
+ export function runAgentsList({ agentsDir, cwd = process.cwd() } = {}) {
103
110
  const catalog = listAgents({ agentsDir })
104
111
  if (catalog.length === 0) {
105
112
  console.info('No agents available.')
@@ -120,40 +127,66 @@ export async function runAgentsList({ agentsDir, cwd = process.cwd() } = {}) {
120
127
  * @param {string[]} names
121
128
  * @param {{ all?: boolean, force?: boolean, remote?: boolean, agentsDir?: string, cwd?: string, fetchImpl?: typeof fetch }} [opts]
122
129
  */
123
- export async function runAgentsAdd(
124
- names,
125
- { all = false, force = false, remote = false, agentsDir, cwd = process.cwd(), fetchImpl } = {}
126
- ) {
130
+ export async function runAgentsAdd(names, opts = {}) {
131
+ const { all = false, agentsDir } = opts
127
132
  const catalog = listAgents({ agentsDir })
128
- let selected = names
129
- if (all) {
130
- selected = catalog.map((a) => a.name)
131
- } else if (selected.length === 0) {
132
- const res = await prompts({
133
- type: 'multiselect',
134
- name: 'picked',
135
- message: 'Select agents to add',
136
- choices: catalog.map((a) => ({ title: a.name, value: a.name, description: a.description }))
137
- })
138
- selected = res.picked ?? []
139
- }
133
+ const selected = await resolveAgentSelection(names, catalog, all)
140
134
  if (selected.length === 0) {
141
135
  console.info('No agents selected.')
142
136
  return
143
137
  }
138
+ await installAndReport(selected, catalog, opts)
139
+ }
140
+
141
+ /**
142
+ * Install the selection — locally, or from the site with `--remote` — and report
143
+ * each outcome.
144
+ *
145
+ * @param {string[]} selected
146
+ * @param {Array<{ name: string, description: string }>} catalog
147
+ * @param {{ force?: boolean, remote?: boolean, agentsDir?: string, cwd?: string, fetchImpl?: typeof fetch }} opts
148
+ */
149
+ async function installAndReport(
150
+ selected,
151
+ catalog,
152
+ { force = false, remote = false, agentsDir, cwd = process.cwd(), fetchImpl }
153
+ ) {
144
154
  const results = remote
145
155
  ? await fetchAgents(selected, { cwd, force, fetchImpl })
146
156
  : installAgents(selected, { cwd, force, agentsDir })
147
- for (const r of results) {
148
- if (r.status === 'added') console.info(` added .claude/agents/${r.name}.md`)
149
- else if (r.status === 'skipped')
150
- console.info(` skipped ${r.name} (exists — use --force to overwrite)`)
151
- else console.error(` unknown agent: ${r.name}`)
152
- }
153
- if (results.some((r) => r.status === 'unknown')) {
154
- if (!remote) console.error(`\nValid agents: ${catalog.map((a) => a.name).join(', ')}`)
155
- process.exitCode = 1
156
- }
157
+ results.forEach(reportAgentResult)
158
+ if (!results.some((r) => r.status === 'unknown')) return
159
+ // A remote fetch has no catalog to enumerate, so there are no valid names to suggest.
160
+ if (!remote) console.error(`\nValid agents: ${catalog.map((a) => a.name).join(', ')}`)
161
+ process.exitCode = 1
162
+ }
163
+
164
+ /**
165
+ * Which agents to install: everything with `--all`, the named ones, or an
166
+ * interactive pick when neither was given.
167
+ * @param {string[]} names
168
+ * @param {Array<{ name: string, description: string }>} catalog
169
+ * @param {boolean} all
170
+ * @returns {Promise<string[]>}
171
+ */
172
+ async function resolveAgentSelection(names, catalog, all) {
173
+ if (all) return catalog.map((a) => a.name)
174
+ if (names.length > 0) return names
175
+ const res = await prompts({
176
+ type: 'multiselect',
177
+ name: 'picked',
178
+ message: 'Select agents to add',
179
+ choices: catalog.map((a) => ({ title: a.name, value: a.name, description: a.description }))
180
+ })
181
+ return res.picked ?? []
182
+ }
183
+
184
+ /** Report one install outcome. Unknown names go to stderr — they're a user error. */
185
+ function reportAgentResult(r) {
186
+ if (r.status === 'added') console.info(` added .claude/agents/${r.name}.md`)
187
+ else if (r.status === 'skipped')
188
+ console.info(` skipped ${r.name} (exists — use --force to overwrite)`)
189
+ else console.error(` unknown agent: ${r.name}`)
157
190
  }
158
191
 
159
192
  /**