@wabot-dev/framework 0.9.27 → 2.0.0-beta.0
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 +27 -0
- package/bin/skills.mjs +151 -0
- package/bin/wabot-skills.mjs +120 -0
- package/dist/build/build.js +1031 -8
- package/dist/src/addon/chat-bot/in-memory/InMemoryChatMemory.js +1 -3
- package/dist/src/addon/chat-bot/xai/XAIChatAdapter.js +180 -0
- package/dist/src/addon/chat-controller/cmd/cmdChannelSocketPath.js +1 -5
- package/dist/src/addon/chat-controller/hubspot/@hubspot.js +28 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotChannel.js +81 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotChannelConfig.js +20 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotReceiver.js +42 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotSender.js +118 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotWebhookController.js +122 -0
- package/dist/src/addon/chat-controller/hubspot/downloadHubSpotAttachments.js +45 -0
- package/dist/src/addon/chat-controller/hubspot/hubspotChannelName.js +3 -0
- package/dist/src/addon/chat-controller/hubspot/verifyHubSpotSignatureV3.js +28 -0
- package/dist/src/addon/chat-controller/{telegram/markdownToTelegramHtml.js → markdown/markdownToChatHtml.js} +5 -8
- package/dist/src/addon/chat-controller/slack/@slack.js +22 -0
- package/dist/src/addon/chat-controller/slack/SlackChannel.js +187 -0
- package/dist/src/addon/chat-controller/slack/SlackChannelConfig.js +12 -0
- package/dist/src/addon/chat-controller/slack/markdownToSlackMrkdwn.js +38 -0
- package/dist/src/addon/chat-controller/slack/slackChannelName.js +3 -0
- package/dist/src/addon/chat-controller/telegram/TelegramChannel.js +2 -2
- package/dist/src/addon/ui/preact/PreactRenderer.js +86 -0
- package/dist/src/addon/ui/preact/outlet.js +22 -0
- package/dist/src/addon/ui/preact/preactClientRuntime.js +67 -0
- package/dist/src/core/repository/CrudRepository.js +7 -7
- package/dist/src/feature/async/computeDedupKey.js +1 -1
- package/dist/src/feature/chat-controller/runChatControllers.js +4 -1
- package/dist/src/feature/pg/@pgExtension.js +2 -4
- package/dist/src/feature/project-runner/ProjectRunner.js +62 -10
- package/dist/src/feature/project-runner/scanner.js +1 -1
- package/dist/src/feature/repository/@memExtension.js +1 -2
- package/dist/src/feature/rest-controller/runRestControllers.js +11 -6
- package/dist/src/feature/ui-controller/actions.js +35 -0
- package/dist/src/feature/ui-controller/bundler/UiBundler.js +191 -0
- package/dist/src/feature/ui-controller/bundler/devMiddleware.js +41 -0
- package/dist/src/feature/ui-controller/bundler/index.js +4 -0
- package/dist/src/feature/ui-controller/bundler/manifest.js +34 -0
- package/dist/src/feature/ui-controller/bundler/navRuntime.js +236 -0
- package/dist/src/feature/ui-controller/bundler/pageAssets.js +30 -0
- package/dist/src/feature/ui-controller/document/escape.js +17 -0
- package/dist/src/feature/ui-controller/document/helpers.js +13 -0
- package/dist/src/feature/ui-controller/document/renderDocument.js +43 -0
- package/dist/src/feature/ui-controller/island/IslandRegistry.js +68 -0
- package/dist/src/feature/ui-controller/island/island.js +40 -0
- package/dist/src/feature/ui-controller/island/serialize.js +35 -0
- package/dist/src/feature/ui-controller/metadata/@action.js +18 -0
- package/dist/src/feature/ui-controller/metadata/@uiController.js +19 -0
- package/dist/src/feature/ui-controller/metadata/@uiMiddleware.js +20 -0
- package/dist/src/feature/ui-controller/metadata/@view.js +18 -0
- package/dist/src/feature/ui-controller/metadata/UiControllerMetadataStore.js +107 -0
- package/dist/src/feature/ui-controller/renderer/UiRendererRegistry.js +42 -0
- package/dist/src/feature/ui-controller/runUiControllers.js +285 -0
- package/dist/src/index.d.ts +640 -3
- package/dist/src/index.js +32 -3
- package/dist/src/testing/LlmJudge.js +93 -0
- package/dist/src/testing/MockChatAdapter.js +68 -0
- package/dist/src/testing/TestChatMemory.js +73 -0
- package/dist/src/testing/asyncHarness.js +66 -0
- package/dist/src/testing/auth.js +114 -0
- package/dist/src/testing/chatBotHarness.js +88 -0
- package/dist/src/testing/chatControllerHarness.js +94 -0
- package/dist/src/testing/conformance/chatAdapterConformanceCases.js +656 -0
- package/dist/src/testing/fixtures.js +53 -0
- package/dist/src/testing/helpers.js +42 -0
- package/dist/src/testing/index.d.ts +818 -0
- package/dist/src/testing/index.js +14 -0
- package/dist/src/testing/repositories.js +34 -0
- package/dist/src/testing/restHarness.js +127 -0
- package/dist/src/testing/testImageBase64.js +5 -0
- package/dist/src/testing/uiHarness.js +102 -0
- package/dist/src/testing/validation.js +66 -0
- package/dist/src/ui/client.js +6 -0
- package/dist/src/ui/index.d.ts +427 -0
- package/dist/src/ui/index.js +29 -0
- package/dist/src/ui/jsx-dev-runtime.d.ts +1 -0
- package/dist/src/ui/jsx-dev-runtime.js +1 -0
- package/dist/src/ui/jsx-runtime.d.ts +1 -0
- package/dist/src/ui/jsx-runtime.js +1 -0
- package/package.json +48 -11
- package/skills/wabot-async/SKILL.md +143 -0
- package/skills/wabot-auth/SKILL.md +153 -0
- package/skills/wabot-chat/SKILL.md +140 -0
- package/skills/wabot-di-config/SKILL.md +117 -0
- package/skills/wabot-framework/SKILL.md +81 -0
- package/skills/wabot-framework/references/quickstart.md +85 -0
- package/skills/wabot-mindset/SKILL.md +159 -0
- package/skills/wabot-ops/SKILL.md +151 -0
- package/skills/wabot-persistence/SKILL.md +159 -0
- package/skills/wabot-rest-socket/SKILL.md +167 -0
- package/skills/wabot-testing/SKILL.md +214 -0
- package/skills/wabot-ui/SKILL.md +201 -0
- package/skills/wabot-validation/SKILL.md +108 -0
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
- 🤖 **Soporte para bots con IA** - Inteligencia artificial lista para usar
|
|
29
29
|
- 🧠 **Múltiples proveedores de IA** - OpenAI, Google Gemini, Anthropic Claude
|
|
30
30
|
- 💬 **Múltiples canales de chat** - Telegram, WhatsApp, Socket y más
|
|
31
|
+
- 🧪 **Sistema de testing integrado** - Prueba tus chatbots sin API keys ni base de datos
|
|
31
32
|
- 📖 **Documentación clara y en español** - Aprende sin barreras de idioma
|
|
32
33
|
|
|
33
34
|
---
|
|
@@ -103,6 +104,32 @@ Los addons opcionales (`pg`, SDKs de IA) se mantienen como `peerDependencies` y
|
|
|
103
104
|
|
|
104
105
|
---
|
|
105
106
|
|
|
107
|
+
## 🧪 Testing
|
|
108
|
+
|
|
109
|
+
El framework incluye un sistema de testing en `@wabot-dev/framework/testing`, agnóstico al runner (node:test, vitest, bun test). Permite probar chatbots de forma determinista —sin API keys ni base de datos— y también evaluar el comportamiento real con un juez LLM.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { createChatBotHarness, LlmJudge } from '@wabot-dev/framework/testing'
|
|
113
|
+
|
|
114
|
+
// Determinista: el LLM se simula, tus tools se ejecutan de verdad
|
|
115
|
+
const harness = createChatBotHarness({ mindset: EliaMindset })
|
|
116
|
+
harness.adapter.callTool('saveEvent', { title: 'Demo', ... }).reply('¡Agendado!')
|
|
117
|
+
|
|
118
|
+
const turn = await harness.send('agenda una demo mañana')
|
|
119
|
+
// turn.replies, turn.toolCalls (con resultados reales), harness.history()
|
|
120
|
+
|
|
121
|
+
// Evals: juzga conversaciones reales con un LLM
|
|
122
|
+
const judge = new LlmJudge({ adapter, models: [{ model: 'claude-haiku-4-5' }] })
|
|
123
|
+
await judge.assert({
|
|
124
|
+
transcript: harness.history(),
|
|
125
|
+
criteria: 'Responde en español y confirma la fecha del evento',
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
También incluye harnesses para controllers de chat (`createChatControllerHarness`), endpoints REST con guards JWT/API-Key reales (`createRestHarness`), commands y crons (`createAsyncHarness`), repositorios en memoria (`useMemoryRepositories`), aserciones de validación y una suite de conformance para adapters LLM propios (`chatAdapterConformanceCases`).
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
106
133
|
## 💬 Plataformas Soportadas
|
|
107
134
|
|
|
108
135
|
Wabot se integra nativamente con las principales plataformas de mensajería:
|
package/bin/skills.mjs
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Canonical skills installer for @wabot-dev/framework.
|
|
2
|
+
//
|
|
3
|
+
// The packaged agent skills live at `<package>/skills/<name>/SKILL.md` and are
|
|
4
|
+
// versioned together with the framework API they document. This module is the
|
|
5
|
+
// single source of truth for enumerating and installing them; it is consumed by
|
|
6
|
+
// the `wabot-skills` bin and by @wabot-dev/create during project bootstrap.
|
|
7
|
+
//
|
|
8
|
+
// Dependency-free (node builtins only) so `npx wabot-skills` works with just the
|
|
9
|
+
// framework installed.
|
|
10
|
+
|
|
11
|
+
import fs from 'fs/promises'
|
|
12
|
+
import fss from 'fs'
|
|
13
|
+
import os from 'os'
|
|
14
|
+
import path from 'path'
|
|
15
|
+
import { fileURLToPath } from 'url'
|
|
16
|
+
|
|
17
|
+
export const SKILLS_DIR = fileURLToPath(new URL('../skills', import.meta.url))
|
|
18
|
+
|
|
19
|
+
const AGENT_DIRS = {
|
|
20
|
+
claude: ['.claude', 'skills'],
|
|
21
|
+
codex: ['.codex', 'skills'],
|
|
22
|
+
agents: ['.agents', 'skills'],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function listSupportedAgents() {
|
|
26
|
+
return Object.keys(AGENT_DIRS)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function agentSkillsSegments(agent) {
|
|
30
|
+
const segments = AGENT_DIRS[agent]
|
|
31
|
+
if (!segments) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Unsupported agent "${agent}". Supported: ${listSupportedAgents().join(', ')}`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return segments
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function listSkillNames() {
|
|
40
|
+
return fss
|
|
41
|
+
.readdirSync(SKILLS_DIR, { withFileTypes: true })
|
|
42
|
+
.filter(
|
|
43
|
+
(entry) =>
|
|
44
|
+
entry.isDirectory() &&
|
|
45
|
+
fss.existsSync(path.join(SKILLS_DIR, entry.name, 'SKILL.md')),
|
|
46
|
+
)
|
|
47
|
+
.map((entry) => entry.name)
|
|
48
|
+
.sort()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function listSkills() {
|
|
52
|
+
return listSkillNames().map((name) => ({
|
|
53
|
+
name,
|
|
54
|
+
sourceDir: path.join(SKILLS_DIR, name),
|
|
55
|
+
}))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getSkill(name) {
|
|
59
|
+
const sourceDir = path.join(SKILLS_DIR, name)
|
|
60
|
+
if (!fss.existsSync(path.join(sourceDir, 'SKILL.md'))) {
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
return { name, sourceDir }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function resolveSkills(skillNames) {
|
|
67
|
+
if (!skillNames || skillNames.length === 0) {
|
|
68
|
+
return listSkills()
|
|
69
|
+
}
|
|
70
|
+
return skillNames.map((name) => {
|
|
71
|
+
const skill = getSkill(name)
|
|
72
|
+
if (!skill) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Unknown skill "${name}". Available skills: ${listSkillNames().join(', ')}`,
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
return skill
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Copy skills into `<projectDir>/.<agent>/skills`. By default existing skills are
|
|
82
|
+
// left untouched (bootstrap semantics). Pass `{ overwrite: true }` to refresh them
|
|
83
|
+
// to the currently installed framework version (resync semantics).
|
|
84
|
+
export async function installSkillsInProject(projectDir, agents, skillNames, options = {}) {
|
|
85
|
+
if (!projectDir) {
|
|
86
|
+
throw new Error('installSkillsInProject: projectDir is required')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const resolvedAgents = (agents && agents.length > 0 ? agents : ['claude']).map((agent) => {
|
|
90
|
+
agentSkillsSegments(agent)
|
|
91
|
+
return agent
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const skills = resolveSkills(skillNames)
|
|
95
|
+
const overwrite = options.overwrite === true
|
|
96
|
+
const installations = []
|
|
97
|
+
|
|
98
|
+
for (const agent of resolvedAgents) {
|
|
99
|
+
const baseDir = path.join(projectDir, ...agentSkillsSegments(agent))
|
|
100
|
+
await fs.mkdir(baseDir, { recursive: true })
|
|
101
|
+
|
|
102
|
+
for (const skill of skills) {
|
|
103
|
+
const installDir = path.join(baseDir, skill.name)
|
|
104
|
+
try {
|
|
105
|
+
await fs.cp(skill.sourceDir, installDir, {
|
|
106
|
+
recursive: true,
|
|
107
|
+
force: overwrite,
|
|
108
|
+
errorOnExist: !overwrite,
|
|
109
|
+
})
|
|
110
|
+
installations.push({
|
|
111
|
+
agent,
|
|
112
|
+
skill: skill.name,
|
|
113
|
+
installDir,
|
|
114
|
+
status: overwrite ? 'synced' : 'installed',
|
|
115
|
+
})
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!overwrite && (error?.code === 'ERR_FS_CP_EEXIST' || error?.code === 'EEXIST')) {
|
|
118
|
+
installations.push({ agent, skill: skill.name, installDir, status: 'skipped' })
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
throw error
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { agents: resolvedAgents, skills: skills.map((skill) => skill.name), installations }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Copy a single skill into agent homes under `homeRoot` (defaults to $HOME).
|
|
130
|
+
export async function installSkillGlobally(skillName, agents, homeRoot = os.homedir()) {
|
|
131
|
+
const skill = getSkill(skillName)
|
|
132
|
+
if (!skill) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Unknown skill "${skillName}". Available skills: ${listSkillNames().join(', ')}`,
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
const resolvedAgents = (agents && agents.length > 0 ? agents : ['claude']).map((agent) => {
|
|
138
|
+
agentSkillsSegments(agent)
|
|
139
|
+
return agent
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const installations = []
|
|
143
|
+
for (const agent of resolvedAgents) {
|
|
144
|
+
const baseDir = path.join(homeRoot, ...agentSkillsSegments(agent))
|
|
145
|
+
await fs.mkdir(baseDir, { recursive: true })
|
|
146
|
+
const installDir = path.join(baseDir, skill.name)
|
|
147
|
+
await fs.cp(skill.sourceDir, installDir, { recursive: true, force: true, errorOnExist: false })
|
|
148
|
+
installations.push({ agent, skill: skill.name, installDir })
|
|
149
|
+
}
|
|
150
|
+
return { skill: skill.name, homeRoot, installations }
|
|
151
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// wabot-skills — install / resync the packaged Wabot agent skills that ship with
|
|
4
|
+
// the installed @wabot-dev/framework version.
|
|
5
|
+
//
|
|
6
|
+
// wabot-skills list
|
|
7
|
+
// wabot-skills sync [--agents claude,codex,agents] [--project <dir>]
|
|
8
|
+
// wabot-skills add <skill> [--agents claude,codex,agents] [--home <dir>]
|
|
9
|
+
//
|
|
10
|
+
// `sync` refreshes the project's skills to match the currently installed framework
|
|
11
|
+
// version (overwrites in place). Run it after upgrading @wabot-dev/framework.
|
|
12
|
+
|
|
13
|
+
import fss from 'fs'
|
|
14
|
+
import path from 'path'
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
installSkillGlobally,
|
|
18
|
+
installSkillsInProject,
|
|
19
|
+
listSkillNames,
|
|
20
|
+
listSupportedAgents,
|
|
21
|
+
} from './skills.mjs'
|
|
22
|
+
|
|
23
|
+
function parseFlags(argv) {
|
|
24
|
+
const flags = {}
|
|
25
|
+
const positional = []
|
|
26
|
+
for (let i = 0; i < argv.length; i++) {
|
|
27
|
+
const arg = argv[i]
|
|
28
|
+
if (arg.startsWith('--')) {
|
|
29
|
+
const key = arg.slice(2)
|
|
30
|
+
const next = argv[i + 1]
|
|
31
|
+
if (next === undefined || next.startsWith('--')) {
|
|
32
|
+
flags[key] = true
|
|
33
|
+
} else {
|
|
34
|
+
flags[key] = next
|
|
35
|
+
i++
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
positional.push(arg)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { flags, positional }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function parseAgents(value) {
|
|
45
|
+
if (!value || value === true) return listSupportedAgents()
|
|
46
|
+
return String(value)
|
|
47
|
+
.split(',')
|
|
48
|
+
.map((a) => a.trim())
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function usage() {
|
|
53
|
+
console.log(`wabot-skills — manage packaged Wabot agent skills
|
|
54
|
+
|
|
55
|
+
Usage:
|
|
56
|
+
wabot-skills list
|
|
57
|
+
wabot-skills sync [--agents claude,codex,agents] [--project <dir>]
|
|
58
|
+
wabot-skills add <skill> [--agents claude,codex,agents] [--home <dir>]
|
|
59
|
+
|
|
60
|
+
sync refreshes existing project skills to the installed framework version.`)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function main() {
|
|
64
|
+
const [command, ...rest] = process.argv.slice(2)
|
|
65
|
+
const { flags, positional } = parseFlags(rest)
|
|
66
|
+
|
|
67
|
+
if (!command || command === 'help' || flags.help) {
|
|
68
|
+
usage()
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (command === 'list') {
|
|
73
|
+
for (const name of listSkillNames()) console.log(name)
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (command === 'sync') {
|
|
78
|
+
const projectDir = path.resolve(flags.project || process.cwd())
|
|
79
|
+
// Default to the agent dirs that already exist in the project; fall back to claude.
|
|
80
|
+
let agents = flags.agents
|
|
81
|
+
? parseAgents(flags.agents)
|
|
82
|
+
: listSupportedAgents().filter((agent) =>
|
|
83
|
+
fss.existsSync(path.join(projectDir, `.${agent}`, 'skills')),
|
|
84
|
+
)
|
|
85
|
+
if (agents.length === 0) agents = ['claude']
|
|
86
|
+
|
|
87
|
+
const result = await installSkillsInProject(projectDir, agents, undefined, { overwrite: true })
|
|
88
|
+
const byAgent = new Map()
|
|
89
|
+
for (const item of result.installations) {
|
|
90
|
+
byAgent.set(item.agent, (byAgent.get(item.agent) ?? 0) + 1)
|
|
91
|
+
}
|
|
92
|
+
for (const [agent, count] of byAgent) {
|
|
93
|
+
console.log(`✓ synced ${count} skills into .${agent}/skills`)
|
|
94
|
+
}
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (command === 'add') {
|
|
99
|
+
const skillName = positional[0]
|
|
100
|
+
if (!skillName) {
|
|
101
|
+
console.error('Error: `wabot-skills add` requires a skill name')
|
|
102
|
+
process.exit(1)
|
|
103
|
+
}
|
|
104
|
+
const agents = parseAgents(flags.agents)
|
|
105
|
+
const result = await installSkillGlobally(skillName, agents, flags.home || undefined)
|
|
106
|
+
for (const item of result.installations) {
|
|
107
|
+
console.log(`✓ installed ${result.skill} -> ${item.installDir}`)
|
|
108
|
+
}
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.error(`Error: unknown command "${command}"`)
|
|
113
|
+
usage()
|
|
114
|
+
process.exit(1)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main().catch((error) => {
|
|
118
|
+
console.error('Error:', error.message)
|
|
119
|
+
process.exit(1)
|
|
120
|
+
})
|