gufi-cli 0.1.21 → 0.1.23
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/CLAUDE.md +97 -182
- package/dist/mcp.js +296 -245
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -1,213 +1,128 @@
|
|
|
1
|
-
# Gufi CLI
|
|
1
|
+
# Gufi CLI & MCP Server
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Para documentación de USO del CLI**, ve a `docs/mcp/`
|
|
4
4
|
>
|
|
5
|
-
> Este archivo es
|
|
6
|
-
> - [docs/claude/06-cli.md](../../docs/claude/06-cli.md) - Comandos del CLI
|
|
7
|
-
> - [docs/claude/00-index.md](../../docs/claude/00-index.md) - Overview de Gufi
|
|
8
|
-
> - [docs/claude/05-automations.md](../../docs/claude/05-automations.md) - Automations
|
|
9
|
-
> - [docs/claude/04-views.md](../../docs/claude/04-views.md) - Sistema de vistas
|
|
5
|
+
> Este archivo es para desarrollo INTERNO del CLI (código en `tools/cli/src/`)
|
|
10
6
|
|
|
11
|
-
##
|
|
7
|
+
## Estructura del CLI
|
|
12
8
|
|
|
13
|
-
```bash
|
|
14
|
-
# Contexto, diagnóstico y documentación
|
|
15
|
-
gufi context # Genera contexto para Claude
|
|
16
|
-
gufi doctor # Diagnóstico del sistema
|
|
17
|
-
gufi docs # Ver topics disponibles
|
|
18
|
-
gufi docs fields # Documentación de tipos de campo
|
|
19
|
-
gufi docs errors # Errores comunes y soluciones
|
|
20
|
-
gufi docs --search "currency" # Buscar en toda la documentación
|
|
21
|
-
|
|
22
|
-
# Entornos
|
|
23
|
-
gufi config # Ver entornos
|
|
24
|
-
gufi config:local # Cambiar a localhost
|
|
25
|
-
gufi config:prod # Cambiar a producción
|
|
26
|
-
|
|
27
|
-
# Módulos
|
|
28
|
-
gufi modules 146 # Ver módulos
|
|
29
|
-
gufi module 360 --edit # Editar con $EDITOR
|
|
30
|
-
|
|
31
|
-
# Automations
|
|
32
|
-
gufi automations # Ver scripts
|
|
33
|
-
gufi automation 15 --edit # Editar script
|
|
34
|
-
gufi entity:automations 4136 # Ver triggers
|
|
35
|
-
|
|
36
|
-
# Vistas
|
|
37
|
-
gufi view:pull 13 # Descargar
|
|
38
|
-
gufi view:push # Subir cambios
|
|
39
|
-
gufi view:watch # Auto-sync
|
|
40
|
-
|
|
41
|
-
# Datos
|
|
42
|
-
gufi rows m360_t16192 # Listar registros
|
|
43
|
-
gufi row:create table --data '{...}'
|
|
44
9
|
```
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
10
|
+
tools/cli/
|
|
11
|
+
├── src/
|
|
12
|
+
│ ├── index.ts # Entry point CLI
|
|
13
|
+
│ ├── mcp.ts # MCP Server (44 tools)
|
|
14
|
+
│ ├── commands/ # Comandos CLI
|
|
15
|
+
│ │ ├── context.ts # gufi context
|
|
16
|
+
│ │ ├── pull.ts # gufi view:pull
|
|
17
|
+
│ │ ├── push.ts # gufi view:push
|
|
18
|
+
│ │ ├── watch.ts # gufi view:watch
|
|
19
|
+
│ │ └── ...
|
|
20
|
+
│ └── lib/
|
|
21
|
+
│ ├── api.ts # Cliente API
|
|
22
|
+
│ ├── config.ts # Gestión de config (~/.gufi/)
|
|
23
|
+
│ └── sync.ts # Sincronización de vistas
|
|
24
|
+
├── package.json
|
|
25
|
+
└── tsconfig.json
|
|
61
26
|
```
|
|
62
27
|
|
|
63
|
-
|
|
28
|
+
## MCP Server
|
|
64
29
|
|
|
65
|
-
|
|
30
|
+
El servidor MCP está en `src/mcp.ts` y expone 44 tools para que Claude interactúe con Gufi.
|
|
66
31
|
|
|
67
|
-
|
|
32
|
+
### Tools principales (nuevos)
|
|
68
33
|
|
|
69
|
-
|
|
34
|
+
- **`gufi_start`** - Entrypoint inteligente que auto-detecta contexto:
|
|
35
|
+
- Si está en gogufi/: Detecta codebase, apunta a docs/claude/
|
|
36
|
+
- Si está en carpeta de vista: Devuelve contexto de la vista
|
|
37
|
+
- Si no detecta nada: Lista packages del usuario
|
|
70
38
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
39
|
+
- **`gufi_context`** - Ahora devuelve:
|
|
40
|
+
- `summary`: Resumen ejecutivo
|
|
41
|
+
- `next_actions`: Pasos sugeridos
|
|
42
|
+
- Auto-detección de codebase y vistas locales
|
|
74
43
|
|
|
75
|
-
###
|
|
76
|
-
|
|
77
|
-
**Contexto e Info (EMPEZAR AQUÍ):**
|
|
78
|
-
- `gufi_context` - **USAR PRIMERO** - Genera contexto inteligente del proyecto
|
|
79
|
-
- `gufi_whoami` - Usuario y entorno actual
|
|
80
|
-
- `gufi_schema` - Estructura de tablas/campos
|
|
81
|
-
- `gufi_docs` - **LEER DOCUMENTACIÓN** - Topics: fields, views, automations, errors, examples
|
|
82
|
-
|
|
83
|
-
**Companies:**
|
|
84
|
-
- `gufi_companies` - Listar companies
|
|
85
|
-
- `gufi_company_create` - Crear company
|
|
86
|
-
|
|
87
|
-
**Módulos (estructura de datos):**
|
|
88
|
-
- `gufi_modules` - Listar módulos de una company
|
|
89
|
-
- `gufi_module` - Ver JSON completo de un módulo
|
|
90
|
-
- `gufi_module_update` - **Modificar módulo** (añadir campos, entidades)
|
|
91
|
-
- `gufi_module_create` - Crear módulo nuevo
|
|
92
|
-
|
|
93
|
-
**Automations (lógica de negocio):**
|
|
94
|
-
- `gufi_automations` - Listar scripts
|
|
95
|
-
- `gufi_automation` - Ver código JS de un script
|
|
96
|
-
- `gufi_automation_create` - **Crear/actualizar script**
|
|
97
|
-
- `gufi_entity_automations` - Ver triggers de una entidad
|
|
98
|
-
- `gufi_entity_automations_update` - **Configurar triggers**
|
|
99
|
-
- `gufi_automations_executions` - Ver historial de ejecuciones
|
|
100
|
-
|
|
101
|
-
**Datos (CRUD):**
|
|
102
|
-
- `gufi_rows` - Listar registros de una tabla
|
|
103
|
-
- `gufi_row` - Ver un registro
|
|
104
|
-
- `gufi_row_create` - Crear registro
|
|
105
|
-
- `gufi_row_update` - Actualizar registro
|
|
106
|
-
- `gufi_row_delete` - Eliminar registro
|
|
107
|
-
|
|
108
|
-
**Environment Variables:**
|
|
109
|
-
- `gufi_env` - Listar variables
|
|
110
|
-
- `gufi_env_set` - Crear/actualizar variable
|
|
111
|
-
- `gufi_env_delete` - Eliminar variable
|
|
112
|
-
|
|
113
|
-
**Vistas (React/TSX):**
|
|
114
|
-
- `gufi_view_files` - Ver archivos de una vista
|
|
115
|
-
- `gufi_view_file_update` - **Modificar archivo de vista**
|
|
116
|
-
- `gufi_view_files_update` - Modificar múltiples archivos
|
|
117
|
-
|
|
118
|
-
**Packages (Marketplace):**
|
|
119
|
-
- `gufi_packages` - Listar packages
|
|
120
|
-
- `gufi_package` - Ver detalles
|
|
121
|
-
- `gufi_package_create` - Crear package
|
|
122
|
-
- `gufi_package_publish` - Publicar
|
|
123
|
-
- `gufi_package_sync` - Sincronizar versión
|
|
124
|
-
- `gufi_package_add_module` / `gufi_package_remove_module`
|
|
125
|
-
- `gufi_package_add_view` / `gufi_package_remove_view`
|
|
126
|
-
|
|
127
|
-
**Package Migrations:**
|
|
128
|
-
- `gufi_package_migrations` - Listar migraciones
|
|
129
|
-
- `gufi_package_migration_create` - Crear migración SQL
|
|
130
|
-
- `gufi_package_entities` - Listar entidades para target_entity
|
|
131
|
-
|
|
132
|
-
### Ejemplos de uso con Claude
|
|
44
|
+
### Añadir un nuevo tool MCP
|
|
133
45
|
|
|
46
|
+
1. **Definir tool** en array `TOOLS` (~línea 200):
|
|
47
|
+
```typescript
|
|
48
|
+
{
|
|
49
|
+
name: "gufi_nuevo_tool",
|
|
50
|
+
description: getDesc("gufi_nuevo_tool"),
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
param1: { type: "string", description: "..." },
|
|
55
|
+
},
|
|
56
|
+
required: ["param1"],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
134
59
|
```
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
[usa gufi_automation_create]
|
|
143
|
-
[usa gufi_entity_automations_update para configurar trigger]
|
|
144
|
-
"Listo, creé el automation 'email_pedido_enviado' con trigger on_update"
|
|
145
|
-
|
|
146
|
-
Usuario: "¿Cuántos clientes hay en la empresa 116?"
|
|
147
|
-
Claude: [usa gufi_schema para encontrar tabla de clientes]
|
|
148
|
-
[usa gufi_rows para consultar]
|
|
149
|
-
"Hay 234 clientes en la tabla m360_t4136"
|
|
60
|
+
|
|
61
|
+
2. **Añadir handler** en `toolHandlers` (~línea 870):
|
|
62
|
+
```typescript
|
|
63
|
+
async gufi_nuevo_tool(params: { param1: string }) {
|
|
64
|
+
// Implementación
|
|
65
|
+
return { result: "..." };
|
|
66
|
+
},
|
|
150
67
|
```
|
|
151
68
|
|
|
152
|
-
|
|
69
|
+
3. **Añadir descripción** en `docs/mcp/tool-descriptions.json`:
|
|
70
|
+
```json
|
|
71
|
+
"gufi_nuevo_tool": {
|
|
72
|
+
"description": "Descripción clara del tool..."
|
|
73
|
+
}
|
|
74
|
+
```
|
|
153
75
|
|
|
154
|
-
|
|
76
|
+
### Funciones helper importantes
|
|
155
77
|
|
|
156
|
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
78
|
+
- `detectIfInGufiCodebase()` - Detecta si está en el repo gogufi
|
|
79
|
+
- `loadViewMetaFromCwd()` - Carga `.gufi-view.json` del directorio actual
|
|
80
|
+
- `generateViewContextMcp()` - Genera contexto de una vista
|
|
81
|
+
- `generatePackageContextMcp()` - Genera contexto de un package
|
|
82
|
+
- `apiRequest()` - Peticiones a API con auth
|
|
83
|
+
- `developerRequest()` - Peticiones a /api/developer/
|
|
162
84
|
|
|
163
|
-
|
|
164
|
-
- multiselect: `["value1", "value2"]`
|
|
165
|
-
- users: `[16, 23]`
|
|
85
|
+
## CLI Commands
|
|
166
86
|
|
|
167
|
-
|
|
168
|
-
- currency: `{ "currency": "EUR", "amount": 150.00 }`
|
|
169
|
-
- phone: `{ "prefix": "+34", "number": "612345678" }`
|
|
170
|
-
- location: `{ "street": "Mayor", "number": "15", "city": "Madrid", "lat": 40.41 }`
|
|
171
|
-
- file: `[{ "url": "company_130/doc.pdf", "name": "doc.pdf" }]`
|
|
87
|
+
Cada comando está en `src/commands/`. Patrón común:
|
|
172
88
|
|
|
173
|
-
En vistas usa `gufi.CB.*` para formatear correctamente:
|
|
174
89
|
```typescript
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
90
|
+
export async function miComando(args: string[], flags: Flags) {
|
|
91
|
+
// 1. Parsear argumentos
|
|
92
|
+
// 2. Validar
|
|
93
|
+
// 3. Hacer petición API
|
|
94
|
+
// 4. Mostrar resultado
|
|
95
|
+
}
|
|
179
96
|
```
|
|
180
97
|
|
|
181
|
-
|
|
98
|
+
## Config (~/.gufi/)
|
|
182
99
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
100
|
+
```
|
|
101
|
+
~/.gufi/
|
|
102
|
+
├── config.json # Credenciales y entornos
|
|
103
|
+
└── gufi-dev/ # Vistas descargadas
|
|
104
|
+
└── view_13/
|
|
105
|
+
├── .gufi-view.json # Metadata de sync
|
|
106
|
+
├── index.tsx
|
|
107
|
+
└── ...
|
|
108
|
+
```
|
|
186
109
|
|
|
187
|
-
##
|
|
110
|
+
## Testing
|
|
188
111
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
| **Leer documentación** | `gufi docs fields` |
|
|
194
|
-
| **Buscar en docs** | `gufi docs --search "currency"` |
|
|
195
|
-
| Ver companies | `gufi companies` |
|
|
196
|
-
| Ver módulos | `gufi modules 146` |
|
|
197
|
-
| Editar módulo | `gufi module 360 --edit` |
|
|
198
|
-
| Ver automations | `gufi automations` |
|
|
199
|
-
| Desarrollar vista | `gufi view:pull 13` → `gufi view:push` |
|
|
112
|
+
```bash
|
|
113
|
+
cd tools/cli
|
|
114
|
+
npm test
|
|
115
|
+
```
|
|
200
116
|
|
|
201
|
-
##
|
|
117
|
+
## Build
|
|
202
118
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
5. **Auto-login**: CLI refresca tokens automáticamente
|
|
119
|
+
```bash
|
|
120
|
+
npm run build # Compila TypeScript
|
|
121
|
+
npm link # Instala globalmente para testing
|
|
122
|
+
```
|
|
208
123
|
|
|
209
|
-
## Documentación
|
|
124
|
+
## Documentación
|
|
210
125
|
|
|
211
|
-
Para
|
|
212
|
-
-
|
|
213
|
-
- `docs/
|
|
126
|
+
- **Para usuarios del CLI**: `docs/mcp/` (usado por `gufi_docs`)
|
|
127
|
+
- **Para desarrollo del CLI**: Este archivo
|
|
128
|
+
- **Tool descriptions**: `docs/mcp/tool-descriptions.json`
|
package/dist/mcp.js
CHANGED
|
@@ -122,30 +122,34 @@ async function developerRequest(path, options = {}, retry = true) {
|
|
|
122
122
|
return res.json();
|
|
123
123
|
}
|
|
124
124
|
// ════════════════════════════════════════════════════════════════════════════
|
|
125
|
-
// Tool Definitions
|
|
125
|
+
// Tool Definitions - Descriptions loaded from docs/mcp/tool-descriptions.json
|
|
126
126
|
// ════════════════════════════════════════════════════════════════════════════
|
|
127
|
+
// Load tool descriptions from centralized documentation
|
|
128
|
+
const TOOL_DESCRIPTIONS_PATH = path.join(DOCS_MCP_PATH, "tool-descriptions.json");
|
|
129
|
+
let toolDescriptions = {};
|
|
130
|
+
try {
|
|
131
|
+
const content = fs.readFileSync(TOOL_DESCRIPTIONS_PATH, "utf-8");
|
|
132
|
+
toolDescriptions = JSON.parse(content);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
console.error(`Warning: Could not load tool descriptions from ${TOOL_DESCRIPTIONS_PATH}`);
|
|
136
|
+
}
|
|
137
|
+
// Helper to get description from JSON or use fallback
|
|
138
|
+
function getDesc(toolName, fallback = "") {
|
|
139
|
+
return toolDescriptions[toolName]?.description || fallback;
|
|
140
|
+
}
|
|
127
141
|
const TOOLS = [
|
|
128
142
|
// ─────────────────────────────────────────────────────────────────────────
|
|
129
143
|
// Context & Info
|
|
130
144
|
// ─────────────────────────────────────────────────────────────────────────
|
|
145
|
+
{
|
|
146
|
+
name: "gufi_start",
|
|
147
|
+
description: getDesc("gufi_start"),
|
|
148
|
+
inputSchema: { type: "object", properties: {} },
|
|
149
|
+
},
|
|
131
150
|
{
|
|
132
151
|
name: "gufi_context",
|
|
133
|
-
description:
|
|
134
|
-
|
|
135
|
-
Use cases:
|
|
136
|
-
- Starting work on a package: gufi_context({ package_id: "14" })
|
|
137
|
-
- Understanding a view: gufi_context({ view_id: "13" })
|
|
138
|
-
- Exploring a company: gufi_context({ company_id: "116" })
|
|
139
|
-
|
|
140
|
-
The context includes:
|
|
141
|
-
- All modules and their entities (tables) with physical table names
|
|
142
|
-
- Field definitions with types, constraints, and options
|
|
143
|
-
- Available automations and their trigger types
|
|
144
|
-
- DataSources mappings for views (viewSpec.mainTable, etc.)
|
|
145
|
-
- Environment variables available
|
|
146
|
-
- Useful CLI commands for the project
|
|
147
|
-
|
|
148
|
-
Returns markdown-formatted context optimized for Claude.`,
|
|
152
|
+
description: getDesc("gufi_context"),
|
|
149
153
|
inputSchema: {
|
|
150
154
|
type: "object",
|
|
151
155
|
properties: {
|
|
@@ -158,20 +162,12 @@ Returns markdown-formatted context optimized for Claude.`,
|
|
|
158
162
|
},
|
|
159
163
|
{
|
|
160
164
|
name: "gufi_whoami",
|
|
161
|
-
description: "
|
|
165
|
+
description: getDesc("gufi_whoami"),
|
|
162
166
|
inputSchema: { type: "object", properties: {} },
|
|
163
167
|
},
|
|
164
168
|
{
|
|
165
169
|
name: "gufi_schema",
|
|
166
|
-
description:
|
|
167
|
-
|
|
168
|
-
Returns for each entity:
|
|
169
|
-
- id: Entity ID
|
|
170
|
-
- name: Entity name
|
|
171
|
-
- table: Physical table name (m{moduleId}_t{entityId})
|
|
172
|
-
- fields: Array of {name, type, label}
|
|
173
|
-
|
|
174
|
-
Use this to understand the data structure before creating queries or modifications.`,
|
|
170
|
+
description: getDesc("gufi_schema"),
|
|
175
171
|
inputSchema: {
|
|
176
172
|
type: "object",
|
|
177
173
|
properties: {
|
|
@@ -182,26 +178,7 @@ Use this to understand the data structure before creating queries or modificatio
|
|
|
182
178
|
},
|
|
183
179
|
{
|
|
184
180
|
name: "gufi_docs",
|
|
185
|
-
description:
|
|
186
|
-
|
|
187
|
-
Available topics:
|
|
188
|
-
- "overview" - Overview and workflow (start here)
|
|
189
|
-
- "architecture" - Technical architecture
|
|
190
|
-
- "modules" - Module system and entities
|
|
191
|
-
- "fields" - Field types and CB builders (IMPORTANT for data operations)
|
|
192
|
-
- "views" - View system, SDK, and React components
|
|
193
|
-
- "automations" - Automations and worker
|
|
194
|
-
- "api" - API endpoints reference
|
|
195
|
-
- "packages" - Packages and marketplace
|
|
196
|
-
- "errors" - Common errors and solutions
|
|
197
|
-
- "examples" - Practical code examples
|
|
198
|
-
|
|
199
|
-
You can also search across all docs with the search parameter.
|
|
200
|
-
|
|
201
|
-
Examples:
|
|
202
|
-
- gufi_docs({ topic: "fields" }) - Read about field types
|
|
203
|
-
- gufi_docs({ topic: "errors" }) - Common errors and fixes
|
|
204
|
-
- gufi_docs({ search: "currency" }) - Search for currency info`,
|
|
181
|
+
description: getDesc("gufi_docs"),
|
|
205
182
|
inputSchema: {
|
|
206
183
|
type: "object",
|
|
207
184
|
properties: {
|
|
@@ -215,12 +192,12 @@ Examples:
|
|
|
215
192
|
// ─────────────────────────────────────────────────────────────────────────
|
|
216
193
|
{
|
|
217
194
|
name: "gufi_companies",
|
|
218
|
-
description: "
|
|
195
|
+
description: getDesc("gufi_companies"),
|
|
219
196
|
inputSchema: { type: "object", properties: {} },
|
|
220
197
|
},
|
|
221
198
|
{
|
|
222
199
|
name: "gufi_company_create",
|
|
223
|
-
description: "
|
|
200
|
+
description: getDesc("gufi_company_create"),
|
|
224
201
|
inputSchema: {
|
|
225
202
|
type: "object",
|
|
226
203
|
properties: {
|
|
@@ -234,7 +211,7 @@ Examples:
|
|
|
234
211
|
// ─────────────────────────────────────────────────────────────────────────
|
|
235
212
|
{
|
|
236
213
|
name: "gufi_modules",
|
|
237
|
-
description: "
|
|
214
|
+
description: getDesc("gufi_modules"),
|
|
238
215
|
inputSchema: {
|
|
239
216
|
type: "object",
|
|
240
217
|
properties: {
|
|
@@ -245,26 +222,7 @@ Examples:
|
|
|
245
222
|
},
|
|
246
223
|
{
|
|
247
224
|
name: "gufi_module",
|
|
248
|
-
description:
|
|
249
|
-
|
|
250
|
-
Returns the complete module structure:
|
|
251
|
-
- name, displayName, icon
|
|
252
|
-
- submodules[]: Array of submodules
|
|
253
|
-
- entities[]: Array of entities (tables)
|
|
254
|
-
- name, label, kind
|
|
255
|
-
- fields[]: Array of fields with type, label, required, options, etc.
|
|
256
|
-
|
|
257
|
-
Field types (from @gufi/column-types):
|
|
258
|
-
- Text: text, email, url, barcode
|
|
259
|
-
- Numbers: number_int, number_float, percentage
|
|
260
|
-
- Date/Time: date, datetime, time
|
|
261
|
-
- Boolean: boolean
|
|
262
|
-
- Selection: select (single), multiselect (array)
|
|
263
|
-
- Relations: relation (FK), reversed_relation (virtual), users (array of user IDs)
|
|
264
|
-
- Complex (JSONB): currency, phone, location, file, signature, json
|
|
265
|
-
- Computed: formula, mirror
|
|
266
|
-
|
|
267
|
-
Each type has specific format. Use gufi.CB.* builders for correct format.`,
|
|
225
|
+
description: getDesc("gufi_module"),
|
|
268
226
|
inputSchema: {
|
|
269
227
|
type: "object",
|
|
270
228
|
properties: {
|
|
@@ -275,33 +233,7 @@ Each type has specific format. Use gufi.CB.* builders for correct format.`,
|
|
|
275
233
|
},
|
|
276
234
|
{
|
|
277
235
|
name: "gufi_module_update",
|
|
278
|
-
description:
|
|
279
|
-
|
|
280
|
-
IMPORTANT: Always read the module first with gufi_module, modify the JSON, then update.
|
|
281
|
-
|
|
282
|
-
Common modifications:
|
|
283
|
-
- Add a field: Add to entity.fields array
|
|
284
|
-
- Add an entity: Add to submodule.entities array
|
|
285
|
-
- Modify field: Change properties like type, label, required, options
|
|
286
|
-
|
|
287
|
-
Example field definition:
|
|
288
|
-
{
|
|
289
|
-
"name": "fecha_entrega",
|
|
290
|
-
"type": "date",
|
|
291
|
-
"label": "Fecha de Entrega",
|
|
292
|
-
"required": false
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
For select fields, include options:
|
|
296
|
-
{
|
|
297
|
-
"name": "estado",
|
|
298
|
-
"type": "select",
|
|
299
|
-
"label": "Estado",
|
|
300
|
-
"options": [
|
|
301
|
-
{ "value": "pendiente", "label": "Pendiente", "color": "yellow" },
|
|
302
|
-
{ "value": "completado", "label": "Completado", "color": "green" }
|
|
303
|
-
]
|
|
304
|
-
}`,
|
|
236
|
+
description: getDesc("gufi_module_update"),
|
|
305
237
|
inputSchema: {
|
|
306
238
|
type: "object",
|
|
307
239
|
properties: {
|
|
@@ -313,28 +245,7 @@ For select fields, include options:
|
|
|
313
245
|
},
|
|
314
246
|
{
|
|
315
247
|
name: "gufi_module_create",
|
|
316
|
-
description:
|
|
317
|
-
|
|
318
|
-
Example module structure:
|
|
319
|
-
{
|
|
320
|
-
"name": "inventory",
|
|
321
|
-
"displayName": "Inventario",
|
|
322
|
-
"icon": "Package",
|
|
323
|
-
"submodules": [{
|
|
324
|
-
"name": "products",
|
|
325
|
-
"label": "Productos",
|
|
326
|
-
"entities": [{
|
|
327
|
-
"name": "productos",
|
|
328
|
-
"label": "Productos",
|
|
329
|
-
"kind": "table",
|
|
330
|
-
"fields": [
|
|
331
|
-
{ "name": "nombre", "type": "text", "label": "Nombre", "required": true },
|
|
332
|
-
{ "name": "precio", "type": "currency", "label": "Precio" },
|
|
333
|
-
{ "name": "stock", "type": "number_int", "label": "Stock" }
|
|
334
|
-
]
|
|
335
|
-
}]
|
|
336
|
-
}]
|
|
337
|
-
}`,
|
|
248
|
+
description: getDesc("gufi_module_create"),
|
|
338
249
|
inputSchema: {
|
|
339
250
|
type: "object",
|
|
340
251
|
properties: {
|
|
@@ -349,14 +260,7 @@ Example module structure:
|
|
|
349
260
|
// ─────────────────────────────────────────────────────────────────────────
|
|
350
261
|
{
|
|
351
262
|
name: "gufi_automations",
|
|
352
|
-
description:
|
|
353
|
-
|
|
354
|
-
Trigger types:
|
|
355
|
-
- on_create: Runs when a row is created
|
|
356
|
-
- on_update: Runs when a row is updated
|
|
357
|
-
- on_delete: Runs when a row is deleted
|
|
358
|
-
- on_click: Manually triggered from UI buttons
|
|
359
|
-
- schedule: Runs on a cron schedule`,
|
|
263
|
+
description: getDesc("gufi_automations"),
|
|
360
264
|
inputSchema: {
|
|
361
265
|
type: "object",
|
|
362
266
|
properties: {
|
|
@@ -367,7 +271,7 @@ Trigger types:
|
|
|
367
271
|
},
|
|
368
272
|
{
|
|
369
273
|
name: "gufi_automation",
|
|
370
|
-
description: "
|
|
274
|
+
description: getDesc("gufi_automation"),
|
|
371
275
|
inputSchema: {
|
|
372
276
|
type: "object",
|
|
373
277
|
properties: {
|
|
@@ -378,32 +282,7 @@ Trigger types:
|
|
|
378
282
|
},
|
|
379
283
|
{
|
|
380
284
|
name: "gufi_automation_create",
|
|
381
|
-
description:
|
|
382
|
-
|
|
383
|
-
IMPORTANT: api.query() returns rows directly, NOT { rows }:
|
|
384
|
-
const rows = await api.query("SELECT * FROM table"); // ✅ Correct
|
|
385
|
-
const { rows } = await api.query(...); // ❌ Wrong!
|
|
386
|
-
|
|
387
|
-
Available API methods:
|
|
388
|
-
- api.query(sql, params) - Execute SQL, returns rows array
|
|
389
|
-
- api.getOne(table, id) - Get single row
|
|
390
|
-
- api.getList(table, { filters, sort, limit }) - Get multiple rows
|
|
391
|
-
- api.create(table, data) - Create row, returns { id }
|
|
392
|
-
- api.update(table, id, data) - Update row
|
|
393
|
-
- api.delete(table, id) - Delete row
|
|
394
|
-
- api.log(message) - Log for debugging
|
|
395
|
-
- api.sendEmail({ to, subject, body }) - Send email
|
|
396
|
-
- api.sendWhatsApp({ to, template, params }) - Send WhatsApp
|
|
397
|
-
|
|
398
|
-
Example automation:
|
|
399
|
-
async function send_welcome_email({ record, api }) {
|
|
400
|
-
const { email, nombre } = record;
|
|
401
|
-
await api.sendEmail({
|
|
402
|
-
to: email,
|
|
403
|
-
subject: "Bienvenido!",
|
|
404
|
-
body: \`Hola \${nombre}, gracias por registrarte.\`
|
|
405
|
-
});
|
|
406
|
-
}`,
|
|
285
|
+
description: getDesc("gufi_automation_create"),
|
|
407
286
|
inputSchema: {
|
|
408
287
|
type: "object",
|
|
409
288
|
properties: {
|
|
@@ -417,7 +296,7 @@ async function send_welcome_email({ record, api }) {
|
|
|
417
296
|
},
|
|
418
297
|
{
|
|
419
298
|
name: "gufi_entity_automations",
|
|
420
|
-
description: "
|
|
299
|
+
description: getDesc("gufi_entity_automations"),
|
|
421
300
|
inputSchema: {
|
|
422
301
|
type: "object",
|
|
423
302
|
properties: {
|
|
@@ -428,19 +307,7 @@ async function send_welcome_email({ record, api }) {
|
|
|
428
307
|
},
|
|
429
308
|
{
|
|
430
309
|
name: "gufi_entity_automations_update",
|
|
431
|
-
description:
|
|
432
|
-
|
|
433
|
-
Example configuration:
|
|
434
|
-
{
|
|
435
|
-
"on_create": ["send_welcome_email"],
|
|
436
|
-
"on_update": ["sync_to_external", "notify_changes"],
|
|
437
|
-
"on_delete": [],
|
|
438
|
-
"on_click": [
|
|
439
|
-
{ "function_name": "generate_report", "label": "Generar Reporte", "icon": "FileText" }
|
|
440
|
-
]
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
For on_click, you can specify label and icon for the button that triggers it.`,
|
|
310
|
+
description: getDesc("gufi_entity_automations_update"),
|
|
444
311
|
inputSchema: {
|
|
445
312
|
type: "object",
|
|
446
313
|
properties: {
|
|
@@ -455,7 +322,7 @@ For on_click, you can specify label and icon for the button that triggers it.`,
|
|
|
455
322
|
},
|
|
456
323
|
{
|
|
457
324
|
name: "gufi_automations_executions",
|
|
458
|
-
description: "
|
|
325
|
+
description: getDesc("gufi_automations_executions"),
|
|
459
326
|
inputSchema: {
|
|
460
327
|
type: "object",
|
|
461
328
|
properties: {
|
|
@@ -471,13 +338,7 @@ For on_click, you can specify label and icon for the button that triggers it.`,
|
|
|
471
338
|
// ─────────────────────────────────────────────────────────────────────────
|
|
472
339
|
{
|
|
473
340
|
name: "gufi_rows",
|
|
474
|
-
description:
|
|
475
|
-
Company is auto-detected from the module ID in the table name.
|
|
476
|
-
|
|
477
|
-
Supports:
|
|
478
|
-
- Pagination: limit (default 20), offset (default 0)
|
|
479
|
-
- Sorting: sort (field name), order (ASC/DESC)
|
|
480
|
-
- Filtering: filter="field=value"`,
|
|
341
|
+
description: getDesc("gufi_rows"),
|
|
481
342
|
inputSchema: {
|
|
482
343
|
type: "object",
|
|
483
344
|
properties: {
|
|
@@ -493,7 +354,7 @@ Supports:
|
|
|
493
354
|
},
|
|
494
355
|
{
|
|
495
356
|
name: "gufi_row",
|
|
496
|
-
description: "
|
|
357
|
+
description: getDesc("gufi_row"),
|
|
497
358
|
inputSchema: {
|
|
498
359
|
type: "object",
|
|
499
360
|
properties: {
|
|
@@ -505,35 +366,7 @@ Supports:
|
|
|
505
366
|
},
|
|
506
367
|
{
|
|
507
368
|
name: "gufi_row_create",
|
|
508
|
-
description:
|
|
509
|
-
|
|
510
|
-
Field formats (from @gufi/column-types):
|
|
511
|
-
|
|
512
|
-
SIMPLE TYPES:
|
|
513
|
-
- text/email/url/barcode: "string value"
|
|
514
|
-
- number_int: 42 (integer)
|
|
515
|
-
- number_float: 3.14 (decimal)
|
|
516
|
-
- percentage: 0.75 (decimal, displayed as 75%)
|
|
517
|
-
- boolean: true/false
|
|
518
|
-
- date: "2024-01-15" (ISO date)
|
|
519
|
-
- datetime: "2024-01-15T10:30:00Z" (ISO)
|
|
520
|
-
- time: "14:30:00"
|
|
521
|
-
- select: "value" (option value, not label)
|
|
522
|
-
- relation: 123 (FK integer)
|
|
523
|
-
|
|
524
|
-
ARRAY TYPES:
|
|
525
|
-
- multiselect: ["value1", "value2"]
|
|
526
|
-
- users: [16, 23] (array of user IDs)
|
|
527
|
-
|
|
528
|
-
JSONB TYPES (complex objects):
|
|
529
|
-
- currency: { "currency": "EUR", "amount": 150.00 }
|
|
530
|
-
- phone: { "prefix": "+34", "number": "612345678" }
|
|
531
|
-
- location: { "street": "Mayor", "number": "15", "city": "Madrid", "lat": 40.41, "lng": -3.70 }
|
|
532
|
-
- file: [{ "url": "company_130/uuid.pdf", "name": "doc.pdf" }] or ["company_130/photo.jpg"]
|
|
533
|
-
- signature: "data:image/png;base64,..." (base64 data URL)
|
|
534
|
-
- json: { any: "object" }
|
|
535
|
-
|
|
536
|
-
In views, use gufi.CB.* builders for correct formatting.`,
|
|
369
|
+
description: getDesc("gufi_row_create"),
|
|
537
370
|
inputSchema: {
|
|
538
371
|
type: "object",
|
|
539
372
|
properties: {
|
|
@@ -545,20 +378,7 @@ In views, use gufi.CB.* builders for correct formatting.`,
|
|
|
545
378
|
},
|
|
546
379
|
{
|
|
547
380
|
name: "gufi_row_update",
|
|
548
|
-
description:
|
|
549
|
-
|
|
550
|
-
IMPORTANT for select/relation fields:
|
|
551
|
-
When updating a select or relation field, you must update BOTH:
|
|
552
|
-
- The field value: "estado": "completado"
|
|
553
|
-
- The display value: "estado__display": "Completado"
|
|
554
|
-
|
|
555
|
-
Example:
|
|
556
|
-
{
|
|
557
|
-
"estado": "completado",
|
|
558
|
-
"estado__display": "Completado",
|
|
559
|
-
"cliente": 123,
|
|
560
|
-
"cliente__display": "Empresa ABC"
|
|
561
|
-
}`,
|
|
381
|
+
description: getDesc("gufi_row_update"),
|
|
562
382
|
inputSchema: {
|
|
563
383
|
type: "object",
|
|
564
384
|
properties: {
|
|
@@ -571,7 +391,7 @@ Example:
|
|
|
571
391
|
},
|
|
572
392
|
{
|
|
573
393
|
name: "gufi_row_delete",
|
|
574
|
-
description: "
|
|
394
|
+
description: getDesc("gufi_row_delete"),
|
|
575
395
|
inputSchema: {
|
|
576
396
|
type: "object",
|
|
577
397
|
properties: {
|
|
@@ -586,7 +406,7 @@ Example:
|
|
|
586
406
|
// ─────────────────────────────────────────────────────────────────────────
|
|
587
407
|
{
|
|
588
408
|
name: "gufi_env",
|
|
589
|
-
description: "
|
|
409
|
+
description: getDesc("gufi_env"),
|
|
590
410
|
inputSchema: {
|
|
591
411
|
type: "object",
|
|
592
412
|
properties: {
|
|
@@ -596,7 +416,7 @@ Example:
|
|
|
596
416
|
},
|
|
597
417
|
{
|
|
598
418
|
name: "gufi_env_set",
|
|
599
|
-
description: "
|
|
419
|
+
description: getDesc("gufi_env_set"),
|
|
600
420
|
inputSchema: {
|
|
601
421
|
type: "object",
|
|
602
422
|
properties: {
|
|
@@ -608,7 +428,7 @@ Example:
|
|
|
608
428
|
},
|
|
609
429
|
{
|
|
610
430
|
name: "gufi_env_delete",
|
|
611
|
-
description: "
|
|
431
|
+
description: getDesc("gufi_env_delete"),
|
|
612
432
|
inputSchema: {
|
|
613
433
|
type: "object",
|
|
614
434
|
properties: {
|
|
@@ -622,7 +442,7 @@ Example:
|
|
|
622
442
|
// ─────────────────────────────────────────────────────────────────────────
|
|
623
443
|
{
|
|
624
444
|
name: "gufi_view_files",
|
|
625
|
-
description: "
|
|
445
|
+
description: getDesc("gufi_view_files"),
|
|
626
446
|
inputSchema: {
|
|
627
447
|
type: "object",
|
|
628
448
|
properties: {
|
|
@@ -633,7 +453,7 @@ Example:
|
|
|
633
453
|
},
|
|
634
454
|
{
|
|
635
455
|
name: "gufi_view_file_update",
|
|
636
|
-
description: "
|
|
456
|
+
description: getDesc("gufi_view_file_update"),
|
|
637
457
|
inputSchema: {
|
|
638
458
|
type: "object",
|
|
639
459
|
properties: {
|
|
@@ -646,7 +466,7 @@ Example:
|
|
|
646
466
|
},
|
|
647
467
|
{
|
|
648
468
|
name: "gufi_view_files_update",
|
|
649
|
-
description: "
|
|
469
|
+
description: getDesc("gufi_view_files_update"),
|
|
650
470
|
inputSchema: {
|
|
651
471
|
type: "object",
|
|
652
472
|
properties: {
|
|
@@ -672,12 +492,12 @@ Example:
|
|
|
672
492
|
// ─────────────────────────────────────────────────────────────────────────
|
|
673
493
|
{
|
|
674
494
|
name: "gufi_packages",
|
|
675
|
-
description: "
|
|
495
|
+
description: getDesc("gufi_packages"),
|
|
676
496
|
inputSchema: { type: "object", properties: {} },
|
|
677
497
|
},
|
|
678
498
|
{
|
|
679
499
|
name: "gufi_package",
|
|
680
|
-
description: "
|
|
500
|
+
description: getDesc("gufi_package"),
|
|
681
501
|
inputSchema: {
|
|
682
502
|
type: "object",
|
|
683
503
|
properties: {
|
|
@@ -688,7 +508,7 @@ Example:
|
|
|
688
508
|
},
|
|
689
509
|
{
|
|
690
510
|
name: "gufi_package_create",
|
|
691
|
-
description: "
|
|
511
|
+
description: getDesc("gufi_package_create"),
|
|
692
512
|
inputSchema: {
|
|
693
513
|
type: "object",
|
|
694
514
|
properties: {
|
|
@@ -700,7 +520,7 @@ Example:
|
|
|
700
520
|
},
|
|
701
521
|
{
|
|
702
522
|
name: "gufi_package_delete",
|
|
703
|
-
description: "
|
|
523
|
+
description: getDesc("gufi_package_delete"),
|
|
704
524
|
inputSchema: {
|
|
705
525
|
type: "object",
|
|
706
526
|
properties: {
|
|
@@ -711,7 +531,7 @@ Example:
|
|
|
711
531
|
},
|
|
712
532
|
{
|
|
713
533
|
name: "gufi_package_add_module",
|
|
714
|
-
description: "
|
|
534
|
+
description: getDesc("gufi_package_add_module"),
|
|
715
535
|
inputSchema: {
|
|
716
536
|
type: "object",
|
|
717
537
|
properties: {
|
|
@@ -724,7 +544,7 @@ Example:
|
|
|
724
544
|
},
|
|
725
545
|
{
|
|
726
546
|
name: "gufi_package_remove_module",
|
|
727
|
-
description: "
|
|
547
|
+
description: getDesc("gufi_package_remove_module"),
|
|
728
548
|
inputSchema: {
|
|
729
549
|
type: "object",
|
|
730
550
|
properties: {
|
|
@@ -736,7 +556,7 @@ Example:
|
|
|
736
556
|
},
|
|
737
557
|
{
|
|
738
558
|
name: "gufi_package_add_view",
|
|
739
|
-
description: "
|
|
559
|
+
description: getDesc("gufi_package_add_view"),
|
|
740
560
|
inputSchema: {
|
|
741
561
|
type: "object",
|
|
742
562
|
properties: {
|
|
@@ -748,7 +568,7 @@ Example:
|
|
|
748
568
|
},
|
|
749
569
|
{
|
|
750
570
|
name: "gufi_package_remove_view",
|
|
751
|
-
description: "
|
|
571
|
+
description: getDesc("gufi_package_remove_view"),
|
|
752
572
|
inputSchema: {
|
|
753
573
|
type: "object",
|
|
754
574
|
properties: {
|
|
@@ -760,7 +580,7 @@ Example:
|
|
|
760
580
|
},
|
|
761
581
|
{
|
|
762
582
|
name: "gufi_package_publish",
|
|
763
|
-
description: "
|
|
583
|
+
description: getDesc("gufi_package_publish"),
|
|
764
584
|
inputSchema: {
|
|
765
585
|
type: "object",
|
|
766
586
|
properties: {
|
|
@@ -771,7 +591,7 @@ Example:
|
|
|
771
591
|
},
|
|
772
592
|
{
|
|
773
593
|
name: "gufi_package_unpublish",
|
|
774
|
-
description: "
|
|
594
|
+
description: getDesc("gufi_package_unpublish"),
|
|
775
595
|
inputSchema: {
|
|
776
596
|
type: "object",
|
|
777
597
|
properties: {
|
|
@@ -782,7 +602,7 @@ Example:
|
|
|
782
602
|
},
|
|
783
603
|
{
|
|
784
604
|
name: "gufi_package_sync",
|
|
785
|
-
description: "
|
|
605
|
+
description: getDesc("gufi_package_sync"),
|
|
786
606
|
inputSchema: {
|
|
787
607
|
type: "object",
|
|
788
608
|
properties: {
|
|
@@ -793,7 +613,7 @@ Example:
|
|
|
793
613
|
},
|
|
794
614
|
{
|
|
795
615
|
name: "gufi_package_check",
|
|
796
|
-
description: "
|
|
616
|
+
description: getDesc("gufi_package_check"),
|
|
797
617
|
inputSchema: {
|
|
798
618
|
type: "object",
|
|
799
619
|
properties: {
|
|
@@ -807,7 +627,7 @@ Example:
|
|
|
807
627
|
// ─────────────────────────────────────────────────────────────────────────
|
|
808
628
|
{
|
|
809
629
|
name: "gufi_package_migrations",
|
|
810
|
-
description: "
|
|
630
|
+
description: getDesc("gufi_package_migrations"),
|
|
811
631
|
inputSchema: {
|
|
812
632
|
type: "object",
|
|
813
633
|
properties: {
|
|
@@ -818,7 +638,7 @@ Example:
|
|
|
818
638
|
},
|
|
819
639
|
{
|
|
820
640
|
name: "gufi_package_migration_create",
|
|
821
|
-
description: "
|
|
641
|
+
description: getDesc("gufi_package_migration_create"),
|
|
822
642
|
inputSchema: {
|
|
823
643
|
type: "object",
|
|
824
644
|
properties: {
|
|
@@ -834,7 +654,7 @@ Example:
|
|
|
834
654
|
},
|
|
835
655
|
{
|
|
836
656
|
name: "gufi_package_migration_delete",
|
|
837
|
-
description: "
|
|
657
|
+
description: getDesc("gufi_package_migration_delete"),
|
|
838
658
|
inputSchema: {
|
|
839
659
|
type: "object",
|
|
840
660
|
properties: {
|
|
@@ -846,7 +666,7 @@ Example:
|
|
|
846
666
|
},
|
|
847
667
|
{
|
|
848
668
|
name: "gufi_package_entities",
|
|
849
|
-
description: "
|
|
669
|
+
description: getDesc("gufi_package_entities"),
|
|
850
670
|
inputSchema: {
|
|
851
671
|
type: "object",
|
|
852
672
|
properties: {
|
|
@@ -927,11 +747,117 @@ async function detectCompanyFromTable(table) {
|
|
|
927
747
|
const result = await detectCompanyFromModule(moduleId);
|
|
928
748
|
return result?.companyId;
|
|
929
749
|
}
|
|
750
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
751
|
+
// Context Auto-Detection Helpers
|
|
752
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
753
|
+
/**
|
|
754
|
+
* Detect if we're inside the gogufi codebase (for internal development)
|
|
755
|
+
* Checks for presence of key directories: backend/, frontend/, tools/cli/, CLAUDE.md
|
|
756
|
+
*/
|
|
757
|
+
function detectIfInGufiCodebase() {
|
|
758
|
+
try {
|
|
759
|
+
const cwd = process.cwd();
|
|
760
|
+
const indicators = [
|
|
761
|
+
path.join(cwd, "backend"),
|
|
762
|
+
path.join(cwd, "frontend"),
|
|
763
|
+
path.join(cwd, "tools", "cli"),
|
|
764
|
+
path.join(cwd, "CLAUDE.md"),
|
|
765
|
+
];
|
|
766
|
+
const matches = indicators.filter((p) => fs.existsSync(p));
|
|
767
|
+
return matches.length >= 3; // If 3+ indicators exist, it's the codebase
|
|
768
|
+
}
|
|
769
|
+
catch {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
function loadViewMetaFromCwd() {
|
|
774
|
+
try {
|
|
775
|
+
const metaPath = path.join(process.cwd(), ".gufi-view.json");
|
|
776
|
+
if (fs.existsSync(metaPath)) {
|
|
777
|
+
return JSON.parse(fs.readFileSync(metaPath, "utf-8"));
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
catch { }
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
930
783
|
// Tool handler implementations
|
|
931
784
|
const toolHandlers = {
|
|
932
785
|
// ─────────────────────────────────────────────────────────────────────────
|
|
933
786
|
// Context & Info
|
|
934
787
|
// ─────────────────────────────────────────────────────────────────────────
|
|
788
|
+
/**
|
|
789
|
+
* Smart entrypoint that auto-detects context and provides guidance
|
|
790
|
+
*/
|
|
791
|
+
async gufi_start() {
|
|
792
|
+
// 1. Check if we're in the gogufi codebase (internal development)
|
|
793
|
+
if (detectIfInGufiCodebase()) {
|
|
794
|
+
return {
|
|
795
|
+
detected: "gogufi_codebase",
|
|
796
|
+
summary: "You are inside the Gufi codebase. This is for INTERNAL platform development.",
|
|
797
|
+
what_to_read: {
|
|
798
|
+
first: "docs/claude/01-critical-rules.md - MUST READ (deployment, notificaciones, traducciones)",
|
|
799
|
+
architecture: "docs/claude/02-architecture.md",
|
|
800
|
+
patterns: "docs/claude/07-patterns.md - Common errors and patterns",
|
|
801
|
+
},
|
|
802
|
+
important_rules: {
|
|
803
|
+
hot_reload: "Frontend and backend auto-reload on save. DON'T restart manually.",
|
|
804
|
+
column_types: "After libs/column-types changes: cd libs/column-types && npm run build",
|
|
805
|
+
no_deploy: "NEVER deploy to production without explicit user request.",
|
|
806
|
+
notifications: "Use toastSuccess/toastError from @/shared/notifications/toast (NOT shadcn)",
|
|
807
|
+
translations: "Add to es.ts AND en.ts BEFORE using tUI()",
|
|
808
|
+
},
|
|
809
|
+
for_client_work: "If you need to work on packages/views, use: gufi_context({ package_id: 'X' })",
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
// 2. Check if we're in a view directory (.gufi-view.json)
|
|
813
|
+
const viewMeta = loadViewMetaFromCwd();
|
|
814
|
+
if (viewMeta) {
|
|
815
|
+
const context = await generateViewContextMcp(viewMeta.viewId, false);
|
|
816
|
+
return {
|
|
817
|
+
detected: "view_directory",
|
|
818
|
+
summary: `Working on view "${viewMeta.viewName}" (ID: ${viewMeta.viewId})`,
|
|
819
|
+
...context,
|
|
820
|
+
workflow: {
|
|
821
|
+
edit: "Edit files with your editor, changes will sync",
|
|
822
|
+
watch: "Run: gufi view:watch (auto-syncs on save)",
|
|
823
|
+
push: "Manual push: gufi view:push",
|
|
824
|
+
logs: "View logs: gufi view:logs",
|
|
825
|
+
},
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
// 3. Fallback: List packages and guide
|
|
829
|
+
try {
|
|
830
|
+
const response = await developerRequest("/my-packages");
|
|
831
|
+
const packages = response.data || [];
|
|
832
|
+
return {
|
|
833
|
+
detected: "none",
|
|
834
|
+
summary: `No specific context detected. You have ${packages.length} package(s).`,
|
|
835
|
+
packages: packages.map((p) => ({
|
|
836
|
+
id: p.pk_id,
|
|
837
|
+
name: p.name,
|
|
838
|
+
version: p.version,
|
|
839
|
+
status: p.status,
|
|
840
|
+
})),
|
|
841
|
+
how_to_start: [
|
|
842
|
+
"Get package context: gufi_context({ package_id: 'X' })",
|
|
843
|
+
"Get view context: gufi_context({ view_id: 'Y' })",
|
|
844
|
+
"Pull a view locally: gufi view:pull <id>",
|
|
845
|
+
"Then gufi_start will auto-detect",
|
|
846
|
+
],
|
|
847
|
+
if_building_new: [
|
|
848
|
+
"Create package: gufi_package_create({ name: 'My Package' })",
|
|
849
|
+
"Then add modules and views",
|
|
850
|
+
],
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
catch {
|
|
854
|
+
return {
|
|
855
|
+
detected: "none",
|
|
856
|
+
summary: "Could not fetch packages. Make sure you're logged in.",
|
|
857
|
+
hint: "Run: gufi login",
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
},
|
|
935
861
|
async gufi_whoami() {
|
|
936
862
|
const config = loadConfig();
|
|
937
863
|
return {
|
|
@@ -953,18 +879,57 @@ const toolHandlers = {
|
|
|
953
879
|
return generateCompanyContextMcp(parseInt(params.company_id), params.full);
|
|
954
880
|
}
|
|
955
881
|
else {
|
|
956
|
-
//
|
|
882
|
+
// Auto-detect context from current directory
|
|
883
|
+
// 1. Check if we're in the gogufi codebase
|
|
884
|
+
if (detectIfInGufiCodebase()) {
|
|
885
|
+
return {
|
|
886
|
+
type: "codebase",
|
|
887
|
+
summary: "You are inside the Gufi codebase (gogufi/). This is for INTERNAL development of the platform.",
|
|
888
|
+
what_to_do: {
|
|
889
|
+
for_codebase_work: [
|
|
890
|
+
"Read docs/claude/01-critical-rules.md FIRST (deployment rules, notificaciones, traducciones)",
|
|
891
|
+
"Architecture: docs/claude/02-architecture.md",
|
|
892
|
+
"Patterns & errors: docs/claude/07-patterns.md",
|
|
893
|
+
],
|
|
894
|
+
for_client_work: [
|
|
895
|
+
"To work on a specific package: gufi_context({ package_id: 'X' })",
|
|
896
|
+
"To work on a specific view: gufi_context({ view_id: 'Y' })",
|
|
897
|
+
"List your packages: gufi_packages()",
|
|
898
|
+
],
|
|
899
|
+
},
|
|
900
|
+
important_rules: {
|
|
901
|
+
hot_reload: "Frontend and backend auto-reload on file save. DON'T restart manually.",
|
|
902
|
+
column_types: "After changes to libs/column-types: cd libs/column-types && npm run build",
|
|
903
|
+
no_deploy: "NEVER deploy to production without explicit request from user.",
|
|
904
|
+
},
|
|
905
|
+
docs_structure: {
|
|
906
|
+
"docs/claude/": "For INTERNAL codebase development (you are here)",
|
|
907
|
+
"docs/mcp/": "For platform USERS (consultants building ERPs) - used by gufi_docs tool",
|
|
908
|
+
},
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
// 2. Check if we're in a view directory (.gufi-view.json)
|
|
912
|
+
const viewMeta = loadViewMetaFromCwd();
|
|
913
|
+
if (viewMeta) {
|
|
914
|
+
return generateViewContextMcp(viewMeta.viewId, params.full);
|
|
915
|
+
}
|
|
916
|
+
// 3. Fallback: Return packages overview
|
|
957
917
|
const response = await developerRequest("/my-packages");
|
|
958
918
|
const packages = response.data || [];
|
|
959
919
|
return {
|
|
960
920
|
type: "packages_overview",
|
|
921
|
+
summary: `You have ${packages.length} package(s). Specify one to get detailed context.`,
|
|
961
922
|
packages: packages.map((p) => ({
|
|
962
923
|
id: p.pk_id,
|
|
963
924
|
name: p.name,
|
|
964
925
|
version: p.version,
|
|
965
926
|
status: p.status,
|
|
966
927
|
})),
|
|
967
|
-
|
|
928
|
+
next_actions: [
|
|
929
|
+
"Get package context: gufi_context({ package_id: 'X' })",
|
|
930
|
+
"Get view context: gufi_context({ view_id: 'Y' })",
|
|
931
|
+
"Pull a view locally: gufi view:pull <id> (then gufi_context will auto-detect)",
|
|
932
|
+
],
|
|
968
933
|
};
|
|
969
934
|
}
|
|
970
935
|
},
|
|
@@ -1354,6 +1319,15 @@ const toolHandlers = {
|
|
|
1354
1319
|
content: f.content,
|
|
1355
1320
|
is_entry_point: f.is_entry_point,
|
|
1356
1321
|
})),
|
|
1322
|
+
_hint: {
|
|
1323
|
+
cli_workflow: [
|
|
1324
|
+
`gufi view:pull ${params.view_id} # Download files to local folder`,
|
|
1325
|
+
"# Edit files locally with your editor",
|
|
1326
|
+
"gufi view:push # Upload changes back to Gufi",
|
|
1327
|
+
"gufi view:watch # Auto-sync on file changes",
|
|
1328
|
+
],
|
|
1329
|
+
note: "For large views, consider using CLI commands instead of MCP tools",
|
|
1330
|
+
},
|
|
1357
1331
|
};
|
|
1358
1332
|
},
|
|
1359
1333
|
async gufi_view_file_update(params) {
|
|
@@ -1592,8 +1566,33 @@ async function generateViewContextMcp(viewId, includeConcepts) {
|
|
|
1592
1566
|
tableStructures[dsKey] = tableInfo;
|
|
1593
1567
|
}
|
|
1594
1568
|
}
|
|
1569
|
+
// Build summary and next_actions
|
|
1570
|
+
const dsCount = Object.keys(dataSources).length;
|
|
1571
|
+
const autoCount = automations.length;
|
|
1572
|
+
const firstTable = Object.values(dataSources)[0];
|
|
1573
|
+
const summary = [
|
|
1574
|
+
`View "${view.name}" (ID: ${viewId})`,
|
|
1575
|
+
pkg ? `Package: "${pkg.name}"` : "Independent view",
|
|
1576
|
+
dsCount > 0 ? `${dsCount} dataSource(s): ${Object.keys(dataSources).join(", ")}` : "No dataSources configured",
|
|
1577
|
+
autoCount > 0 ? `${autoCount} automation(s) available` : "No automations",
|
|
1578
|
+
].join(" | ");
|
|
1579
|
+
const nextActions = [];
|
|
1580
|
+
// Always first: pull for local editing
|
|
1581
|
+
nextActions.push(`Edit locally: gufi view:pull ${viewId} && gufi view:watch`);
|
|
1582
|
+
// If has tables, suggest viewing data
|
|
1583
|
+
if (firstTable) {
|
|
1584
|
+
nextActions.push(`View data: gufi_rows({ table: "${firstTable}", limit: 5 })`);
|
|
1585
|
+
}
|
|
1586
|
+
// If has automations, suggest viewing them
|
|
1587
|
+
if (autoCount > 0 && viewCompanyId) {
|
|
1588
|
+
nextActions.push(`See automations: gufi_automations({ company_id: "${viewCompanyId}" })`);
|
|
1589
|
+
}
|
|
1590
|
+
// Always: docs for field types
|
|
1591
|
+
nextActions.push(`Field types reference: gufi_docs({ topic: "fields" })`);
|
|
1595
1592
|
const result = {
|
|
1596
1593
|
type: "view",
|
|
1594
|
+
summary,
|
|
1595
|
+
next_actions: nextActions,
|
|
1597
1596
|
view_id: viewId,
|
|
1598
1597
|
name: view.name,
|
|
1599
1598
|
view_type: view.view_type || "marketplace_view",
|
|
@@ -1639,8 +1638,33 @@ async function generatePackageContextMcp(packageId, includeConcepts) {
|
|
|
1639
1638
|
source_module_id: mod.source_module_id,
|
|
1640
1639
|
});
|
|
1641
1640
|
}
|
|
1641
|
+
// Build summary and next_actions
|
|
1642
|
+
const summary = [
|
|
1643
|
+
`Package "${pkg.name}" (ID: ${packageId})`,
|
|
1644
|
+
`Version: ${pkg.version || "0.1.0"}`,
|
|
1645
|
+
`Status: ${pkg.status || "draft"}`,
|
|
1646
|
+
`${modulesInfo.length} module(s)`,
|
|
1647
|
+
`${views.length} view(s)`,
|
|
1648
|
+
].join(" | ");
|
|
1649
|
+
const nextActions = [];
|
|
1650
|
+
// If has views, suggest editing one
|
|
1651
|
+
if (views.length > 0) {
|
|
1652
|
+
const firstView = views[0];
|
|
1653
|
+
nextActions.push(`Edit a view: gufi view:pull ${firstView.view_id} && gufi view:watch`);
|
|
1654
|
+
nextActions.push(`Get view context: gufi_context({ view_id: "${firstView.view_id}" })`);
|
|
1655
|
+
}
|
|
1656
|
+
// If has sandbox company, suggest exploring data
|
|
1657
|
+
if (pkg.sandbox_company_id) {
|
|
1658
|
+
nextActions.push(`Explore sandbox data: gufi_schema({ company_id: "${pkg.sandbox_company_id}" })`);
|
|
1659
|
+
}
|
|
1660
|
+
// If draft, suggest publishing workflow
|
|
1661
|
+
if (pkg.status === "draft" || !pkg.status) {
|
|
1662
|
+
nextActions.push(`When ready: gufi package:sync ${packageId} && gufi package:publish ${packageId}`);
|
|
1663
|
+
}
|
|
1642
1664
|
const result = {
|
|
1643
1665
|
type: "package",
|
|
1666
|
+
summary,
|
|
1667
|
+
next_actions: nextActions,
|
|
1644
1668
|
package_id: packageId,
|
|
1645
1669
|
name: pkg.name,
|
|
1646
1670
|
version: pkg.version || "0.1.0",
|
|
@@ -1714,8 +1738,35 @@ async function generateCompanyContextMcp(companyId, includeConcepts) {
|
|
|
1714
1738
|
entities,
|
|
1715
1739
|
});
|
|
1716
1740
|
}
|
|
1741
|
+
// Build summary and next_actions
|
|
1742
|
+
const totalEntities = modulesInfo.reduce((acc, m) => acc + (m.entities?.length || 0), 0);
|
|
1743
|
+
const summary = [
|
|
1744
|
+
`Company ID: ${companyId}`,
|
|
1745
|
+
`${modulesInfo.length} module(s)`,
|
|
1746
|
+
`${totalEntities} table(s)`,
|
|
1747
|
+
`${automations.length} automation(s)`,
|
|
1748
|
+
].join(" | ");
|
|
1749
|
+
const nextActions = [];
|
|
1750
|
+
// Suggest viewing data from first table
|
|
1751
|
+
if (modulesInfo.length > 0 && modulesInfo[0].entities?.length > 0) {
|
|
1752
|
+
const firstTable = modulesInfo[0].entities[0].table;
|
|
1753
|
+
if (firstTable) {
|
|
1754
|
+
nextActions.push(`View data: gufi_rows({ table: "${firstTable}", limit: 5 })`);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
// If has modules, suggest editing one
|
|
1758
|
+
if (modulesInfo.length > 0 && modulesInfo[0].id) {
|
|
1759
|
+
nextActions.push(`Edit module structure: gufi_module({ module_id: "${modulesInfo[0].id}" })`);
|
|
1760
|
+
}
|
|
1761
|
+
// If has automations, suggest viewing them
|
|
1762
|
+
if (automations.length > 0) {
|
|
1763
|
+
nextActions.push(`View automation code: gufi_automation({ automation_id: "${automations[0].id}" })`);
|
|
1764
|
+
}
|
|
1765
|
+
nextActions.push(`Field types reference: gufi_docs({ topic: "fields" })`);
|
|
1717
1766
|
const result = {
|
|
1718
1767
|
type: "company",
|
|
1768
|
+
summary,
|
|
1769
|
+
next_actions: nextActions,
|
|
1719
1770
|
company_id: companyId,
|
|
1720
1771
|
modules: modulesInfo,
|
|
1721
1772
|
automations: automations.map((a) => ({
|