@soleri/cli 1.9.0 → 1.10.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.
Files changed (94) hide show
  1. package/README.md +4 -0
  2. package/dist/commands/agent.d.ts +8 -0
  3. package/dist/commands/agent.js +150 -0
  4. package/dist/commands/agent.js.map +1 -0
  5. package/dist/commands/create.js +38 -6
  6. package/dist/commands/create.js.map +1 -1
  7. package/dist/commands/install-knowledge.js +65 -3
  8. package/dist/commands/install-knowledge.js.map +1 -1
  9. package/dist/commands/install.d.ts +2 -0
  10. package/dist/commands/install.js +80 -0
  11. package/dist/commands/install.js.map +1 -0
  12. package/dist/commands/pack.d.ts +10 -0
  13. package/dist/commands/pack.js +512 -0
  14. package/dist/commands/pack.js.map +1 -0
  15. package/dist/commands/skills.d.ts +8 -0
  16. package/dist/commands/skills.js +167 -0
  17. package/dist/commands/skills.js.map +1 -0
  18. package/dist/commands/uninstall.d.ts +2 -0
  19. package/dist/commands/uninstall.js +74 -0
  20. package/dist/commands/uninstall.js.map +1 -0
  21. package/dist/hook-packs/installer.d.ts +0 -7
  22. package/dist/hook-packs/installer.js +1 -14
  23. package/dist/hook-packs/installer.js.map +1 -1
  24. package/dist/hook-packs/installer.ts +1 -18
  25. package/dist/hook-packs/registry.d.ts +2 -1
  26. package/dist/hook-packs/registry.ts +1 -1
  27. package/dist/main.js +40 -1
  28. package/dist/main.js.map +1 -1
  29. package/dist/prompts/archetypes.d.ts +1 -0
  30. package/dist/prompts/archetypes.js +177 -62
  31. package/dist/prompts/archetypes.js.map +1 -1
  32. package/dist/prompts/create-wizard.d.ts +3 -3
  33. package/dist/prompts/create-wizard.js +99 -50
  34. package/dist/prompts/create-wizard.js.map +1 -1
  35. package/dist/prompts/playbook.d.ts +8 -7
  36. package/dist/prompts/playbook.js +201 -15
  37. package/dist/prompts/playbook.js.map +1 -1
  38. package/dist/utils/checks.d.ts +0 -1
  39. package/dist/utils/checks.js +1 -1
  40. package/dist/utils/checks.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/__tests__/archetypes.test.ts +84 -0
  43. package/src/__tests__/doctor.test.ts +2 -2
  44. package/src/__tests__/wizard-e2e.mjs +508 -0
  45. package/src/commands/agent.ts +181 -0
  46. package/src/commands/create.ts +152 -104
  47. package/src/commands/install-knowledge.ts +75 -4
  48. package/src/commands/install.ts +101 -0
  49. package/src/commands/pack.ts +585 -0
  50. package/src/commands/skills.ts +191 -0
  51. package/src/commands/uninstall.ts +93 -0
  52. package/src/hook-packs/installer.ts +1 -18
  53. package/src/hook-packs/registry.ts +1 -1
  54. package/src/main.ts +42 -1
  55. package/src/prompts/archetypes.ts +193 -62
  56. package/src/prompts/create-wizard.ts +117 -61
  57. package/src/prompts/playbook.ts +207 -21
  58. package/src/utils/checks.ts +1 -1
  59. package/code-reviewer/.claude/hookify.focus-ring-required.local.md +0 -21
  60. package/code-reviewer/.claude/hookify.no-ai-attribution.local.md +0 -18
  61. package/code-reviewer/.claude/hookify.no-any-types.local.md +0 -18
  62. package/code-reviewer/.claude/hookify.no-console-log.local.md +0 -21
  63. package/code-reviewer/.claude/hookify.no-important.local.md +0 -18
  64. package/code-reviewer/.claude/hookify.no-inline-styles.local.md +0 -21
  65. package/code-reviewer/.claude/hookify.semantic-html.local.md +0 -18
  66. package/code-reviewer/.claude/hookify.ux-touch-targets.local.md +0 -18
  67. package/code-reviewer/.mcp.json +0 -11
  68. package/code-reviewer/README.md +0 -346
  69. package/code-reviewer/package-lock.json +0 -4484
  70. package/code-reviewer/package.json +0 -45
  71. package/code-reviewer/scripts/copy-assets.js +0 -15
  72. package/code-reviewer/scripts/setup.sh +0 -130
  73. package/code-reviewer/skills/brainstorming/SKILL.md +0 -170
  74. package/code-reviewer/skills/code-patrol/SKILL.md +0 -176
  75. package/code-reviewer/skills/context-resume/SKILL.md +0 -143
  76. package/code-reviewer/skills/executing-plans/SKILL.md +0 -201
  77. package/code-reviewer/skills/fix-and-learn/SKILL.md +0 -164
  78. package/code-reviewer/skills/health-check/SKILL.md +0 -225
  79. package/code-reviewer/skills/second-opinion/SKILL.md +0 -142
  80. package/code-reviewer/skills/systematic-debugging/SKILL.md +0 -230
  81. package/code-reviewer/skills/verification-before-completion/SKILL.md +0 -170
  82. package/code-reviewer/skills/writing-plans/SKILL.md +0 -207
  83. package/code-reviewer/src/__tests__/facades.test.ts +0 -598
  84. package/code-reviewer/src/activation/activate.ts +0 -125
  85. package/code-reviewer/src/activation/claude-md-content.ts +0 -217
  86. package/code-reviewer/src/activation/inject-claude-md.ts +0 -113
  87. package/code-reviewer/src/extensions/index.ts +0 -47
  88. package/code-reviewer/src/extensions/ops/example.ts +0 -28
  89. package/code-reviewer/src/identity/persona.ts +0 -62
  90. package/code-reviewer/src/index.ts +0 -278
  91. package/code-reviewer/src/intelligence/data/architecture.json +0 -5
  92. package/code-reviewer/src/intelligence/data/code-review.json +0 -5
  93. package/code-reviewer/tsconfig.json +0 -30
  94. package/code-reviewer/vitest.config.ts +0 -23
