plazbot-cli 0.3.6 → 0.4.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.
Files changed (117) hide show
  1. package/README.md +38 -2
  2. package/dist/commands/agent/export.js +25 -2
  3. package/dist/commands/auth/browser-login.js +121 -0
  4. package/dist/commands/auth/index.js +5 -1
  5. package/dist/commands/auth/login.js +1 -3
  6. package/dist/commands/auth/logout.js +4 -3
  7. package/dist/commands/auth/status.js +8 -5
  8. package/dist/commands/auth/workspace.js +73 -0
  9. package/dist/commands/whatsapp/connect-flow.js +137 -0
  10. package/dist/commands/whatsapp/connect.js +26 -160
  11. package/dist/commands/whatsapp/index.js +4 -0
  12. package/dist/commands/whatsapp/setup.js +242 -0
  13. package/dist/studio/components/App.js +1 -1
  14. package/dist/studio/runOneShot.js +2 -2
  15. package/dist/studio/runRepl.js +1 -1
  16. package/dist/utils/agent-errors.js +2 -2
  17. package/dist/utils/banner.js +10 -9
  18. package/dist/utils/credentials.js +31 -3
  19. package/dist/utils/open-browser.js +17 -0
  20. package/package.json +14 -6
  21. package/.claude/settings.local.json +0 -15
  22. package/CLAUDE.md +0 -121
  23. package/agent.config.json +0 -21
  24. package/dist/studio/components/AgentPanel.js +0 -35
  25. package/dist/studio/render/json.js +0 -16
  26. package/dist/studio/whatsapp/api.js +0 -63
  27. package/dist/studio/whatsapp/polling.js +0 -77
  28. package/dist/studio/whatsapp/types.js +0 -31
  29. package/src/cli.ts +0 -57
  30. package/src/commands/agent/ai-config.ts +0 -164
  31. package/src/commands/agent/chat.ts +0 -225
  32. package/src/commands/agent/copy.ts +0 -46
  33. package/src/commands/agent/create.ts +0 -103
  34. package/src/commands/agent/delete.ts +0 -71
  35. package/src/commands/agent/enable-widget.ts +0 -67
  36. package/src/commands/agent/export.ts +0 -408
  37. package/src/commands/agent/files.ts +0 -171
  38. package/src/commands/agent/get.ts +0 -233
  39. package/src/commands/agent/index.ts +0 -55
  40. package/src/commands/agent/list.ts +0 -58
  41. package/src/commands/agent/monitor.ts +0 -375
  42. package/src/commands/agent/on-message.ts +0 -82
  43. package/src/commands/agent/set.ts +0 -149
  44. package/src/commands/agent/templates.ts +0 -892
  45. package/src/commands/agent/tools.ts +0 -168
  46. package/src/commands/agent/update.ts +0 -61
  47. package/src/commands/agent/validate.ts +0 -135
  48. package/src/commands/agent/wizard.ts +0 -756
  49. package/src/commands/auth/index.ts +0 -10
  50. package/src/commands/auth/login.ts +0 -72
  51. package/src/commands/auth/logout.ts +0 -28
  52. package/src/commands/auth/status.ts +0 -28
  53. package/src/commands/portal/add-agent.ts +0 -66
  54. package/src/commands/portal/add-link.ts +0 -47
  55. package/src/commands/portal/clear-links.ts +0 -33
  56. package/src/commands/portal/create.ts +0 -58
  57. package/src/commands/portal/delete.ts +0 -70
  58. package/src/commands/portal/get.ts +0 -77
  59. package/src/commands/portal/index.ts +0 -32
  60. package/src/commands/portal/list.ts +0 -79
  61. package/src/commands/portal/update.ts +0 -93
  62. package/src/commands/whatsapp/broadcast.ts +0 -110
  63. package/src/commands/whatsapp/channels.ts +0 -109
  64. package/src/commands/whatsapp/chat.ts +0 -85
  65. package/src/commands/whatsapp/connect.ts +0 -220
  66. package/src/commands/whatsapp/delete-webhook.ts +0 -43
  67. package/src/commands/whatsapp/index.ts +0 -37
  68. package/src/commands/whatsapp/register-webhook.ts +0 -47
  69. package/src/commands/whatsapp/send-template.ts +0 -94
  70. package/src/commands/whatsapp/send.ts +0 -55
  71. package/src/commands/whatsapp/widget.ts +0 -75
  72. package/src/commands/workers/deploy.ts +0 -156
  73. package/src/commands/workers/index.ts +0 -30
  74. package/src/commands/workers/list.ts +0 -105
  75. package/src/commands/workers/logs.ts +0 -99
  76. package/src/commands/workers/remove.ts +0 -103
  77. package/src/commands/workers/secret.ts +0 -191
  78. package/src/commands/workers/test.ts +0 -145
  79. package/src/schemas/agent.config.schema.json +0 -569
  80. package/src/studio/api/sseClient.ts +0 -91
  81. package/src/studio/api/studioApi.ts +0 -27
  82. package/src/studio/api/types.ts +0 -96
  83. package/src/studio/components/App.tsx +0 -274
  84. package/src/studio/components/ChatLog.tsx +0 -121
  85. package/src/studio/components/ConnectCard.tsx +0 -171
  86. package/src/studio/components/Footer.tsx +0 -38
  87. package/src/studio/components/Header.tsx +0 -39
  88. package/src/studio/components/Input.tsx +0 -176
  89. package/src/studio/components/Message.tsx +0 -87
  90. package/src/studio/components/Suggestions.tsx +0 -26
  91. package/src/studio/components/ToolCall.tsx +0 -58
  92. package/src/studio/connect/api.ts +0 -98
  93. package/src/studio/connect/polling.ts +0 -94
  94. package/src/studio/connect/types.ts +0 -141
  95. package/src/studio/index.ts +0 -58
  96. package/src/studio/render/markdown.ts +0 -93
  97. package/src/studio/render/steps.ts +0 -57
  98. package/src/studio/runOneShot.ts +0 -114
  99. package/src/studio/runRepl.tsx +0 -82
  100. package/src/studio/slash/handlers.ts +0 -226
  101. package/src/studio/slash/parser.ts +0 -41
  102. package/src/studio/slash/registry.ts +0 -54
  103. package/src/studio/state/store.ts +0 -279
  104. package/src/types/agent.ts +0 -63
  105. package/src/types/auth.ts +0 -9
  106. package/src/types/common.ts +0 -10
  107. package/src/types/message.ts +0 -34
  108. package/src/types/portal.ts +0 -56
  109. package/src/types/workers.ts +0 -86
  110. package/src/utils/agent-errors.ts +0 -67
  111. package/src/utils/api.ts +0 -35
  112. package/src/utils/banner.ts +0 -99
  113. package/src/utils/credentials.ts +0 -38
  114. package/src/utils/help.ts +0 -51
  115. package/src/utils/logger.ts +0 -40
  116. package/src/utils/ui.ts +0 -109
  117. package/tsconfig.json +0 -18
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "plazbot-cli",
3
- "version": "0.3.6",
4
- "description": "CLI para Plazbot SDK",
3
+ "version": "0.4.0",
4
+ "description": "CLI oficial de Plazbot: WhatsApp for Developers, agentes IA y workers desde tu terminal",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
7
7
  "bin": {
8
8
  "plazbot": "dist/cli.js"
9
9
  },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
