@wabot-dev/create 0.0.4 → 1.0.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.
- package/README.md +45 -144
- package/lib/create-project.mjs +83 -11
- package/lib/i18n.mjs +18 -6
- package/lib/skills/framework-source.mjs +68 -0
- package/lib/skills/install.mjs +15 -8
- package/lib/skills/registry.mjs +26 -56
- package/package.json +5 -3
- package/skills/wabot-async/SKILL.md +0 -139
- package/skills/wabot-auth/SKILL.md +0 -149
- package/skills/wabot-chat/SKILL.md +0 -136
- package/skills/wabot-di-config/SKILL.md +0 -117
- package/skills/wabot-framework/SKILL.md +0 -79
- package/skills/wabot-framework/references/quickstart.md +0 -85
- package/skills/wabot-mindset/SKILL.md +0 -155
- package/skills/wabot-ops/SKILL.md +0 -151
- package/skills/wabot-persistence/SKILL.md +0 -155
- package/skills/wabot-rest-socket/SKILL.md +0 -163
- package/skills/wabot-validation/SKILL.md +0 -104
package/README.md
CHANGED
|
@@ -1,189 +1,90 @@
|
|
|
1
1
|
# `@wabot-dev/create`
|
|
2
2
|
|
|
3
|
-
CLI para
|
|
3
|
+
CLI para crear un nuevo proyecto Wabot desde el template oficial e instalar las
|
|
4
|
+
skills de agente que **vienen empaquetadas con `@wabot-dev/framework`**.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
> Las skills ya no viven en este paquete: son propiedad de `@wabot-dev/framework`
|
|
7
|
+
> y se versionan junto con su API. Este CLI las descubre desde el framework
|
|
8
|
+
> instalado en el proyecto y las copia a `.claude/`, `.codex/` y/o `.agents/`.
|
|
7
9
|
|
|
8
|
-
##
|
|
10
|
+
## Uso rápido
|
|
9
11
|
|
|
10
12
|
```bash
|
|
11
|
-
npm
|
|
13
|
+
npm create @wabot-dev my-wabot-app
|
|
14
|
+
# o
|
|
15
|
+
npx @wabot-dev/create my-wabot-app
|
|
12
16
|
```
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
El asistente pregunta: nombre, almacenamiento (memoria/postgres), proveedores de
|
|
19
|
+
IA e instalación de skills de agente (por defecto sí). Luego:
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
1. clona el template oficial,
|
|
22
|
+
2. corre `npm install` (deja `@wabot-dev/framework` en `node_modules`),
|
|
23
|
+
3. copia las skills de ese framework a las carpetas de agente elegidas.
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
Si no pasás `project-directory`, se pregunta el nombre en modo interactivo.
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
create-wabot <project-directory>
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Ejemplo:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
create-wabot my-wabot-app
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Variaciones:
|
|
27
|
+
Opciones:
|
|
35
28
|
|
|
36
29
|
```bash
|
|
37
30
|
create-wabot my-wabot-app --db-url "postgres://localhost:5432/wabot"
|
|
38
|
-
create-wabot my-wabot-app --
|
|
39
|
-
create-wabot my-wabot-app --api-key "my-api-key"
|
|
40
|
-
create-wabot my-wabot-app --db-url "postgres://localhost:5432/wabot" --llm-url "http://localhost:3000" --api-key "my-api-key"
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Si no pasás `project-directory`, el CLI pregunta el nombre del proyecto en modo interactivo.
|
|
44
|
-
|
|
45
|
-
## Comando de skills
|
|
46
|
-
|
|
47
|
-
Instalar una skill empaquetada:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
create-wabot skill add <skill-name>
|
|
31
|
+
create-wabot my-wabot-app --lang es
|
|
51
32
|
```
|
|
52
33
|
|
|
53
|
-
|
|
34
|
+
## Canal beta
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## Variaciones de `skill add`
|
|
36
|
+
Las builds beta de `@wabot-dev/create` (versión `X.Y.Z-beta.N`) scaffoldean desde
|
|
37
|
+
la rama **`beta`** del template (`wabot-dev/wabot-template#beta`), que fija la
|
|
38
|
+
versión beta del framework. Las builds estables usan la rama por defecto.
|
|
60
39
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Usa el home del sistema y, si no se indica target, instala para `codex`.
|
|
40
|
+
Para forzar una fuente concreta del template (p. ej. probar una rama antes de
|
|
41
|
+
publicar) usá la variable de entorno:
|
|
64
42
|
|
|
65
43
|
```bash
|
|
66
|
-
create-wabot
|
|
44
|
+
WABOT_TEMPLATE_REF="wabot-dev/wabot-template#beta" create-wabot my-app
|
|
67
45
|
```
|
|
68
46
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- `<os.homedir()>/.codex/skills/wabot-framework`
|
|
47
|
+
## Skills en un proyecto existente
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
49
|
+
Las skills se instalan solas al crear el proyecto. Para **agregarlas o
|
|
50
|
+
actualizarlas** más tarde (por ejemplo tras subir la versión del framework), usá
|
|
51
|
+
el bin que ships el propio framework:
|
|
76
52
|
|
|
77
53
|
```bash
|
|
78
|
-
|
|
54
|
+
npx wabot-skills list # lista las skills empaquetadas
|
|
55
|
+
npx wabot-skills sync # refresca las skills del proyecto a la
|
|
56
|
+
# versión de framework instalada
|
|
57
|
+
npx wabot-skills sync --agents claude,codex
|
|
79
58
|
```
|
|
80
59
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- `./.agents/skills/wabot-framework`
|
|
60
|
+
`sync` sobrescribe en el lugar (resync); detecta las carpetas de agente ya
|
|
61
|
+
presentes en el proyecto (`.claude`, `.codex`, `.agents`) o usá `--agents`.
|
|
84
62
|
|
|
85
|
-
|
|
63
|
+
## `create-wabot skill add` (instalación puntual)
|
|
86
64
|
|
|
87
|
-
|
|
65
|
+
También podés instalar una skill suelta con este CLI. La fuente es el
|
|
66
|
+
`@wabot-dev/framework` resoluble desde el proyecto/entorno actual.
|
|
88
67
|
|
|
89
68
|
```bash
|
|
90
|
-
create-wabot skill add wabot-framework --
|
|
91
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\demo"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### 4. Instalación global para un target único
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
create-wabot skill add wabot-framework --global --target codex
|
|
69
|
+
create-wabot skill add wabot-framework --local # ./.agents/skills/...
|
|
98
70
|
create-wabot skill add wabot-framework --global --target claude
|
|
99
|
-
create-wabot skill add wabot-framework --global --
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Con `--home`:
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\demo" --target codex
|
|
106
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\demo" --target claude
|
|
107
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\demo" --target agents
|
|
71
|
+
create-wabot skill add wabot-framework --global --targets agents,codex,claude --home "/Users/demo"
|
|
108
72
|
```
|
|
109
73
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- `codex` -> `<home>/.codex/skills/wabot-framework`
|
|
113
|
-
- `claude` -> `<home>/.claude/skills/wabot-framework`
|
|
114
|
-
- `agents` -> `<home>/.agents/skills/wabot-framework`
|
|
115
|
-
|
|
116
|
-
### 5. Instalación global para múltiples targets
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
create-wabot skill add wabot-framework --global --targets codex,claude
|
|
120
|
-
create-wabot skill add wabot-framework --global --targets agents,codex,claude
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Con `--home`:
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\demo" --targets agents,codex,claude
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Esto instala la misma skill en múltiples destinos dentro del mismo home root.
|
|
130
|
-
|
|
131
|
-
## Reglas útiles
|
|
74
|
+
Reglas:
|
|
132
75
|
|
|
133
76
|
- `--local` y `--global` son excluyentes.
|
|
134
77
|
- `--home`, `--target` y `--targets` aplican solo con `--global`.
|
|
135
|
-
- Si no se pasa `--target
|
|
136
|
-
- Si el destino ya existe,
|
|
137
|
-
- Si el target no existe en la lista soportada, el comando falla.
|
|
138
|
-
|
|
139
|
-
## Targets soportados
|
|
140
|
-
|
|
141
|
-
```text
|
|
142
|
-
agents
|
|
143
|
-
codex
|
|
144
|
-
claude
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Ejemplos completos
|
|
148
|
-
|
|
149
|
-
Crear un proyecto:
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
create-wabot my-bot
|
|
153
|
-
```
|
|
78
|
+
- Si no se pasa `--target`/`--targets`, el default es `codex`.
|
|
79
|
+
- Si el destino ya existe, falla y no sobrescribe (usá `wabot-skills sync` para refrescar).
|
|
154
80
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
create-wabot my-bot \
|
|
159
|
-
--db-url "postgres://localhost:5432/mybot" \
|
|
160
|
-
--llm-url "http://localhost:3000" \
|
|
161
|
-
--api-key "secret"
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
Instalar la skill local al repo:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
create-wabot skill add wabot-framework --local
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Instalar la skill para Claude en otro home:
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\another-user" --target claude
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Instalar la skill para varios agentes en el mismo home:
|
|
177
|
-
|
|
178
|
-
```bash
|
|
179
|
-
create-wabot skill add wabot-framework --global --home "C:\\Users\\another-user" --targets agents,codex,claude
|
|
180
|
-
```
|
|
81
|
+
Targets soportados: `agents`, `codex`, `claude`.
|
|
181
82
|
|
|
182
83
|
## Desarrollo
|
|
183
84
|
|
|
184
|
-
Mostrar ayuda:
|
|
185
|
-
|
|
186
85
|
```bash
|
|
86
|
+
npm install # linkea @wabot-dev/framework (file:../wabot-ts) para tests
|
|
87
|
+
npm run test:smoke # smokes del instalador de skills
|
|
187
88
|
node ./bin/create-wabot.mjs --help
|
|
188
89
|
node ./bin/create-wabot.mjs skill add --help
|
|
189
90
|
```
|
package/lib/create-project.mjs
CHANGED
|
@@ -6,11 +6,39 @@ import fs from 'fs/promises'
|
|
|
6
6
|
import { spawn } from 'child_process'
|
|
7
7
|
|
|
8
8
|
import { installSkillsInProject, listSupportedAgents } from './skills/install.mjs'
|
|
9
|
-
import { listSkills } from './skills/registry.mjs'
|
|
10
9
|
import { createTranslator } from './i18n.mjs'
|
|
11
10
|
|
|
12
11
|
const REQUIRED_NODE_MAJOR = 22
|
|
13
12
|
|
|
13
|
+
const TEMPLATE_REPO = 'wabot-dev/wabot-template'
|
|
14
|
+
|
|
15
|
+
// Each starter variant lives on its own branch of the template repo, with a
|
|
16
|
+
// matching `*-beta` branch that pins the beta framework. Beta builds of
|
|
17
|
+
// @wabot-dev/create scaffold from the beta branch, stable builds from the
|
|
18
|
+
// default one. `WABOT_TEMPLATE_REF` overrides everything (e.g. to test a branch).
|
|
19
|
+
//
|
|
20
|
+
// variant stable branch beta branch
|
|
21
|
+
// full (default) beta
|
|
22
|
+
// empty empty empty-beta
|
|
23
|
+
const TEMPLATE_BRANCHES = {
|
|
24
|
+
full: { stable: '', beta: 'beta' },
|
|
25
|
+
empty: { stable: 'empty', beta: 'empty-beta' },
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function resolveTemplateRepo(variant = 'empty') {
|
|
29
|
+
if (process.env.WABOT_TEMPLATE_REF) {
|
|
30
|
+
return process.env.WABOT_TEMPLATE_REF
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pkgRaw = await fs.readFile(new URL('../package.json', import.meta.url), 'utf-8')
|
|
34
|
+
const version = JSON.parse(pkgRaw).version ?? ''
|
|
35
|
+
const isBeta = version.includes('-beta')
|
|
36
|
+
|
|
37
|
+
const branches = TEMPLATE_BRANCHES[variant] ?? TEMPLATE_BRANCHES.empty
|
|
38
|
+
const branch = isBeta ? branches.beta : branches.stable
|
|
39
|
+
return branch ? `${TEMPLATE_REPO}#${branch}` : TEMPLATE_REPO
|
|
40
|
+
}
|
|
41
|
+
|
|
14
42
|
const AI_PROVIDERS = [
|
|
15
43
|
{
|
|
16
44
|
value: 'openrouter',
|
|
@@ -76,6 +104,7 @@ function printIntro(t) {
|
|
|
76
104
|
)
|
|
77
105
|
console.log()
|
|
78
106
|
console.log(` ${t('intro.askAbout')}`)
|
|
107
|
+
console.log(` • ${t('intro.bullet.template')}`)
|
|
79
108
|
console.log(` • ${t('intro.bullet.storage')}`)
|
|
80
109
|
console.log(` • ${t('intro.bullet.providers')}`)
|
|
81
110
|
console.log(line)
|
|
@@ -127,6 +156,20 @@ async function collectSetup(options, t) {
|
|
|
127
156
|
throw new Error(t('project.cancelled'))
|
|
128
157
|
}
|
|
129
158
|
|
|
159
|
+
const { template } = await prompts(
|
|
160
|
+
{
|
|
161
|
+
type: 'select',
|
|
162
|
+
name: 'template',
|
|
163
|
+
message: t('template.prompt'),
|
|
164
|
+
choices: [
|
|
165
|
+
{ title: t('template.empty'), value: 'empty' },
|
|
166
|
+
{ title: t('template.full'), value: 'full' },
|
|
167
|
+
],
|
|
168
|
+
initial: 0,
|
|
169
|
+
},
|
|
170
|
+
{ onCancel },
|
|
171
|
+
)
|
|
172
|
+
|
|
130
173
|
const { storage } = await prompts(
|
|
131
174
|
{
|
|
132
175
|
type: 'select',
|
|
@@ -189,25 +232,24 @@ async function collectSetup(options, t) {
|
|
|
189
232
|
|
|
190
233
|
const skills = await collectSkillsSetup({ onCancel }, t)
|
|
191
234
|
|
|
192
|
-
return { storage, databaseUrl, providers, providerKeys, skills }
|
|
235
|
+
return { template, storage, databaseUrl, providers, providerKeys, skills }
|
|
193
236
|
}
|
|
194
237
|
|
|
195
238
|
async function collectSkillsSetup({ onCancel }, t) {
|
|
196
239
|
const supportedAgents = listSupportedAgents()
|
|
197
|
-
const availableSkills = listSkills()
|
|
198
240
|
|
|
199
241
|
const { install } = await prompts(
|
|
200
242
|
{
|
|
201
243
|
type: 'confirm',
|
|
202
244
|
name: 'install',
|
|
203
|
-
message: t('skills.installPrompt'
|
|
245
|
+
message: t('skills.installPrompt'),
|
|
204
246
|
initial: true,
|
|
205
247
|
},
|
|
206
248
|
{ onCancel },
|
|
207
249
|
)
|
|
208
250
|
|
|
209
251
|
if (!install) {
|
|
210
|
-
return { install: false, agents: [], skills: [] }
|
|
252
|
+
return { install: false, agents: [], skills: [], exclude: [] }
|
|
211
253
|
}
|
|
212
254
|
|
|
213
255
|
const { agents } = await prompts(
|
|
@@ -227,10 +269,26 @@ async function collectSkillsSetup({ onCancel }, t) {
|
|
|
227
269
|
{ onCancel },
|
|
228
270
|
)
|
|
229
271
|
|
|
272
|
+
// Always offer the design-system skill explicitly — it's opt-in regardless of
|
|
273
|
+
// the chosen starter.
|
|
274
|
+
const { installDesign } = await prompts(
|
|
275
|
+
{
|
|
276
|
+
type: 'confirm',
|
|
277
|
+
name: 'installDesign',
|
|
278
|
+
message: t('design.prompt'),
|
|
279
|
+
initial: true,
|
|
280
|
+
},
|
|
281
|
+
{ onCancel },
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
// Empty skills list = install every skill the framework ships (resolved at
|
|
285
|
+
// install time from @wabot-dev/framework in the new project); `exclude` drops
|
|
286
|
+
// wabot-design when the dev opts out.
|
|
230
287
|
return {
|
|
231
288
|
install: true,
|
|
232
289
|
agents,
|
|
233
|
-
skills:
|
|
290
|
+
skills: [],
|
|
291
|
+
exclude: installDesign ? [] : ['wabot-design'],
|
|
234
292
|
}
|
|
235
293
|
}
|
|
236
294
|
|
|
@@ -241,7 +299,12 @@ async function createProject(projectName, setup, t) {
|
|
|
241
299
|
|
|
242
300
|
console.log(chalk.blue(t('project.creating', chalk.green(targetDir))))
|
|
243
301
|
|
|
244
|
-
const
|
|
302
|
+
const templateRepo = await resolveTemplateRepo(setup.template)
|
|
303
|
+
if (templateRepo !== TEMPLATE_REPO) {
|
|
304
|
+
console.log(chalk.gray(t('project.templateSource', templateRepo)))
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const emitter = degit(templateRepo, {
|
|
245
308
|
cache: false,
|
|
246
309
|
force: true,
|
|
247
310
|
verbose: true,
|
|
@@ -287,9 +350,13 @@ async function writeEnvFile(targetDir, setup, t) {
|
|
|
287
350
|
|
|
288
351
|
lines.push(t('env.providersComment'))
|
|
289
352
|
for (const provider of AI_PROVIDERS) {
|
|
353
|
+
const apiKey = setup.providerKeys[provider.envKey]
|
|
290
354
|
const selected = setup.providers.includes(provider.value)
|
|
291
|
-
|
|
292
|
-
|
|
355
|
+
// The framework refuses to boot on a key that is defined but empty, so a
|
|
356
|
+
// provider chosen without a key ships commented out like an unchosen one —
|
|
357
|
+
// the project still runs, and printNextSteps warns which keys to fill in.
|
|
358
|
+
if (selected && apiKey) {
|
|
359
|
+
lines.push(`${provider.envKey}=${apiKey}`)
|
|
293
360
|
} else {
|
|
294
361
|
lines.push(`# ${provider.envKey}=`)
|
|
295
362
|
}
|
|
@@ -328,7 +395,12 @@ async function installAgentSkills(projectName, skillsSetup, t) {
|
|
|
328
395
|
console.log(chalk.blue(t('skills.installing')))
|
|
329
396
|
|
|
330
397
|
try {
|
|
331
|
-
const result = await installSkillsInProject(
|
|
398
|
+
const result = await installSkillsInProject(
|
|
399
|
+
targetDir,
|
|
400
|
+
skillsSetup.agents,
|
|
401
|
+
skillsSetup.skills,
|
|
402
|
+
skillsSetup.exclude,
|
|
403
|
+
)
|
|
332
404
|
|
|
333
405
|
const installed = result.installations.filter((i) => i.status === 'installed')
|
|
334
406
|
const skipped = result.installations.filter((i) => i.status === 'skipped')
|
|
@@ -381,6 +453,6 @@ function printNextSteps(projectName, setup, t) {
|
|
|
381
453
|
console.log(chalk.cyan(`\n cd ${projectName}`))
|
|
382
454
|
console.log(chalk.cyan(' npm run dev:watch'))
|
|
383
455
|
console.log(t('next.cmdChannelHint'))
|
|
384
|
-
console.log(chalk.cyan('\n npm run cmd
|
|
456
|
+
console.log(chalk.cyan('\n npm run cmd'))
|
|
385
457
|
console.log(t('next.happy'))
|
|
386
458
|
}
|
package/lib/i18n.mjs
CHANGED
|
@@ -4,9 +4,15 @@ const STRINGS = {
|
|
|
4
4
|
'intro.line1': 'This wizard will scaffold a new chat-bot project from the',
|
|
5
5
|
'intro.line2': (template, env) => `${template} starter and configure your ${env}.`,
|
|
6
6
|
'intro.askAbout': 'You will be asked about:',
|
|
7
|
+
'intro.bullet.template': 'which starter to scaffold (empty or full example)',
|
|
7
8
|
'intro.bullet.storage': 'where to store data (in-memory or PostgreSQL)',
|
|
8
9
|
'intro.bullet.providers': 'which AI providers you want to use',
|
|
9
10
|
|
|
11
|
+
'template.prompt': 'Which starter do you want?',
|
|
12
|
+
'template.empty': 'Empty (just the runner — build from scratch with the skills)',
|
|
13
|
+
'template.full': 'Full example (local chat bot + web UI, no third-party channels)',
|
|
14
|
+
'design.prompt': 'Also install the wabot-design design-system skill?',
|
|
15
|
+
|
|
10
16
|
'node.required': (required, current) =>
|
|
11
17
|
`✖ Node.js ${required} is required (you are running ${current}).`,
|
|
12
18
|
'node.templatePin': (required, nvmrc) =>
|
|
@@ -19,6 +25,7 @@ const STRINGS = {
|
|
|
19
25
|
'project.cancelled': 'Setup cancelled',
|
|
20
26
|
'project.exists': (name) => `Directory ${name} already exists`,
|
|
21
27
|
'project.creating': (dir) => `\nCreating a new Wabot project in ${dir}\n`,
|
|
28
|
+
'project.templateSource': (repo) => ` Using template source: ${repo}`,
|
|
22
29
|
|
|
23
30
|
'storage.prompt': 'How do you want to store data?',
|
|
24
31
|
'storage.memory': 'In-memory (quickest start, data resets on restart)',
|
|
@@ -33,8 +40,7 @@ const STRINGS = {
|
|
|
33
40
|
'providers.anthropic': 'Claude models',
|
|
34
41
|
'providers.google': 'Gemini models',
|
|
35
42
|
|
|
36
|
-
'skills.installPrompt':
|
|
37
|
-
`Install Wabot agent skills (${count}) into the new project?`,
|
|
43
|
+
'skills.installPrompt': 'Install Wabot agent skills into the new project?',
|
|
38
44
|
'skills.agentsPrompt': 'Install for which agents? (space to toggle, enter to confirm)',
|
|
39
45
|
'skills.agentsHint': 'Each adds a folder of <agent>/skills under the project root',
|
|
40
46
|
'skills.installing': '\nInstalling Wabot agent skills...\n',
|
|
@@ -44,7 +50,7 @@ const STRINGS = {
|
|
|
44
50
|
` ⚠ ${count} skill folder(s) already existed and were left untouched.`,
|
|
45
51
|
'skills.failed': (msg) => ` ✖ Failed to install agent skills: ${msg}`,
|
|
46
52
|
'skills.installLater':
|
|
47
|
-
' You can install them later with `
|
|
53
|
+
' You can install/refresh them later with `npx wabot-skills sync`.',
|
|
48
54
|
|
|
49
55
|
'deps.installing': '\nInstalling dependencies with npm...\n',
|
|
50
56
|
'deps.exitCode': (code) => `npm install exited with code ${code}`,
|
|
@@ -74,9 +80,15 @@ const STRINGS = {
|
|
|
74
80
|
'intro.line2': (template, env) =>
|
|
75
81
|
`la plantilla ${template} y configurará tu archivo ${env}.`,
|
|
76
82
|
'intro.askAbout': 'Te preguntaremos sobre:',
|
|
83
|
+
'intro.bullet.template': 'con qué plantilla empezar (vacía o ejemplo completo)',
|
|
77
84
|
'intro.bullet.storage': 'dónde almacenar los datos (en memoria o PostgreSQL)',
|
|
78
85
|
'intro.bullet.providers': 'qué proveedores de IA deseas usar',
|
|
79
86
|
|
|
87
|
+
'template.prompt': '¿Con qué plantilla quieres empezar?',
|
|
88
|
+
'template.empty': 'Vacía (solo el runner — construye desde cero con las skills)',
|
|
89
|
+
'template.full': 'Ejemplo completo (chat bot local + UI web, sin canales de terceros)',
|
|
90
|
+
'design.prompt': '¿Instalar también la skill del sistema de diseño wabot-design?',
|
|
91
|
+
|
|
80
92
|
'node.required': (required, current) =>
|
|
81
93
|
`✖ Se requiere Node.js ${required} (estás usando ${current}).`,
|
|
82
94
|
'node.templatePin': (required, nvmrc) =>
|
|
@@ -89,6 +101,7 @@ const STRINGS = {
|
|
|
89
101
|
'project.cancelled': 'Configuración cancelada',
|
|
90
102
|
'project.exists': (name) => `El directorio ${name} ya existe`,
|
|
91
103
|
'project.creating': (dir) => `\nCreando un nuevo proyecto Wabot en ${dir}\n`,
|
|
104
|
+
'project.templateSource': (repo) => ` Usando fuente del template: ${repo}`,
|
|
92
105
|
|
|
93
106
|
'storage.prompt': '¿Cómo deseas almacenar los datos?',
|
|
94
107
|
'storage.memory': 'En memoria (inicio más rápido, los datos se pierden al reiniciar)',
|
|
@@ -106,8 +119,7 @@ const STRINGS = {
|
|
|
106
119
|
'providers.anthropic': 'Modelos Claude',
|
|
107
120
|
'providers.google': 'Modelos Gemini',
|
|
108
121
|
|
|
109
|
-
'skills.installPrompt':
|
|
110
|
-
`¿Instalar las skills de agente de Wabot (${count}) en el nuevo proyecto?`,
|
|
122
|
+
'skills.installPrompt': '¿Instalar las skills de agente de Wabot en el nuevo proyecto?',
|
|
111
123
|
'skills.agentsPrompt':
|
|
112
124
|
'¿Para qué agentes instalarlas? (espacio para alternar, enter para confirmar)',
|
|
113
125
|
'skills.agentsHint':
|
|
@@ -119,7 +131,7 @@ const STRINGS = {
|
|
|
119
131
|
` ⚠ ${count} carpeta(s) de skill ya existían y no se modificaron.`,
|
|
120
132
|
'skills.failed': (msg) => ` ✖ Fallo al instalar las skills de agente: ${msg}`,
|
|
121
133
|
'skills.installLater':
|
|
122
|
-
' Puedes instalarlas más tarde con `
|
|
134
|
+
' Puedes instalarlas/actualizarlas más tarde con `npx wabot-skills sync`.',
|
|
123
135
|
|
|
124
136
|
'deps.installing': '\nInstalando dependencias con npm...\n',
|
|
125
137
|
'deps.exitCode': (code) => `npm install terminó con código ${code}`,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createRequire } from 'module'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url)
|
|
7
|
+
|
|
8
|
+
const FRAMEWORK_PKG = '@wabot-dev/framework'
|
|
9
|
+
const FRAMEWORK_SEGMENTS = FRAMEWORK_PKG.split('/')
|
|
10
|
+
|
|
11
|
+
function packageRootFromEntry(entryPath) {
|
|
12
|
+
let dir = path.dirname(entryPath)
|
|
13
|
+
const { root } = path.parse(dir)
|
|
14
|
+
while (dir && dir !== root) {
|
|
15
|
+
const pkgFile = path.join(dir, 'package.json')
|
|
16
|
+
if (fs.existsSync(pkgFile)) {
|
|
17
|
+
try {
|
|
18
|
+
if (JSON.parse(fs.readFileSync(pkgFile, 'utf8')).name === FRAMEWORK_PKG) {
|
|
19
|
+
return dir
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
// ignore malformed package.json and keep walking up
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
dir = path.dirname(dir)
|
|
26
|
+
}
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Locate the packaged `skills/` directory shipped by @wabot-dev/framework.
|
|
31
|
+
//
|
|
32
|
+
// The framework owns the skills and versions them with its API. When bootstrapping
|
|
33
|
+
// or resyncing a project, resolve them from the framework installed *in that
|
|
34
|
+
// project* (`fromDir`) so the copied skills match the project's pinned framework
|
|
35
|
+
// version. For standalone use (e.g. `skill add`) fall back to the framework
|
|
36
|
+
// resolvable from this package.
|
|
37
|
+
export function resolveFrameworkSkillsDir(fromDir) {
|
|
38
|
+
const candidates = []
|
|
39
|
+
|
|
40
|
+
if (fromDir) {
|
|
41
|
+
candidates.push(path.join(fromDir, 'node_modules', ...FRAMEWORK_SEGMENTS, 'skills'))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const pkgRoot = packageRootFromEntry(require.resolve(FRAMEWORK_PKG))
|
|
46
|
+
if (pkgRoot) candidates.push(path.join(pkgRoot, 'skills'))
|
|
47
|
+
} catch {
|
|
48
|
+
// framework not resolvable via node resolution; try the node_modules lookups below
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const createPkgRoot = fileURLToPath(new URL('../../', import.meta.url))
|
|
52
|
+
candidates.push(path.join(createPkgRoot, 'node_modules', ...FRAMEWORK_SEGMENTS, 'skills'))
|
|
53
|
+
candidates.push(path.join(process.cwd(), 'node_modules', ...FRAMEWORK_SEGMENTS, 'skills'))
|
|
54
|
+
|
|
55
|
+
// Monorepo dev fallback: the framework lives beside this package as a sibling
|
|
56
|
+
// checkout (`../wabot-ts`). Used so smoke tests can resolve skills without the
|
|
57
|
+
// framework being installed as a dependency; installed lookups above win.
|
|
58
|
+
candidates.push(path.join(createPkgRoot, '..', 'wabot-ts', 'skills'))
|
|
59
|
+
|
|
60
|
+
for (const dir of candidates) {
|
|
61
|
+
if (dir && fs.existsSync(dir)) return dir
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Could not locate ${FRAMEWORK_PKG} skills. Ensure ${FRAMEWORK_PKG} is installed ` +
|
|
66
|
+
`(the packaged skills ship with the framework as of the version that added them).`,
|
|
67
|
+
)
|
|
68
|
+
}
|
package/lib/skills/install.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import os from 'os'
|
|
|
3
3
|
import path from 'path'
|
|
4
4
|
|
|
5
5
|
import { getSkill, listSkillNames, listSkills } from './registry.mjs'
|
|
6
|
+
import { resolveFrameworkSkillsDir } from './framework-source.mjs'
|
|
6
7
|
|
|
7
8
|
const supportedAgents = {
|
|
8
9
|
codex: ['.codex', 'skills'],
|
|
@@ -14,7 +15,7 @@ export function listSupportedAgents() {
|
|
|
14
15
|
return Object.keys(supportedAgents)
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export async function installSkillsInProject(projectDir, agents, skillNames) {
|
|
18
|
+
export async function installSkillsInProject(projectDir, agents, skillNames, excludeSkills = []) {
|
|
18
19
|
if (!projectDir) {
|
|
19
20
|
throw new Error('installSkillsInProject: projectDir is required')
|
|
20
21
|
}
|
|
@@ -28,8 +29,13 @@ export async function installSkillsInProject(projectDir, agents, skillNames) {
|
|
|
28
29
|
return agent
|
|
29
30
|
})
|
|
30
31
|
|
|
31
|
-
const
|
|
32
|
-
|
|
32
|
+
const skillsDir = resolveFrameworkSkillsDir(projectDir)
|
|
33
|
+
const excluded = new Set(excludeSkills ?? [])
|
|
34
|
+
const skills = (
|
|
35
|
+
skillNames && skillNames.length > 0
|
|
36
|
+
? skillNames.map((name) => requireSkill(name, skillsDir))
|
|
37
|
+
: listSkills(skillsDir)
|
|
38
|
+
).filter((skill) => !excluded.has(skill.name))
|
|
33
39
|
|
|
34
40
|
const installations = []
|
|
35
41
|
|
|
@@ -59,22 +65,23 @@ export async function installSkillsInProject(projectDir, agents, skillNames) {
|
|
|
59
65
|
return { agents: resolvedAgents, skills: skills.map((skill) => skill.name), installations }
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
function requireSkill(name) {
|
|
63
|
-
const skill = getSkill(name)
|
|
68
|
+
function requireSkill(name, skillsDir) {
|
|
69
|
+
const skill = getSkill(name, skillsDir)
|
|
64
70
|
if (!skill) {
|
|
65
71
|
throw new Error(
|
|
66
|
-
`Unknown skill "${name}". Available skills: ${listSkillNames().join(', ')}`,
|
|
72
|
+
`Unknown skill "${name}". Available skills: ${listSkillNames(skillsDir).join(', ')}`,
|
|
67
73
|
)
|
|
68
74
|
}
|
|
69
75
|
return skill
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
export async function installSkill(skillName, options, cwd = process.cwd()) {
|
|
73
|
-
const
|
|
79
|
+
const skillsDir = resolveFrameworkSkillsDir(cwd)
|
|
80
|
+
const skill = getSkill(skillName, skillsDir)
|
|
74
81
|
|
|
75
82
|
if (!skill) {
|
|
76
83
|
throw new Error(
|
|
77
|
-
`Unknown skill "${skillName}". Available skills: ${listSkillNames().join(', ')}`,
|
|
84
|
+
`Unknown skill "${skillName}". Available skills: ${listSkillNames(skillsDir).join(', ')}`,
|
|
78
85
|
)
|
|
79
86
|
}
|
|
80
87
|
|