@@ -9,6 +9,7 @@ export interface Archetype {
9
9
  value: string;
10
10
  label: string;
11
11
  hint: string;
12
+ tier: 'free' | 'premium';
12
13
  defaults: {
13
14
  role: string;
14
15
  description: string;
@@ -25,6 +26,7 @@ export const ARCHETYPES: Archetype[] = [
25
26
  value: 'code-reviewer',
26
27
  label: 'Code Reviewer',
27
28
  hint: 'Catches bugs, enforces patterns, reviews PRs before merge',
29
+ tier: 'free',
28
30
  defaults: {
29
31
  role: 'Catches bugs, enforces code patterns, and reviews pull requests before merge',
30
32
  description:
@@ -32,17 +34,12 @@ export const ARCHETYPES: Archetype[] = [
32
34
  domains: ['code-review', 'architecture'],
33
35
  principles: [
34
36
  'Actionable feedback only',
37
+ 'Readable over clever',
38
+ 'Small PR scope',
35
39
  'Respect existing patterns',
36
- 'Simplicity over cleverness',
37
- ],
38
- skills: [
39
- 'writing-plans',
40
- 'executing-plans',
41
- 'code-patrol',
42
- 'fix-and-learn',
43
- 'second-opinion',
44
40
  ],
45
- tone: 'pragmatic',
41
+ skills: ['code-patrol', 'fix-and-learn', 'second-opinion'],
42
+ tone: 'mentor',
46
43
  greetingTemplate: (name) =>
47
44
  `Hello! I'm ${name}. Drop a PR link or paste code — I'll review it for bugs, patterns, and quality.`,
48
45
  },
@@ -51,6 +48,7 @@ export const ARCHETYPES: Archetype[] = [
51
48
  value: 'security-auditor',
52
49
  label: 'Security Auditor',
53
50
  hint: 'OWASP Top 10, dependency scanning, secrets detection',
51
+ tier: 'free',
54
52
  defaults: {
55
53
  role: 'Identifies vulnerabilities and enforces secure coding practices',
56
54
  description:
@@ -61,14 +59,9 @@ export const ARCHETYPES: Archetype[] = [
61
59
  'Fail closed, not open',
62
60
  'Zero trust by default',
63
61
  'Least privilege always',
62
+ 'Defense in depth',
64
63
  ],
65
- skills: [
66
- 'writing-plans',
67
- 'executing-plans',
68
- 'code-patrol',
69
- 'fix-and-learn',
70
- 'vault-navigator',
71
- ],
64
+ skills: ['code-patrol', 'fix-and-learn', 'vault-navigator'],
72
65
  tone: 'precise',
73
66
  greetingTemplate: (name) =>
74
67
  `Hello! I'm ${name}. I help identify vulnerabilities and enforce secure coding practices across your codebase.`,
@@ -78,25 +71,20 @@ export const ARCHETYPES: Archetype[] = [
78
71
  value: 'api-architect',
79
72
  label: 'API Architect',
80
73
  hint: 'REST/GraphQL design, contract validation, versioning',
74
+ tier: 'free',
81
75
  defaults: {
82
76
  role: 'Designs and validates APIs for consistency, usability, and correctness',
83
77
  description:
84
78
  'This agent reviews API designs for RESTful conventions, GraphQL best practices, versioning strategy, error handling, pagination patterns, and contract consistency. It catches breaking changes before they ship.',
85
79
  domains: ['api-design', 'architecture'],
86
80
  principles: [
87
- 'Convention over configuration',
81
+ 'Backward compatibility by default',
82
+ 'Consumer-driven contracts',
88
83
  'Design for the consumer, not the implementer',
89
- 'Respect existing patterns',
90
84
  'Every migration must be reversible',
91
85
  ],
92
- skills: [
93
- 'writing-plans',
94
- 'executing-plans',
95
- 'vault-navigator',
96
- 'vault-capture',
97
- 'second-opinion',
98
- ],
99
- tone: 'mentor',
86
+ skills: ['vault-navigator', 'vault-capture', 'second-opinion'],
87
+ tone: 'pragmatic',
100
88
  greetingTemplate: (name) =>
101
89
  `Hello! I'm ${name}. Share your API design or schema — I'll review it for consistency, usability, and best practices.`,
102
90
  },
@@ -105,6 +93,7 @@ export const ARCHETYPES: Archetype[] = [
105
93
  value: 'test-engineer',
106
94
  label: 'Test Engineer',
107
95
  hint: 'Test generation, coverage analysis, TDD workflow',
96
+ tier: 'free',
108
97
  defaults: {
109
98
  role: 'Generates tests, analyzes coverage, and enforces test-driven development',
110
99
  description:
@@ -112,18 +101,12 @@ export const ARCHETYPES: Archetype[] = [
112
101
  domains: ['testing', 'code-review'],
113
102
  principles: [
114
103
  'Test everything that can break',
104
+ 'Deterministic tests only',
105
+ 'Test at boundaries, not internals',
115
106
  'Simplicity over cleverness',
116
- 'Actionable feedback only',
117
- 'Respect existing patterns',
118
107
  ],
119
- skills: [
120
- 'writing-plans',
121
- 'executing-plans',
122
- 'test-driven-development',
123
- 'fix-and-learn',
124
- 'code-patrol',
125
- ],
126
- tone: 'pragmatic',
108
+ skills: ['test-driven-development', 'fix-and-learn', 'code-patrol'],
109
+ tone: 'mentor',
127
110
  greetingTemplate: (name) =>
128
111
  `Hello! I'm ${name}. Point me at code that needs tests — I'll generate comprehensive suites and identify coverage gaps.`,
129
112
  },
@@ -132,6 +115,7 @@ export const ARCHETYPES: Archetype[] = [
132
115
  value: 'devops-pilot',
133
116
  label: 'DevOps Pilot',
134
117
  hint: 'CI/CD pipelines, infrastructure, deployment automation',
118
+ tier: 'free',
135
119
  defaults: {
136
120
  role: 'Manages CI/CD pipelines, infrastructure, and deployment automation',
137
121
  description:
@@ -139,17 +123,11 @@ export const ARCHETYPES: Archetype[] = [
139
123
  domains: ['devops', 'architecture'],
140
124
  principles: [
141
125
  'Automate everything repeatable',
142
- 'Graceful degradation over hard failures',
126
+ 'Infrastructure as code',
127
+ 'Blast radius awareness',
143
128
  'Observability built in from day one',
144
- 'Convention over configuration',
145
- ],
146
- skills: [
147
- 'writing-plans',
148
- 'executing-plans',
149
- 'vault-navigator',
150
- 'fix-and-learn',
151
- 'knowledge-harvest',
152
129
  ],
130
+ skills: ['vault-navigator', 'fix-and-learn', 'knowledge-harvest'],
153
131
  tone: 'pragmatic',
154
132
  greetingTemplate: (name) =>
155
133
  `Hello! I'm ${name}. I help with CI/CD, infrastructure, and deployment — describe your setup or issue.`,
@@ -159,24 +137,19 @@ export const ARCHETYPES: Archetype[] = [
159
137
  value: 'database-architect',
160
138
  label: 'Database Architect',
161
139
  hint: 'Schema design, migrations, query optimization',
140
+ tier: 'free',
162
141
  defaults: {
163
142
  role: 'Designs database schemas, manages migrations, and optimizes queries',
164
143
  description:
165
144
  'This agent reviews database designs for normalization, indexing strategy, migration safety, query performance, and data integrity. It supports SQL and NoSQL patterns.',
166
145
  domains: ['database', 'performance'],
167
146
  principles: [
147
+ 'Schema evolution over breaking changes',
148
+ 'Query performance first',
168
149
  'Every migration must be reversible',
169
150
  'Convention over configuration',
170
- 'Test everything that can break',
171
- 'Simplicity over cleverness',
172
- ],
173
- skills: [
174
- 'writing-plans',
175
- 'executing-plans',
176
- 'vault-navigator',
177
- 'vault-capture',
178
- 'knowledge-harvest',
179
151
  ],
152
+ skills: ['vault-navigator', 'vault-capture', 'knowledge-harvest'],
180
153
  tone: 'precise',
181
154
  greetingTemplate: (name) =>
182
155
  `Hello! I'm ${name}. Share your schema, migration, or query — I'll review it for correctness and performance.`,
@@ -186,6 +159,7 @@ export const ARCHETYPES: Archetype[] = [
186
159
  value: 'full-stack',
187
160
  label: 'Full-Stack Assistant',
188
161
  hint: 'General-purpose dev helper across the entire stack',
162
+ tier: 'free',
189
163
  defaults: {
190
164
  role: 'A general-purpose development assistant across the full stack',
191
165
  description:
@@ -193,20 +167,177 @@ export const ARCHETYPES: Archetype[] = [
193
167
  domains: ['code-review', 'testing', 'architecture'],
194
168
  principles: [
195
169
  'Simplicity over cleverness',
170
+ 'Progressive enhancement',
196
171
  'Test everything that can break',
197
172
  'Respect existing patterns',
198
173
  ],
199
- skills: [
200
- 'writing-plans',
201
- 'executing-plans',
202
- 'test-driven-development',
203
- 'code-patrol',
204
- 'fix-and-learn',
205
- 'vault-navigator',
206
- ],
174
+ skills: ['test-driven-development', 'code-patrol', 'fix-and-learn', 'vault-navigator'],
207
175
  tone: 'mentor',
208
176
  greetingTemplate: (name) =>
209
177
  `Hello! I'm ${name}. I help across the full stack — frontend, backend, testing, deployment. What are you working on?`,
210
178
  },
211
179
  },
180
+ {
181
+ value: 'accessibility-guardian',
182
+ label: 'Accessibility Guardian',
183
+ hint: 'WCAG compliance, semantic HTML, keyboard navigation audits',
184
+ tier: 'free',
185
+ defaults: {
186
+ role: 'Audits code for WCAG compliance and accessibility best practices',
187
+ description:
188
+ 'This agent reviews components and pages for accessibility issues including WCAG 2.1 violations, missing ARIA labels, keyboard navigation gaps, color contrast failures, and semantic HTML problems. It provides fix suggestions with severity ratings.',
189
+ domains: ['accessibility', 'code-review'],
190
+ principles: [
191
+ 'WCAG compliance is non-negotiable',
192
+ 'Semantic HTML before ARIA',
193
+ 'Keyboard navigation for every interaction',
194
+ 'Actionable feedback only',
195
+ ],
196
+ skills: ['code-patrol', 'second-opinion'],
197
+ tone: 'precise',
198
+ greetingTemplate: (name) =>
199
+ `Hello! I'm ${name}. I audit your code for accessibility — WCAG compliance, keyboard navigation, screen reader support, and more.`,
200
+ },
201
+ },
202
+ {
203
+ value: 'documentation-writer',
204
+ label: 'Documentation Writer',
205
+ hint: 'Technical docs, API references, example-driven guides',
206
+ tier: 'free',
207
+ defaults: {
208
+ role: 'Creates and maintains clear, example-driven technical documentation',
209
+ description:
210
+ 'This agent helps write and maintain technical documentation including API references, getting-started guides, architecture docs, and changelogs. It follows docs-as-code practices and ensures every concept has a working example.',
211
+ domains: ['documentation', 'developer-experience'],
212
+ principles: [
213
+ 'Clarity over completeness',
214
+ 'Every concept needs an example',
215
+ 'Docs rot faster than code — keep current',
216
+ 'Design for the consumer, not the implementer',
217
+ ],
218
+ skills: ['knowledge-harvest', 'vault-navigator'],
219
+ tone: 'mentor',
220
+ greetingTemplate: (name) =>
221
+ `Hello! I'm ${name}. I help write and maintain clear, example-driven documentation. What needs documenting?`,
222
+ },
223
+ },
224
+
225
+ // ─── Premium Archetypes ──────────────────────────────────────────
226
+ {
227
+ value: 'design-system-architect',
228
+ label: 'Design System Architect',
229
+ hint: 'Tokens, component APIs, accessibility, atomic design hierarchy',
230
+ tier: 'premium',
231
+ defaults: {
232
+ role: 'Designs and enforces design systems with semantic tokens, component APIs, and accessibility baselines',
233
+ description:
234
+ 'This agent architects design systems end-to-end: semantic token hierarchies, component variant APIs, atomic design classification, spacing and typography scales, color contrast enforcement, and cross-platform consistency. It bridges design and engineering with a token-first methodology.',
235
+ domains: ['architecture', 'accessibility', 'code-review', 'design-tokens', 'frontend'],
236
+ principles: [
237
+ 'Semantic tokens over primitives',
238
+ 'Component variant enum over boolean props',
239
+ 'Atomic design classification for component hierarchy',
240
+ 'Token enforcement: blocked then forbidden then preferred',
241
+ 'Respect existing design system patterns',
242
+ 'Every component needs accessibility baseline',
243
+ ],
244
+ skills: ['code-patrol', 'vault-navigator', 'vault-capture', 'knowledge-harvest'],
245
+ tone: 'precise',
246
+ greetingTemplate: (name) =>
247
+ `Hello! I'm ${name}. I architect design systems — tokens, component APIs, accessibility, and cross-platform consistency. Show me your system or describe what you need.`,
248
+ },
249
+ },
250
+ {
251
+ value: 'frontend-craftsman',
252
+ label: 'Frontend Craftsman',
253
+ hint: 'Stack-aware implementation, UX patterns, performance budgets, accessibility',
254
+ tier: 'premium',
255
+ defaults: {
256
+ role: 'Builds production-grade frontends with stack-specific expertise, UX-informed structure, and performance discipline',
257
+ description:
258
+ 'This agent combines deep stack knowledge (React, Next.js, Vue, Svelte, Flutter, SwiftUI) with UX design principles, performance budgets, and accessibility-first development. It provides implementation guidance tailored to your specific framework and UI patterns.',
259
+ domains: ['code-review', 'testing', 'performance', 'accessibility', 'frontend'],
260
+ principles: [
261
+ 'Stack-aware implementation over generic advice',
262
+ 'UX patterns inform code structure',
263
+ 'Performance budget before feature scope',
264
+ 'Accessible by default, not bolted on after',
265
+ 'Convention over configuration',
266
+ ],
267
+ skills: ['test-driven-development', 'code-patrol', 'fix-and-learn', 'vault-navigator'],
268
+ tone: 'mentor',
269
+ greetingTemplate: (name) =>
270
+ `Hello! I'm ${name}. I build production-grade frontends with stack-specific expertise, performance discipline, and accessibility built in. What are you working on?`,
271
+ },
272
+ },
273
+ {
274
+ value: 'ux-intelligence',
275
+ label: 'UX Intelligence Agent',
276
+ hint: 'User behavior, conversion optimization, inclusive design, ethical patterns',
277
+ tier: 'premium',
278
+ defaults: {
279
+ role: 'Applies user behavior research to design decisions for conversion, accessibility, and ethical UX',
280
+ description:
281
+ 'This agent brings UX research intelligence to every design decision: onboarding flows, form optimization, navigation patterns, data entry, search UX, touch targets, animation, performance perception, and AI interaction patterns. It measures conversion impact and ensures inclusive, ethical design.',
282
+ domains: ['accessibility', 'performance', 'testing', 'frontend', 'ux-design'],
283
+ principles: [
284
+ 'User behavior drives design decisions',
285
+ 'Accessibility is not a feature, it is a baseline',
286
+ 'Measure conversion impact of every UX change',
287
+ 'Progressive disclosure over information overload',
288
+ 'Design for the consumer, not the implementer',
289
+ ],
290
+ skills: ['vault-navigator', 'vault-capture', 'second-opinion', 'knowledge-harvest'],
291
+ tone: 'mentor',
292
+ greetingTemplate: (name) =>
293
+ `Hello! I'm ${name}. I help make UX decisions backed by user behavior research — onboarding, forms, navigation, accessibility, and conversion optimization.`,
294
+ },
295
+ },
296
+ {
297
+ value: 'knowledge-curator',
298
+ label: 'Knowledge Curator',
299
+ hint: 'Vault lifecycle, cross-project patterns, domain vocabulary, knowledge architecture',
300
+ tier: 'premium',
301
+ defaults: {
302
+ role: 'Manages knowledge capture, curation, and cross-project pattern extraction for organizational learning',
303
+ description:
304
+ 'This agent manages the full knowledge lifecycle: capturing patterns at the moment of discovery, curating vault entries for quality and consistency, extracting cross-project patterns, maintaining domain vocabulary, and ensuring knowledge is searchable and actionable.',
305
+ domains: ['documentation', 'architecture', 'code-review', 'knowledge-management'],
306
+ principles: [
307
+ 'Knowledge-gather before execute, always',
308
+ 'Vault is the single source of truth',
309
+ 'Capture lessons at the moment of discovery',
310
+ 'Cross-project patterns beat project-local fixes',
311
+ 'Domain vocabulary must be explicit and extensible',
312
+ ],
313
+ skills: ['vault-navigator', 'vault-capture', 'knowledge-harvest', 'brain-debrief'],
314
+ tone: 'precise',
315
+ greetingTemplate: (name) =>
316
+ `Hello! I'm ${name}. I manage knowledge — capturing patterns, curating quality, and extracting insights across projects. What knowledge needs attention?`,
317
+ },
318
+ },
319
+ {
320
+ value: 'architecture-sentinel',
321
+ label: 'Architecture Sentinel',
322
+ hint: 'Governance gates, protocol enforcement, reversible migrations, graceful degradation',
323
+ tier: 'premium',
324
+ defaults: {
325
+ role: 'Enforces architectural governance with checkpoint gates, protocol enforcement, and data-driven decision making',
326
+ description:
327
+ 'This agent guards architectural integrity through two-gate approval (plan then execute), checkpoint-based protocol enforcement, data-driven architecture decisions, reversible migration strategies, and graceful degradation patterns. It ensures systems fail closed and degrade gracefully.',
328
+ domains: ['architecture', 'security', 'code-review', 'testing', 'governance'],
329
+ principles: [
330
+ 'Two-gate approval: plan then execute, never skip',
331
+ 'Protocol enforcement via checkpoint gates',
332
+ 'Data-driven architecture: logic in config, not code',
333
+ 'Every migration must be reversible',
334
+ 'Fail closed, not open',
335
+ 'Graceful degradation over hard failures',
336
+ ],
337
+ skills: ['code-patrol', 'vault-navigator', 'second-opinion', 'knowledge-harvest'],
338
+ tone: 'precise',
339
+ greetingTemplate: (name) =>
340
+ `Hello! I'm ${name}. I enforce architectural governance — approval gates, protocol checkpoints, reversible migrations, and graceful degradation. What needs review?`,
341
+ },
342
+ },
212
343
  ];
@@ -6,7 +6,7 @@
6
6
  * is Enter / arrow keys / space bar.
7
7
  */
8
8
  import * as p from '@clack/prompts';
9
- import type { AgentConfig } from '@soleri/forge/lib';
9
+ import type { AgentConfigInput } from '@soleri/forge/lib';
10
10
  import { ARCHETYPES, type Archetype } from './archetypes.js';
11
11
  import {
12
12
  DOMAIN_OPTIONS,
@@ -31,10 +31,10 @@ function slugify(name: string): string {
31
31
  }
32
32
 
33
33
  /**
34
- * Run the interactive create wizard and return an AgentConfig.
34
+ * Run the interactive create wizard and return an AgentConfigInput.
35
35
  * Returns null if the user cancels at any point.
36
36
  */
37
- export async function runCreateWizard(initialName?: string): Promise<AgentConfig | null> {
37
+ export async function runCreateWizard(initialName?: string): Promise<AgentConfigInput | null> {
38
38
  p.intro('Create a new Soleri agent');
39
39
 
40
40
  // ─── Step 1: Archetype ────────────────────────────────────
@@ -51,18 +51,37 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
51
51
  },
52
52
  ];
53
53
 
54
- const archetypeValue = await p.select({
55
- message: 'What kind of agent are you building?',
54
+ const archetypeValues = await p.multiselect({
55
+ message: 'What kind of agent are you building? (select one or more)',
56
56
  options: archetypeChoices,
57
+ required: false,
57
58
  });
58
59
 
59
- if (p.isCancel(archetypeValue)) return null;
60
+ if (p.isCancel(archetypeValues)) return null;
61
+
62
+ const selectedValues = archetypeValues as string[];
63
+ const isCustom = selectedValues.includes('_custom') || selectedValues.length === 0;
64
+ const selectedArchetypes = ARCHETYPES.filter((a) => selectedValues.includes(a.value));
60
65
 
61
- const archetype: Archetype | undefined = ARCHETYPES.find((a) => a.value === archetypeValue);
62
- const isCustom = archetypeValue === '_custom';
66
+ // Merge defaults from all selected archetypes
67
+ function mergeDefaults(archetypes: Archetype[]) {
68
+ if (archetypes.length === 0) return null;
69
+ const domains = [...new Set(archetypes.flatMap((a) => a.defaults.domains))];
70
+ const principles = [...new Set(archetypes.flatMap((a) => a.defaults.principles))];
71
+ const skills = [...new Set(archetypes.flatMap((a) => a.defaults.skills))];
72
+ const tones = [...new Set(archetypes.map((a) => a.defaults.tone))];
73
+ return { domains, principles, skills, tones };
74
+ }
75
+
76
+ const merged = mergeDefaults(selectedArchetypes);
63
77
 
64
78
  // ─── Step 2: Display name ─────────────────────────────────
65
- const nameDefault = archetype ? archetype.label : undefined;
79
+ const nameDefault =
80
+ selectedArchetypes.length === 1
81
+ ? selectedArchetypes[0].label
82
+ : selectedArchetypes.length > 1
83
+ ? selectedArchetypes.map((a) => a.label).join(' + ')
84
+ : undefined;
66
85
 
67
86
  const name = (await p.text({
68
87
  message: 'Display name',
@@ -75,46 +94,40 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
75
94
 
76
95
  if (p.isCancel(name)) return null;
77
96
 
78
- // ─── Step 3: Agent ID (auto-derived, confirm or edit) ─────
79
- const autoId = slugify(name);
80
-
81
- const id = (await p.text({
82
- message: 'Agent ID (auto-generated, press Enter to accept)',
83
- placeholder: autoId,
84
- initialValue: autoId,
85
- validate: (v = '') => {
86
- if (!/^[a-z][a-z0-9-]*$/.test(v)) return 'Must be kebab-case (e.g., "my-agent")';
87
- },
88
- })) as string;
89
-
90
- if (p.isCancel(id)) return null;
97
+ // ─── Step 3: Agent ID (auto-derived from name) ─────────────
98
+ const id = slugify(name);
91
99
 
92
100
  // ─── Step 4: Role ─────────────────────────────────────────
93
101
  let role: string;
94
102
 
95
- if (isCustom) {
96
- p.note(
97
- [
98
- CUSTOM_ROLE_GUIDANCE.instruction,
99
- '',
100
- 'Examples:',
101
- ...CUSTOM_ROLE_GUIDANCE.examples.map((e) => ` "${e}"`),
102
- ].join('\n'),
103
- '\u2726 Custom Agent Playbook',
104
- );
103
+ if (isCustom || selectedArchetypes.length > 1) {
104
+ if (isCustom) {
105
+ p.note(
106
+ [
107
+ CUSTOM_ROLE_GUIDANCE.instruction,
108
+ '',
109
+ 'Examples:',
110
+ ...CUSTOM_ROLE_GUIDANCE.examples.map((e) => ` "${e}"`),
111
+ ].join('\n'),
112
+ '\u2726 Custom Agent Playbook',
113
+ );
114
+ }
105
115
 
106
- const customRole = (await p.text({
107
- message: 'What does your agent do? (one sentence)',
116
+ const rolePrompt = (await p.text({
117
+ message:
118
+ selectedArchetypes.length > 1
119
+ ? 'Combined role (describe what this multi-purpose agent does)'
120
+ : 'What does your agent do? (one sentence)',
108
121
  placeholder: 'Validates GraphQL schemas against federation rules',
109
122
  validate: (v) => {
110
123
  if (!v || v.length > 100) return 'Required (max 100 chars)';
111
124
  },
112
125
  })) as string;
113
126
 
114
- if (p.isCancel(customRole)) return null;
115
- role = customRole;
127
+ if (p.isCancel(rolePrompt)) return null;
128
+ role = rolePrompt;
116
129
  } else {
117
- const prefilledRole = archetype!.defaults.role;
130
+ const prefilledRole = selectedArchetypes[0].defaults.role;
118
131
  const editedRole = (await p.text({
119
132
  message: 'Role (pre-filled, press Enter to accept)',
120
133
  initialValue: prefilledRole,
@@ -130,29 +143,34 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
130
143
  // ─── Step 5: Description ──────────────────────────────────
131
144
  let description: string;
132
145
 
133
- if (isCustom) {
134
- p.note(
135
- [
136
- CUSTOM_DESCRIPTION_GUIDANCE.instruction,
137
- '',
138
- 'Example:',
139
- ...CUSTOM_DESCRIPTION_GUIDANCE.examples.map((e) => ` "${e}"`),
140
- ].join('\n'),
141
- '\u2726 Description',
142
- );
146
+ if (isCustom || selectedArchetypes.length > 1) {
147
+ if (isCustom) {
148
+ p.note(
149
+ [
150
+ CUSTOM_DESCRIPTION_GUIDANCE.instruction,
151
+ '',
152
+ 'Example:',
153
+ ...CUSTOM_DESCRIPTION_GUIDANCE.examples.map((e) => ` "${e}"`),
154
+ ].join('\n'),
155
+ '\u2726 Description',
156
+ );
157
+ }
143
158
 
144
- const customDesc = (await p.text({
145
- message: 'Describe your agent in detail',
159
+ const descPrompt = (await p.text({
160
+ message:
161
+ selectedArchetypes.length > 1
162
+ ? 'Combined description (what does this multi-purpose agent do?)'
163
+ : 'Describe your agent in detail',
146
164
  placeholder: 'This agent helps developers with...',
147
165
  validate: (v) => {
148
166
  if (!v || v.length < 10 || v.length > 500) return 'Required (10-500 chars)';
149
167
  },
150
168
  })) as string;
151
169
 
152
- if (p.isCancel(customDesc)) return null;
153
- description = customDesc;
170
+ if (p.isCancel(descPrompt)) return null;
171
+ description = descPrompt;
154
172
  } else {
155
- const prefilledDesc = archetype!.defaults.description;
173
+ const prefilledDesc = selectedArchetypes[0].defaults.description;
156
174
  const editedDesc = (await p.text({
157
175
  message: 'Description (pre-filled, press Enter to accept)',
158
176
  initialValue: prefilledDesc,
@@ -166,7 +184,7 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
166
184
  }
167
185
 
168
186
  // ─── Step 6: Domains (multiselect) ────────────────────────
169
- const preselectedDomains = new Set(archetype?.defaults.domains ?? []);
187
+ const preselectedDomains = new Set(merged?.domains ?? []);
170
188
 
171
189
  const domainChoices = [
172
190
  ...DOMAIN_OPTIONS.map((d) => ({
@@ -228,14 +246,16 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
228
246
  }
229
247
 
230
248
  // ─── Step 7: Principles (multiselect) ─────────────────────
231
- const preselectedPrinciples = new Set(archetype?.defaults.principles ?? []);
249
+ const preselectedPrinciples = new Set(merged?.principles ?? []);
232
250
 
233
251
  // Flatten categories into a single options list with group labels
234
- const principleChoices = PRINCIPLE_CATEGORIES.flatMap((cat) => cat.options.map((o) => ({
252
+ const principleChoices = PRINCIPLE_CATEGORIES.flatMap((cat) =>
253
+ cat.options.map((o) => ({
235
254
  value: o.value,
236
255
  label: o.label,
237
256
  hint: cat.label,
238
- })));
257
+ })),
258
+ );
239
259
 
240
260
  principleChoices.push({
241
261
  value: '_custom',
@@ -289,7 +309,16 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
289
309
  }
290
310
 
291
311
  // ─── Step 8: Communication tone ───────────────────────────
292
- const defaultTone = archetype?.defaults.tone ?? 'pragmatic';
312
+ let defaultTone: 'precise' | 'mentor' | 'pragmatic';
313
+
314
+ if (merged && merged.tones.length === 1) {
315
+ defaultTone = merged.tones[0];
316
+ } else if (merged && merged.tones.length > 1) {
317
+ p.note(`Selected archetypes use different tones: ${merged.tones.join(', ')}`, 'Tone Conflict');
318
+ defaultTone = 'pragmatic';
319
+ } else {
320
+ defaultTone = 'pragmatic';
321
+ }
293
322
 
294
323
  const tone = await p.select({
295
324
  message: 'Communication tone',
@@ -304,7 +333,7 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
304
333
  if (p.isCancel(tone)) return null;
305
334
 
306
335
  // ─── Step 9: Skills (multiselect) ─────────────────────────
307
- const preselectedSkills = new Set(archetype?.defaults.skills ?? []);
336
+ const preselectedSkills = new Set(merged?.skills ?? []);
308
337
 
309
338
  p.note(`Always included: ${CORE_SKILLS.join(', ')}`, 'Core Skills');
310
339
 
@@ -328,9 +357,10 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
328
357
  const selectedSkills = [...CORE_SKILLS, ...(skillSelection as string[])];
329
358
 
330
359
  // ─── Step 10: Greeting (auto or custom) ───────────────────
331
- const autoGreeting = archetype
332
- ? archetype.defaults.greetingTemplate(name)
333
- : `Hello! I'm ${name}. I ${role[0].toLowerCase()}${role.slice(1)}.`;
360
+ const autoGreeting =
361
+ selectedArchetypes.length === 1
362
+ ? selectedArchetypes[0].defaults.greetingTemplate(name)
363
+ : `Hello! I'm ${name}. I ${role[0].toLowerCase()}${role.slice(1)}.`;
334
364
 
335
365
  const greetingChoice = await p.select({
336
366
  message: 'Greeting message',
@@ -390,6 +420,31 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
390
420
 
391
421
  if (p.isCancel(outputDir)) return null;
392
422
 
423
+ // ─── Step 12: Setup target ────────────────────────────────
424
+ const setupTarget = await p.select({
425
+ message: 'Setup target',
426
+ options: [
427
+ {
428
+ value: 'claude',
429
+ label: 'Claude Code',
430
+ hint: 'Generate/setup Claude integrations (default)',
431
+ },
432
+ {
433
+ value: 'codex',
434
+ label: 'Codex',
435
+ hint: 'Generate/setup Codex integrations',
436
+ },
437
+ {
438
+ value: 'both',
439
+ label: 'Both',
440
+ hint: 'Generate/setup for Claude Code and Codex',
441
+ },
442
+ ],
443
+ initialValue: 'claude',
444
+ });
445
+
446
+ if (p.isCancel(setupTarget)) return null;
447
+
393
448
  return {
394
449
  id,
395
450
  name,
@@ -401,5 +456,6 @@ export async function runCreateWizard(initialName?: string): Promise<AgentConfig
401
456
  greeting,
402
457
  outputDir,
403
458
  skills: selectedSkills,
459
+ setupTarget: setupTarget as 'claude' | 'codex' | 'both',
404
460
  };
405
461
  }