10
14
  "scripts": {
11
15
  "build": "tsc && mkdir -p dist/schemas && cp src/schemas/*.json dist/schemas/ && chmod +x dist/cli.js",
12
16
  "start": "node dist/cli.js",
@@ -23,12 +27,15 @@
23
27
  },
24
28
  "repository": {
25
29
  "type": "git",
26
- "url": "git+https://github.com/tu-usuario/plazbot-cli.git"
30
+ "url": "git+https://github.com/plazbot/Plazbot-CLI-v2.0.git"
27
31
  },
28
32
  "keywords": [
29
33
  "plazbot",
30
34
  "cli",
31
- "sdk"
35
+ "sdk",
36
+ "whatsapp",
37
+ "whatsapp-api",
38
+ "ai-agents"
32
39
  ],
33
40
  "author": "Kristian Garcia <kristian@plazbot.com>",
34
41
  "license": "MIT",
@@ -52,7 +59,7 @@
52
59
  "marked": "^12.0.2",
53
60
  "marked-terminal": "^7.2.1",
54
61
  "ora": "^8.0.1",
55
- "plazbot": "^2.1.4",
62
+ "plazbot": "^2.2.0",
56
63
  "react": "^18.3.1",
57
64
  "zustand": "^4.5.4"
58
65
  },
@@ -64,5 +71,6 @@
64
71
  },
65
72
  "engines": {
66
73
  "node": ">=18.17.0"
67
- }
74
+ },
75
+ "homepage": "https://developers.plazbot.com/cli"
68
76
  }
@@ -1,15 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(tree:*)",
5
- "Bash(wc:*)",
6
- "Bash(git -C /Users/kristian/Source/plazbot-v2/Plazbot-CLI-v2.0 log --oneline -10)",
7
- "Bash(grep:*)",
8
- "Bash(npm install:*)",
9
- "Bash(npm run build:*)",
10
- "Bash(node /Users/kristian/Source/plazbot-v2/Plazbot-CLI-v2.0/dist/cli.js:*)",
11
- "Bash(npm ls:*)",
12
- "Bash(python3:*)"
13
- ]
14
- }
15
- }
package/CLAUDE.md DELETED
@@ -1,121 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Descripción del Proyecto
6
-
7
- Plazbot CLI v2.0 es una interfaz de línea de comandos oficial para la plataforma Plazbot. Permite gestionar agentes de IA, portales web y comunicaciones vía WhatsApp desde la terminal.
8
-
9
- - **Lenguaje**: TypeScript 5.0+
10
- - **Runtime**: Node.js >=18.17.0 (ESM)
11
- - **Framework CLI**: Commander.js
12
- - **TUI**: Ink v5 + React 18 + zustand (solo para `plazbot studio`)
13
-
14
- ## Comandos de Desarrollo
15
-
16
- ```bash
17
- # Compilar TypeScript
18
- npm run build
19
-
20
- # Modo watch (compilación continua)
21
- npm run dev
22
-
23
- # Ejecutar CLI localmente
24
- npm start
25
- # o directamente:
26
- node dist/cli.js
27
-
28
- # Versionado
29
- npm run version:patch # Incrementar patch
30
- npm run version:minor # Incrementar minor
31
- npm run version:major # Incrementar major
32
-
33
- # SDK local vs npm
34
- npm run prepare:dev # Usar SDK local (desarrollo)
35
- npm run prepare:prod # Usar SDK de npm
36
-
37
- # Publicación
38
- npm run publish:beta # Publicar beta
39
- npm run publish:prod # Publicar producción
40
- ```
41
-
42
- ## Arquitectura
43
-
44
- ```
45
- src/
46
- ├── cli.ts # Entry point - registra todos los comandos
47
- ├── commands/ # Comandos organizados por dominio
48
- │ ├── agent/ # CRUD + chat interactivo de agentes
49
- │ ├── auth/ # init (login) y logout
50
- │ ├── portal/ # CRUD + gestión de enlaces
51
- │ ├── whatsapp/ # Mensajes y webhooks
52
- │ └── workers/ # Tools, syncs, schedules, webhooks
53
- ├── studio/ # REPL interactivo (Ink + SSE)
54
- │ ├── index.ts # studioCommand + subcomando ask
55
- │ ├── runRepl.tsx # Bootstrap Ink render(<App/>)
56
- │ ├── runOneShot.ts # Modo no interactivo (stdout)
57
- │ ├── api/ # types, studioApi, sseClient (fetch + ReadableStream)
58
- │ ├── state/store.ts # zustand: messages, steps, agentConfig, usage
59
- │ ├── slash/ # parser, registry, handlers (/help, /clear, /agents…)
60
- │ ├── render/ # markdown (marked-terminal), steps, json
61
- │ └── components/ # App, Header, ChatLog, Message, ToolCall, Input…
62
- ├── types/ # Interfaces TypeScript
63
- └── utils/
64
- ├── logger.ts # Logging formateado (info, success, warning, error)
65
- ├── api.ts # axios con Authorization Bearer + x-workspace-id
66
- └── credentials.ts # Persistencia en ~/.plazbot/config.json
67
- ```
68
-
69
- ### Studio (REPL interactivo)
70
-
71
- `plazbot studio` abre una TUI estilo Claude Code que consume el endpoint SSE
72
- `POST /api/agent/studio`. Permite crear, cargar, diagnosticar y guardar agentes
73
- en conversación natural. Las tool_calls se renderizan como cards con spinner;
74
- el `agentConfig` aparece en un panel lateral con tabs preview/json/diagnose.
75
-
76
- - `plazbot studio` → REPL completo (Ink)
77
- - `plazbot studio -m "..."` o `plazbot studio ask "..."` → one-shot a stdout
78
- - `plazbot studio ask "..." --json` → NDJSON crudo de los chunks SSE
79
-
80
- Atajos: `Tab` panel · `Esc` cancelar stream · `Ctrl+C` salir.
81
-
82
- ### Flujo de Comandos
83
-
84
- 1. `cli.ts` usa Commander.js para registrar grupos de comandos
85
- 2. Cada comando carga credenciales de `~/.plazbot/config.json`
86
- 3. Instancia el SDK (`plazbot`) con las credenciales
87
- 4. Ejecuta la operación contra el backend de Plazbot
88
- 5. Formatea la respuesta usando `logger.ts`
89
-
90
- ### SDK de Plazbot
91
-
92
- El CLI depende del paquete `plazbot` que expone tres clases principales:
93
- - **Agent** - Operaciones con agentes de IA
94
- - **Portal** - Gestión de portales web
95
- - **Message** - Envío de mensajes WhatsApp
96
-
97
- ### Credenciales
98
-
99
- Se almacenan en `~/.plazbot/config.json`:
100
- ```json
101
- {
102
- "email": "string (opcional)",
103
- "apiKey": "string (JWT)",
104
- "workspace": "string",
105
- "zone": "LA | EU",
106
- "userId": "string (opcional, usado por studio como x-user-id)"
107
- }
108
- ```
109
-
110
- El `apiKey` es un JWT válido. El CLI lo envía como `Authorization: Bearer <jwt>`
111
- y mantiene transitoriamente `x-api-key` para endpoints legacy.
112
-
113
- ### Flag --dev
114
-
115
- Todos los comandos soportan `--dev` para apuntar al backend local (`http://localhost:5090`).
116
-
117
- ## Convenciones
118
-
119
- - Cada grupo de comandos tiene un `index.ts` que exporta el comando padre con subcomandos
120
- - Los tipos de opciones de comando se definen en `src/types/`
121
- - El logger proporciona formato consistente: `logger.info()`, `logger.success()`, `logger.error()`
package/agent.config.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "name": "agente-1",
3
- "description": "Asistente que ayuda a resolver preguntas de la empresa",
4
- "prompt": "Vas a ayudar a las personas a poder resolver sus preguntas de la empresa como informacion de contacto, horarios de atencion, etc. Nuestro horario de atencion es de 9:00 a 18:00 y trabajamos en Peru, España y Colombia.",
5
- "zone": "LA",
6
- "buffer": 5,
7
- "color": "blue",
8
- "question": "Como te podemos ayudar?",
9
- "timezone": "America/Lima",
10
- "showInChat": false,
11
- "examples": [
12
- { "value": "quiero informacion de contacto", "color": "green" },
13
- { "value": "horarios de atencion", "color": "orange" }
14
- ],
15
- "person": {
16
- "name": "Leandro",
17
- "role": "Asistente de Atencion al Cliente",
18
- "speaksInFirstPerson": true,
19
- "isHuman": false
20
- }
21
- }
@@ -1,35 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
3
- import { useStudioStore } from '../state/store.js';
4
- import { JsonView, safeStringify } from '../render/json.js';
5
- export function AgentPanel() {
6
- const open = useStudioStore((s) => s.panelOpen);
7
- const tab = useStudioStore((s) => s.panelTab);
8
- const cfg = useStudioStore((s) => s.agentConfig);
9
- if (!open)
10
- return null;
11
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, flexGrow: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "green", children: "Agent panel" }) }), _jsxs(Box, { children: [_jsx(Tab, { active: tab === 'preview', children: "preview" }), _jsx(Text, { dimColor: true, children: " \u00B7 " }), _jsx(Tab, { active: tab === 'json', children: "json" }), _jsx(Text, { dimColor: true, children: " \u00B7 " }), _jsx(Tab, { active: tab === 'diagnose', children: "diagnose" })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: renderTab(tab, cfg) })] }));
12
- }
13
- function Tab({ active, children }) {
14
- return active ? _jsx(Text, { color: "cyan", bold: true, children: children }) : _jsx(Text, { dimColor: true, children: children });
15
- }
16
- function renderTab(tab, cfg) {
17
- if (!cfg) {
18
- return _jsx(Text, { dimColor: true, children: "No agent loaded yet." });
19
- }
20
- if (tab === 'json') {
21
- return _jsx(JsonView, { value: cfg });
22
- }
23
- if (tab === 'diagnose') {
24
- return _jsx(Text, { dimColor: true, children: "Run `/diagnose` to analyze the current agent." });
25
- }
26
- // preview: key agent fields
27
- const c = cfg;
28
- const name = c?.name ?? '(unnamed)';
29
- const description = c?.description ?? '';
30
- const model = c?.model ?? c?.modelId ?? '';
31
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Name: " }), _jsx(Text, { children: name })] }), model ? _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Model: " }), _jsx(Text, { children: model })] }) : null, description ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "Description:" }), _jsx(Text, { children: description })] })) : null, _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: truncate(safeStringify(c), 400) }) })] }));
32
- }
33
- function truncate(s, n) {
34
- return s.length > n ? s.slice(0, n) + '…' : s;
35
- }
@@ -1,16 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Box } from 'ink';
3
- import SyntaxHighlight from 'ink-syntax-highlight';
4
- export function JsonView({ value, maxHeight }) {
5
- const text = safeStringify(value);
6
- return (_jsx(Box, { flexDirection: "column", height: maxHeight, children: _jsx(SyntaxHighlight, { code: text, language: "json" }) }));
7
- }
8
- function safeStringify(v) {
9
- try {
10
- return JSON.stringify(v, null, 2);
11
- }
12
- catch {
13
- return String(v);
14
- }
15
- }
16
- export { safeStringify };
@@ -1,63 +0,0 @@
1
- import { getBaseUrl } from '../api/studioApi.js';
2
- function headers(opts) {
3
- const h = {
4
- 'Content-Type': 'application/json',
5
- Authorization: `Bearer ${opts.apiKey}`,
6
- 'x-workspace-id': opts.workspaceId,
7
- };
8
- if (opts.userId)
9
- h['x-user-id'] = opts.userId;
10
- return h;
11
- }
12
- /**
13
- * GET /api/workspace/{workspaceId} — the API returns an array of workspaces
14
- * (the front uses `[0]`). Returns the first element or null.
15
- */
16
- export async function getWorkspaceById(opts, signal) {
17
- const url = `${getBaseUrl(opts.zone, opts.dev)}/api/workspace/${encodeURIComponent(opts.workspaceId)}`;
18
- const res = await fetch(url, { method: 'GET', headers: headers(opts), signal });
19
- if (!res.ok) {
20
- throw new Error(`GET workspace ${res.status} ${res.statusText}`);
21
- }
22
- const json = (await res.json());
23
- if (!json)
24
- return null;
25
- if (Array.isArray(json))
26
- return json[0] ?? null;
27
- return json;
28
- }
29
- /**
30
- * POST /api/workspace/{workspaceId}/integrations/{integrationId}/activate
31
- * Body: { isActive: true, platformCode: "whatsapp" }
32
- */
33
- export async function activateIntegration(opts, integrationId, signal) {
34
- const url = `${getBaseUrl(opts.zone, opts.dev)}/api/workspace/${encodeURIComponent(opts.workspaceId)}/integrations/${encodeURIComponent(integrationId)}/activate`;
35
- const res = await fetch(url, {
36
- method: 'POST',
37
- headers: headers(opts),
38
- body: JSON.stringify({ isActive: true, platformCode: 'whatsapp' }),
39
- signal,
40
- });
41
- const text = await res.text();
42
- let parsed = {};
43
- if (text) {
44
- try {
45
- parsed = JSON.parse(text);
46
- }
47
- catch { /* not json */ }
48
- }
49
- if (!res.ok) {
50
- return { success: false, message: parsed.message || `HTTP ${res.status} ${res.statusText}` };
51
- }
52
- return parsed.success === false ? parsed : { success: true, ...parsed };
53
- }
54
- /** Adapter: derives the workspace fetch options from a StudioStreamOptions. */
55
- export function workspaceOptsFromStream(stream) {
56
- return {
57
- apiKey: stream.apiKey,
58
- workspaceId: stream.workspaceId,
59
- zone: stream.zone,
60
- dev: stream.dev,
61
- userId: stream.userId,
62
- };
63
- }
@@ -1,77 +0,0 @@
1
- import { activateIntegration, getWorkspaceById } from './api.js';
2
- import { findNewWhatsappIntegration, WA_POLL_INTERVAL_MS, WA_POLL_MAX_ATTEMPTS, } from './types.js';
3
- /**
4
- * Starts the polling loop. Returns a handle to cancel it. The loop:
5
- * 1. GETs the workspace every WA_POLL_INTERVAL_MS up to WA_POLL_MAX_ATTEMPTS.
6
- * 2. Looks for a whatsapp integration whose id isn't in `existingIntegrationIds`.
7
- * 3. When found, calls POST .../activate and reports the result.
8
- */
9
- export function startWhatsappPolling(opts, linkData, cb) {
10
- const knownIds = new Set(linkData.existingIntegrationIds ?? []);
11
- const controller = new AbortController();
12
- let attempts = 0;
13
- let busy = false;
14
- let stopped = false;
15
- let timer = null;
16
- const stop = () => {
17
- stopped = true;
18
- if (timer) {
19
- clearInterval(timer);
20
- timer = null;
21
- }
22
- controller.abort();
23
- };
24
- const tick = async () => {
25
- if (busy || stopped)
26
- return;
27
- busy = true;
28
- attempts++;
29
- cb.onAttempt(attempts);
30
- try {
31
- const ws = await getWorkspaceById(opts, controller.signal);
32
- const newIntegration = findNewWhatsappIntegration(ws?.integrations, knownIds);
33
- if (newIntegration?.id) {
34
- const number = newIntegration.cellphoneNumberFormat ||
35
- newIntegration.cellphoneNumber ||
36
- '';
37
- cb.onActivating(newIntegration.id, number);
38
- if (timer) {
39
- clearInterval(timer);
40
- timer = null;
41
- }
42
- const res = await activateIntegration(opts, newIntegration.id, controller.signal);
43
- if (res.success !== false) {
44
- cb.onConnected(number);
45
- }
46
- else {
47
- cb.onError(res.message || 'Could not activate the integration.');
48
- }
49
- stopped = true;
50
- return;
51
- }
52
- }
53
- catch (err) {
54
- if (err.name === 'AbortError')
55
- return;
56
- // Transient network errors: swallow and keep polling.
57
- }
58
- finally {
59
- busy = false;
60
- }
61
- if (attempts >= WA_POLL_MAX_ATTEMPTS) {
62
- if (timer) {
63
- clearInterval(timer);
64
- timer = null;
65
- }
66
- stopped = true;
67
- cb.onTimeout();
68
- }
69
- };
70
- timer = setInterval(() => { void tick(); }, WA_POLL_INTERVAL_MS);
71
- // Trigger the first attempt immediately so the user sees activity right away.
72
- void tick();
73
- return {
74
- cancel() { stop(); },
75
- get stopped() { return stopped; },
76
- };
77
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Types and helpers for the "connect WhatsApp from Agent Studio" flow.
3
- *
4
- * The backend tool `connect_whatsapp` emits a `tool_result` chunk with
5
- * `type: "whatsapp_link"`. When `data.shortUrl` is present we render an
6
- * inline card with the onboarding link and start polling the workspace
7
- * until the new integration appears. Baseline of "known" ids comes from
8
- * the server (`existingIntegrationIds`) to avoid race conditions.
9
- *
10
- * Mirror of /Plazbot-Front-v2.0/src/modules/agentStudio/whatsappConnect.ts
11
- */
12
- export const WA_POLL_INTERVAL_MS = 5000;
13
- export const WA_POLL_MAX_ATTEMPTS = 60; // 5 minutes
14
- /**
15
- * Returns a new whatsapp integration whose id is NOT in the baseline.
16
- * If multiple are new, picks the most recently created one.
17
- */
18
- export function findNewWhatsappIntegration(integrations, knownIds) {
19
- if (!integrations?.length)
20
- return null;
21
- const candidates = integrations.filter((i) => (i.type === 'whatsapp' || i.type === 'whatsapp_business') &&
22
- !!i.id &&
23
- !knownIds.has(i.id));
24
- if (!candidates.length)
25
- return null;
26
- return candidates.reduce((latest, current) => {
27
- const a = latest.creationDate ? new Date(latest.creationDate).getTime() : 0;
28
- const b = current.creationDate ? new Date(current.creationDate).getTime() : 0;
29
- return b > a ? current : latest;
30
- });
31
- }
package/src/cli.ts DELETED
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program } from 'commander';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname, join } from 'node:path';
6
- import { portalCommands } from './commands/portal/index.js';
7
- import { authCommands } from './commands/auth/index.js';
8
- import { agentCommands } from './commands/agent/index.js';
9
- import { whatsappCommands } from './commands/whatsapp/index.js';
10
- import { workersCommands } from './commands/workers/index.js';
11
- import { studioCommand } from './studio/index.js';
12
- import { showBanner } from './utils/banner.js';
13
-
14
- // Guard de runtime: Plazbot CLI v0.3+ requiere Node 18.17+
15
- const [major, minor] = process.versions.node.split('.').map(Number);
16
- if (major < 18 || (major === 18 && minor < 17)) {
17
- console.error(`Plazbot CLI v0.3+ requires Node.js >=18.17.0. Current version: ${process.versions.node}`);
18
- process.exit(1);
19
- }
20
-
21
- // Leer version desde package.json
22
- const __dirname = dirname(fileURLToPath(import.meta.url));
23
- const pkgPath = join(__dirname, '..', 'package.json');
24
- const { version } = JSON.parse(readFileSync(pkgPath, 'utf-8'));
25
-
26
- // Configuracion basica del CLI
27
- program
28
- .name('plazbot')
29
- .description('Official Plazbot CLI - AI agents for WhatsApp, portals and developers')
30
- .version(version);
31
-
32
- // Registrar todos los comandos de autenticacion
33
- authCommands.forEach(cmd => program.addCommand(cmd));
34
-
35
- // Registrar todos los comandos de agente
36
- program.addCommand(agentCommands);
37
-
38
- // Registrar todos los comandos de portal
39
- program.addCommand(portalCommands);
40
-
41
- // Registrar todos los comandos de WhatsApp
42
- program.addCommand(whatsappCommands);
43
-
44
- // Registrar todos los comandos de Workers
45
- program.addCommand(workersCommands);
46
-
47
- // Registrar el comando Studio (REPL interactivo)
48
- program.addCommand(studioCommand);
49
-
50
- // Si no se pasan argumentos, mostrar banner
51
- if (process.argv.length <= 2) {
52
- showBanner().then(() => {
53
- program.outputHelp();
54
- });
55
- } else {
56
- program.parse(process.argv);
57
- }
@@ -1,164 +0,0 @@
1
- import { Command } from 'commander';
2
- import { Agent } from 'plazbot';
3
- import inquirer from 'inquirer';
4
- import { getStoredCredentials } from '../../utils/credentials.js';
5
- import { logger } from '../../utils/logger.js';
6
- import { addExamples } from '../../utils/help.js';
7
- import { describeAgentLoadError } from '../../utils/agent-errors.js';
8
- import { createSpinner, theme, section, kvPair } from '../../utils/ui.js';
9
- import { AgentCommandOptions } from '../../types/agent.js';
10
-
11
- // Catalogo de modelos sincronizado con el front (AIModelSection.tsx).
12
- // Si se actualiza el dropdown del front, actualizar aqui tambien.
13
- const MODELS: Record<string, string[]> = {
14
- openai: [
15
- // GPT-5.4 (flagship actual)
16
- 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.4-nano',
17
- // GPT-5.2
18
- 'gpt-5.2',
19
- // GPT-5.1
20
- 'gpt-5.1', 'gpt-5.1-codex', 'gpt-5.1-codex-mini',
21
- // GPT-5
22
- 'gpt-5', 'gpt-5-mini', 'gpt-5-nano',
23
- // GPT-4.1
24
- 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano',
25
- // GPT-4o
26
- 'gpt-4o', 'gpt-4o-mini',
27
- // Razonamiento (o-series)
28
- 'o4-mini', 'o3', 'o3-mini', 'o1-2024-12-17',
29
- // Legacy
30
- 'gpt-4-turbo', 'gpt-3.5-turbo',
31
- ],
32
- claude: [
33
- // Mythos-class (flagship)
34
- 'claude-fable-5',
35
- // Claude 4.6
36
- 'claude-opus-4-6', 'claude-sonnet-4-6',
37
- // Claude 4.5
38
- 'claude-opus-4-5-20251101', 'claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001',
39
- // Claude 4.x
40
- 'claude-opus-4-1-20250805', 'claude-opus-4-20250514', 'claude-sonnet-4-20250514',
41
- ],
42
- gemini: [
43
- // Gemini 3.1 (flagship actual)
44
- 'gemini-3.1-pro-preview', 'gemini-3.1-flash-lite-preview',
45
- // Gemini 2.5
46
- 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite',
47
- // Gemini 2.0
48
- 'gemini-2.0-flash',
49
- ],
50
- };
51
-
52
- const DEFAULT_MODEL: Record<string, string> = {
53
- openai: 'gpt-4o',
54
- claude: 'claude-sonnet-4-6',
55
- gemini: 'gemini-2.5-pro',
56
- };
57
-
58
- export const aiConfigCommand = new Command('ai-config')
59
- .description('Configure the agent AI provider')
60
- .argument('<agentId>', 'Agent ID')
61
- .option('--dev', 'Use development environment', false)
62
- .action(async (agentId: string, options: AgentCommandOptions) => {
63
- try {
64
- const credentials = await getStoredCredentials();
65
- const agent = new Agent({
66
- workspaceId: credentials.workspace,
67
- apiKey: credentials.apiKey,
68
- zone: credentials.zone,
69
- ...(options.dev && { customUrl: "http://localhost:5090" })
70
- });
71
-
72
- const spinner = createSpinner('Loading agent...');
73
- spinner.start();
74
- let agentData: any;
75
- try {
76
- const _res: any = await agent.getAgentById({ id: agentId });
77
- agentData = _res.agent || _res.data || _res;
78
- spinner.stop();
79
- } catch (loadErr) {
80
- spinner.stop();
81
- logger.error(describeAgentLoadError(loadErr, agentId, credentials, { dev: options.dev }));
82
- process.exit(1);
83
- }
84
-
85
- console.log(section('AI Configuration - ' + (agentData.name || agentId)));
86
-
87
- const currentProviders = agentData.aiProviders || [];
88
- if (currentProviders.length > 0 && agentData.customAIConfig) {
89
- console.log(theme.bold('\n Current configuration:'));
90
- currentProviders.forEach((p: any) => {
91
- console.log(kvPair(' Provider', p.provider));
92
- console.log(kvPair(' Model', p.model));
93
- console.log(kvPair(' Temperature', String(p.temperature)));
94
- console.log(kvPair(' Max Tokens', String(p.maxTokens)));
95
- console.log(kvPair(' Default', p.isDefault ? 'Yes' : 'No'));
96
- });
97
- } else {
98
- console.log(theme.muted('\n Using default AI configuration (Plazbot)'));
99
- }
100
-
101
- const { action } = await (inquirer as any).prompt([{
102
- type: 'list',
103
- name: 'action',
104
- message: 'What would you like to do?',
105
- choices: [
106
- { name: 'Configure new provider', value: 'set' },
107
- { name: 'Use default configuration', value: 'reset' },
108
- { name: 'Exit', value: 'exit' },
109
- ],
110
- }]);
111
-
112
- if (action === 'exit') return;
113
-
114
- if (action === 'reset') {
115
- const { id, _id, ...resetConfig } = { ...agentData, customAIConfig: false, aiProviders: [] };
116
- const resetSpinner = createSpinner('Resetting configuration...');
117
- resetSpinner.start();
118
- await agent.updateAgent(agentId, resetConfig);
119
- resetSpinner.succeed('Using default configuration');
120
- return;
121
- }
122
-
123
- // Configurar nuevo proveedor
124
- const ai = await (inquirer as any).prompt([
125
- { type: 'list', name: 'provider', message: 'Provider:', choices: ['openai', 'claude', 'gemini'] },
126
- ]);
127
-
128
- const models = MODELS[ai.provider] || MODELS.openai;
129
-
130
- const config = await (inquirer as any).prompt([
131
- { type: 'list', name: 'model', message: 'Model:', choices: models, default: DEFAULT_MODEL[ai.provider] },
132
- { type: 'password', name: 'apiToken', message: 'API Token:', mask: '*', validate: (v: string) => v.length > 0 || 'Required' },
133
- { type: 'number', name: 'temperature', message: 'Temperature (0-2):', default: 0.7 },
134
- { type: 'number', name: 'maxTokens', message: 'Max tokens (1024-16384):', default: 4096 },
135
- ]);
136
-
137
- const { id: _uid, _id: _oid, ...updatedConfig } = {
138
- ...agentData,
139
- customAIConfig: true,
140
- aiProviders: [{
141
- provider: ai.provider,
142
- model: config.model,
143
- apiToken: config.apiToken,
144
- temperature: config.temperature,
145
- maxTokens: config.maxTokens,
146
- isDefault: true,
147
- }],
148
- };
149
- const updateSpinner = createSpinner('Saving configuration...');
150
- updateSpinner.start();
151
- await agent.updateAgent(agentId, updatedConfig);
152
- updateSpinner.succeed(`Provider configured: ${ai.provider} / ${config.model}`);
153
-
154
- } catch (error) {
155
- const message = error instanceof Error ? error.message : 'Unknown error';
156
- logger.error(message);
157
- process.exit(1);
158
- }
159
- });
160
-
161
- addExamples(aiConfigCommand, [
162
- { description: 'Pick provider/model/API key for the agent interactively',
163
- command: 'plazbot agent ai-config agt_AbcDef123' },
164
- ]);