gufi-cli 0.1.22 → 0.1.24

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 (3) hide show
  1. package/CLAUDE.md +158 -177
  2. package/dist/mcp.js +246 -14
  3. package/package.json +1 -1
package/CLAUDE.md CHANGED
@@ -1,213 +1,194 @@
1
- # Gufi CLI - Documentación para Claude
1
+ # Gufi CLI & MCP Server
2
2
 
3
- > **Documentación centralizada en `docs/claude/`**
3
+ > **Para documentación de USO del CLI**, ve a `docs/mcp/`
4
4
  >
5
- > Este archivo es un puntero. Para documentación completa del CLI, lee:
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
- ## Quick Reference
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 '{...}'
9
+ ```
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
44
26
  ```
45
27
 
46
- ## Output JSON (para Claude/scripts)
28
+ ## Entornos: Local vs Producción
47
29
 
48
- Todos los comandos de lectura soportan `--json` para output estructurado sin colores ni emojis:
30
+ El CLI y MCP funcionan **tanto en local como en producción**. El entorno se configura así:
49
31
 
50
32
  ```bash
51
- gufi companies --json # Lista companies en JSON
52
- gufi modules 146 --json # Lista módulos en JSON
53
- gufi module 360 --json # JSON del módulo
54
- gufi automations --json # Lista automations en JSON
55
- gufi automation 15 --json # Código y metadata del automation
56
- gufi schema --json # Estructura de tablas en JSON
57
- gufi rows m360_t16192 --json # Registros en JSON
58
- gufi row m360_t16192 5 --json # Registro específico en JSON
59
- gufi packages --json # Lista packages en JSON
60
- gufi package 14 --json # Detalles del package en JSON
33
+ # Ver entorno actual
34
+ gufi whoami
35
+
36
+ # Cambiar a local (http://localhost:3000)
37
+ gufi config:local
38
+
39
+ # Cambiar a producción (https://gogufi.com)
40
+ gufi config:prod
61
41
  ```
62
42
 
63
- Usar `--json` cuando necesites parsear el output programáticamente.
43
+ **IMPORTANTE**:
44
+ - Todos los tools MCP (`gufi_*`) respetan el entorno configurado
45
+ - `gufi_whoami()` muestra el entorno actual (`environment: "local"` o `"prod"`)
46
+ - Antes de hacer cambios, verifica que estás en el entorno correcto
64
47
 
65
- ## MCP Server (Model Context Protocol)
48
+ ### Config file (~/.gufi/config.json)
66
49
 
67
- El CLI incluye un servidor MCP que permite a Claude interactuar **directamente** con Gufi sin ejecutar comandos manualmente.
50
+ ```json
51
+ {
52
+ "env": "local", // "local" o "prod"
53
+ "email": "user@example.com",
54
+ "accessToken": "...",
55
+ "refreshToken": "..."
56
+ }
57
+ ```
68
58
 
69
- ### Configuración (una sola vez)
59
+ ## MCP Server
70
60
 
71
- ```bash
72
- claude mcp add --transport stdio gufi -- gufi mcp
61
+ El servidor MCP está en `src/mcp.ts` y expone 44 tools para que Claude interactúe con Gufi.
62
+
63
+ ### Tools principales
64
+
65
+ - **`gufi_context`** - Genera contexto inteligente:
66
+ - `summary`: Resumen ejecutivo
67
+ - `next_actions`: Pasos sugeridos
68
+ - Auto-detecta si está en codebase, vista local, o muestra packages
69
+ - **Usar con**: `{ package_id }`, `{ view_id }`, `{ company_id }`
70
+
71
+ - **`gufi_docs`** - Lee documentación de `docs/mcp/`
72
+ - **`gufi_schema`** - Schema de BD (módulos, tablas, campos)
73
+ - **`gufi_rows/row/row_create/row_update`** - CRUD de datos
74
+ - **`gufi_module/module_update`** - Gestión de módulos JSON
75
+ - **`gufi_automation/automation_create`** - Gestión de automations
76
+
77
+ ### Añadir un nuevo tool MCP
78
+
79
+ 1. **Definir tool** en array `TOOLS` (~línea 200):
80
+ ```typescript
81
+ {
82
+ name: "gufi_nuevo_tool",
83
+ description: getDesc("gufi_nuevo_tool"),
84
+ inputSchema: {
85
+ type: "object",
86
+ properties: {
87
+ param1: { type: "string", description: "..." },
88
+ },
89
+ required: ["param1"],
90
+ },
91
+ },
73
92
  ```
74
93
 
75
- ### Tools disponibles (43 tools)
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
94
+ 2. **Añadir handler** en `toolHandlers` (~línea 870):
95
+ ```typescript
96
+ async gufi_nuevo_tool(params: { param1: string }) {
97
+ // Implementación
98
+ return { result: "..." };
99
+ },
100
+ ```
133
101
 
102
+ 3. **Añadir descripción** en `docs/mcp/tool-descriptions.json`:
103
+ ```json
104
+ "gufi_nuevo_tool": {
105
+ "description": "Descripción clara del tool..."
106
+ }
134
107
  ```
135
- Usuario: "Agrega un campo 'fecha_entrega' tipo date al módulo de pedidos"
136
- Claude: [usa gufi_module para leer] → [modifica JSON] → [usa gufi_module_update]
137
- "Listo, agregué el campo fecha_entrega al módulo de pedidos"
138
-
139
- Usuario: "Crea un automation que envíe email cuando un pedido pase a 'enviado'"
140
- Claude: [usa gufi_automations para ver existentes]
141
- [escribe código JS]
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"
108
+
109
+ ### API Endpoints
110
+
111
+ Los endpoints del backend están montados así:
112
+
113
+ ```
114
+ /api/auth/* - Autenticación (login, refresh)
115
+ /api/company/* - Recursos de empresa (modules, schema, tables)
116
+ /api/developer/* - Recursos de developer (packages, views)
117
+ /api/marketplace/* - Marketplace público
118
+ /api/automation-scripts - Scripts de automatización
119
+ /api/cli/* - Endpoints específicos del CLI
150
120
  ```
151
121
 
152
- ### Tipos de Campo (@gufi/column-types)
122
+ **CRÍTICO**: Los módulos usan `/api/company/modules/`, NO `/api/modules/`
153
123
 
154
- Al crear o actualizar datos, usa los formatos correctos:
124
+ ### Funciones helper importantes
155
125
 
156
- **Simples:**
157
- - text, email, url, barcode: `"string"`
158
- - number_int: `42` | number_float: `3.14` | percentage: `0.75`
159
- - boolean: `true/false`
160
- - date: `"2024-01-15"` | datetime: `"2024-01-15T10:30:00Z"` | time: `"14:30:00"`
161
- - select: `"value"` | relation: `123`
126
+ - `detectIfInGufiCodebase()` - Detecta si está en el repo gogufi
127
+ - `loadViewMetaFromCwd()` - Carga `.gufi-view.json` del directorio actual
128
+ - `generateViewContextMcp()` - Genera contexto de una vista
129
+ - `generatePackageContextMcp()` - Genera contexto de un package
130
+ - `apiRequest(endpoint, options, companyId)` - Peticiones a API con auth
131
+ - `developerRequest(path, options)` - Peticiones a /api/developer/
162
132
 
163
- **Arrays:**
164
- - multiselect: `["value1", "value2"]`
165
- - users: `[16, 23]`
133
+ ## CLI Commands
166
134
 
167
- **JSONB (objetos complejos):**
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" }]`
135
+ Cada comando está en `src/commands/`. Patrón común:
172
136
 
173
- En vistas usa `gufi.CB.*` para formatear correctamente:
174
137
  ```typescript
175
- gufi.CB.currency(150) // { currency: 'EUR', amount: 150 }
176
- gufi.CB.phone('612345678') // { prefix: '+34', number: '612345678' }
177
- gufi.CB.date() // '2024-01-15' (hoy)
178
- gufi.CB.multiselect('a', 'b') // → ['a', 'b']
138
+ export async function miComando(args: string[], flags: Flags) {
139
+ // 1. Parsear argumentos
140
+ // 2. Validar
141
+ // 3. Hacer petición API
142
+ // 4. Mostrar resultado
143
+ }
179
144
  ```
180
145
 
181
- ### Seguridad
146
+ ### Comandos principales
182
147
 
183
- - Usa las credenciales del CLI (`gufi login`)
184
- - Solo accede a resources con permisos del usuario
185
- - Todo corre localmente (stdio), no hay servidor público
148
+ | Comando | Descripción |
149
+ |---------|-------------|
150
+ | `gufi login` | Login interactivo |
151
+ | `gufi whoami` | Ver usuario y entorno |
152
+ | `gufi config:local` | Cambiar a entorno local |
153
+ | `gufi config:prod` | Cambiar a producción |
154
+ | `gufi context` | Generar contexto para Claude |
155
+ | `gufi view:pull <id>` | Descargar vista a local |
156
+ | `gufi view:push` | Subir cambios de vista |
157
+ | `gufi view:watch` | Auto-sync de cambios |
158
+ | `gufi docs <topic>` | Ver documentación |
186
159
 
187
- ## Comandos Esenciales
160
+ ## Config (~/.gufi/)
161
+
162
+ ```
163
+ ~/.gufi/
164
+ ├── config.json # Credenciales y entornos
165
+ └── gufi-dev/ # Vistas descargadas
166
+ └── view_13/
167
+ ├── .gufi-view.json # Metadata de sync
168
+ ├── index.tsx
169
+ └── ...
170
+ ```
188
171
 
189
- | Quiero... | Comando |
190
- |-----------|---------|
191
- | **Contexto para Claude** | `gufi context` |
192
- | **Diagnóstico** | `gufi doctor` |
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` |
172
+ ## Testing
200
173
 
201
- ## Tips
174
+ ```bash
175
+ cd tools/cli
176
+ npm test
177
+ ```
178
+
179
+ ## Build
180
+
181
+ ```bash
182
+ npm run build # Compila TypeScript
183
+ npm link # Instala globalmente para testing
184
+ ```
202
185
 
203
- 1. **`gufi context`**: Úsalo al inicio de cualquier tarea
204
- 2. **Auto-detección**: `module`, `automation`, `rows` detectan company automáticamente
205
- 3. **--edit**: Abre en `$EDITOR`
206
- 4. **Entornos separados**: Cada uno con sus credenciales
207
- 5. **Auto-login**: CLI refresca tokens automáticamente
186
+ **IMPORTANTE**: Después de cambios en mcp.ts, hay que:
187
+ 1. `npm run build` en tools/cli/
188
+ 2. Reiniciar el MCP server (o reiniciar Claude Code)
208
189
 
209
- ## Documentación Completa
190
+ ## Documentación
210
191
 
211
- Para documentación detallada de cada comando, arquitectura, y patrones, ve a:
212
- - `docs/claude/` - Fuente de verdad para Claude
213
- - `docs/guide/27-gufi-cli.md` - Guía técnica del CLI
192
+ - **Para usuarios del CLI**: `docs/mcp/` (usado por `gufi_docs`)
193
+ - **Para desarrollo del CLI**: Este archivo
194
+ - **Tool descriptions**: `docs/mcp/tool-descriptions.json`
package/dist/mcp.js CHANGED
@@ -142,6 +142,11 @@ const TOOLS = [
142
142
  // ─────────────────────────────────────────────────────────────────────────
143
143
  // Context & Info
144
144
  // ─────────────────────────────────────────────────────────────────────────
145
+ {
146
+ name: "gufi_start",
147
+ description: getDesc("gufi_start"),
148
+ inputSchema: { type: "object", properties: {} },
149
+ },
145
150
  {
146
151
  name: "gufi_context",
147
152
  description: getDesc("gufi_context"),
@@ -337,7 +342,8 @@ const TOOLS = [
337
342
  inputSchema: {
338
343
  type: "object",
339
344
  properties: {
340
- table: { type: "string", description: "Table name (e.g., m360_t16192)" },
345
+ table: { type: "string", description: "Table name (physical ID like m360_t16192, NOT logical names)" },
346
+ company_id: { type: "string", description: "Company ID (required if table is not physical ID format)" },
341
347
  limit: { type: "number", description: "Number of rows (default 20)" },
342
348
  offset: { type: "number", description: "Offset for pagination (default 0)" },
343
349
  sort: { type: "string", description: "Field to sort by (default: id)" },
@@ -353,7 +359,8 @@ const TOOLS = [
353
359
  inputSchema: {
354
360
  type: "object",
355
361
  properties: {
356
- table: { type: "string", description: "Table name (e.g., m360_t16192)" },
362
+ table: { type: "string", description: "Table name (physical ID like m360_t16192)" },
363
+ company_id: { type: "string", description: "Company ID (required if table is not physical ID format)" },
357
364
  id: { type: "number", description: "Row ID" },
358
365
  },
359
366
  required: ["table", "id"],
@@ -365,7 +372,8 @@ const TOOLS = [
365
372
  inputSchema: {
366
373
  type: "object",
367
374
  properties: {
368
- table: { type: "string", description: "Table name" },
375
+ table: { type: "string", description: "Table name (physical ID like m360_t16192)" },
376
+ company_id: { type: "string", description: "Company ID (required if table is not physical ID format)" },
369
377
  data: { type: "object", description: "Row data as key-value pairs" },
370
378
  },
371
379
  required: ["table", "data"],
@@ -377,7 +385,8 @@ const TOOLS = [
377
385
  inputSchema: {
378
386
  type: "object",
379
387
  properties: {
380
- table: { type: "string", description: "Table name" },
388
+ table: { type: "string", description: "Table name (physical ID like m360_t16192)" },
389
+ company_id: { type: "string", description: "Company ID (required if table is not physical ID format)" },
381
390
  id: { type: "number", description: "Row ID" },
382
391
  data: { type: "object", description: "Fields to update" },
383
392
  },
@@ -390,7 +399,8 @@ const TOOLS = [
390
399
  inputSchema: {
391
400
  type: "object",
392
401
  properties: {
393
- table: { type: "string", description: "Table name" },
402
+ table: { type: "string", description: "Table name (physical ID like m360_t16192)" },
403
+ company_id: { type: "string", description: "Company ID (required if table is not physical ID format)" },
394
404
  id: { type: "number", description: "Row ID" },
395
405
  },
396
406
  required: ["table", "id"],
@@ -742,11 +752,117 @@ async function detectCompanyFromTable(table) {
742
752
  const result = await detectCompanyFromModule(moduleId);
743
753
  return result?.companyId;
744
754
  }
755
+ // ─────────────────────────────────────────────────────────────────────────────
756
+ // Context Auto-Detection Helpers
757
+ // ─────────────────────────────────────────────────────────────────────────────
758
+ /**
759
+ * Detect if we're inside the gogufi codebase (for internal development)
760
+ * Checks for presence of key directories: backend/, frontend/, tools/cli/, CLAUDE.md
761
+ */
762
+ function detectIfInGufiCodebase() {
763
+ try {
764
+ const cwd = process.cwd();
765
+ const indicators = [
766
+ path.join(cwd, "backend"),
767
+ path.join(cwd, "frontend"),
768
+ path.join(cwd, "tools", "cli"),
769
+ path.join(cwd, "CLAUDE.md"),
770
+ ];
771
+ const matches = indicators.filter((p) => fs.existsSync(p));
772
+ return matches.length >= 3; // If 3+ indicators exist, it's the codebase
773
+ }
774
+ catch {
775
+ return false;
776
+ }
777
+ }
778
+ function loadViewMetaFromCwd() {
779
+ try {
780
+ const metaPath = path.join(process.cwd(), ".gufi-view.json");
781
+ if (fs.existsSync(metaPath)) {
782
+ return JSON.parse(fs.readFileSync(metaPath, "utf-8"));
783
+ }
784
+ }
785
+ catch { }
786
+ return null;
787
+ }
745
788
  // Tool handler implementations
746
789
  const toolHandlers = {
747
790
  // ─────────────────────────────────────────────────────────────────────────
748
791
  // Context & Info
749
792
  // ─────────────────────────────────────────────────────────────────────────
793
+ /**
794
+ * Smart entrypoint that auto-detects context and provides guidance
795
+ */
796
+ async gufi_start() {
797
+ // 1. Check if we're in the gogufi codebase (internal development)
798
+ if (detectIfInGufiCodebase()) {
799
+ return {
800
+ detected: "gogufi_codebase",
801
+ summary: "You are inside the Gufi codebase. This is for INTERNAL platform development.",
802
+ what_to_read: {
803
+ first: "docs/claude/01-critical-rules.md - MUST READ (deployment, notificaciones, traducciones)",
804
+ architecture: "docs/claude/02-architecture.md",
805
+ patterns: "docs/claude/07-patterns.md - Common errors and patterns",
806
+ },
807
+ important_rules: {
808
+ hot_reload: "Frontend and backend auto-reload on save. DON'T restart manually.",
809
+ column_types: "After libs/column-types changes: cd libs/column-types && npm run build",
810
+ no_deploy: "NEVER deploy to production without explicit user request.",
811
+ notifications: "Use toastSuccess/toastError from @/shared/notifications/toast (NOT shadcn)",
812
+ translations: "Add to es.ts AND en.ts BEFORE using tUI()",
813
+ },
814
+ for_client_work: "If you need to work on packages/views, use: gufi_context({ package_id: 'X' })",
815
+ };
816
+ }
817
+ // 2. Check if we're in a view directory (.gufi-view.json)
818
+ const viewMeta = loadViewMetaFromCwd();
819
+ if (viewMeta) {
820
+ const context = await generateViewContextMcp(viewMeta.viewId, false);
821
+ return {
822
+ detected: "view_directory",
823
+ summary: `Working on view "${viewMeta.viewName}" (ID: ${viewMeta.viewId})`,
824
+ ...context,
825
+ workflow: {
826
+ edit: "Edit files with your editor, changes will sync",
827
+ watch: "Run: gufi view:watch (auto-syncs on save)",
828
+ push: "Manual push: gufi view:push",
829
+ logs: "View logs: gufi view:logs",
830
+ },
831
+ };
832
+ }
833
+ // 3. Fallback: List packages and guide
834
+ try {
835
+ const response = await developerRequest("/my-packages");
836
+ const packages = response.data || [];
837
+ return {
838
+ detected: "none",
839
+ summary: `No specific context detected. You have ${packages.length} package(s).`,
840
+ packages: packages.map((p) => ({
841
+ id: p.pk_id,
842
+ name: p.name,
843
+ version: p.version,
844
+ status: p.status,
845
+ })),
846
+ how_to_start: [
847
+ "Get package context: gufi_context({ package_id: 'X' })",
848
+ "Get view context: gufi_context({ view_id: 'Y' })",
849
+ "Pull a view locally: gufi view:pull <id>",
850
+ "Then gufi_start will auto-detect",
851
+ ],
852
+ if_building_new: [
853
+ "Create package: gufi_package_create({ name: 'My Package' })",
854
+ "Then add modules and views",
855
+ ],
856
+ };
857
+ }
858
+ catch {
859
+ return {
860
+ detected: "none",
861
+ summary: "Could not fetch packages. Make sure you're logged in.",
862
+ hint: "Run: gufi login",
863
+ };
864
+ }
865
+ },
750
866
  async gufi_whoami() {
751
867
  const config = loadConfig();
752
868
  return {
@@ -768,18 +884,57 @@ const toolHandlers = {
768
884
  return generateCompanyContextMcp(parseInt(params.company_id), params.full);
769
885
  }
770
886
  else {
771
- // Return packages overview as fallback
887
+ // Auto-detect context from current directory
888
+ // 1. Check if we're in the gogufi codebase
889
+ if (detectIfInGufiCodebase()) {
890
+ return {
891
+ type: "codebase",
892
+ summary: "You are inside the Gufi codebase (gogufi/). This is for INTERNAL development of the platform.",
893
+ what_to_do: {
894
+ for_codebase_work: [
895
+ "Read docs/claude/01-critical-rules.md FIRST (deployment rules, notificaciones, traducciones)",
896
+ "Architecture: docs/claude/02-architecture.md",
897
+ "Patterns & errors: docs/claude/07-patterns.md",
898
+ ],
899
+ for_client_work: [
900
+ "To work on a specific package: gufi_context({ package_id: 'X' })",
901
+ "To work on a specific view: gufi_context({ view_id: 'Y' })",
902
+ "List your packages: gufi_packages()",
903
+ ],
904
+ },
905
+ important_rules: {
906
+ hot_reload: "Frontend and backend auto-reload on file save. DON'T restart manually.",
907
+ column_types: "After changes to libs/column-types: cd libs/column-types && npm run build",
908
+ no_deploy: "NEVER deploy to production without explicit request from user.",
909
+ },
910
+ docs_structure: {
911
+ "docs/claude/": "For INTERNAL codebase development (you are here)",
912
+ "docs/mcp/": "For platform USERS (consultants building ERPs) - used by gufi_docs tool",
913
+ },
914
+ };
915
+ }
916
+ // 2. Check if we're in a view directory (.gufi-view.json)
917
+ const viewMeta = loadViewMetaFromCwd();
918
+ if (viewMeta) {
919
+ return generateViewContextMcp(viewMeta.viewId, params.full);
920
+ }
921
+ // 3. Fallback: Return packages overview
772
922
  const response = await developerRequest("/my-packages");
773
923
  const packages = response.data || [];
774
924
  return {
775
925
  type: "packages_overview",
926
+ summary: `You have ${packages.length} package(s). Specify one to get detailed context.`,
776
927
  packages: packages.map((p) => ({
777
928
  id: p.pk_id,
778
929
  name: p.name,
779
930
  version: p.version,
780
931
  status: p.status,
781
932
  })),
782
- hint: "Specify package_id, view_id, or company_id for detailed context",
933
+ next_actions: [
934
+ "Get package context: gufi_context({ package_id: 'X' })",
935
+ "Get view context: gufi_context({ view_id: 'Y' })",
936
+ "Pull a view locally: gufi view:pull <id> (then gufi_context will auto-detect)",
937
+ ],
783
938
  };
784
939
  }
785
940
  },
@@ -991,7 +1146,7 @@ const toolHandlers = {
991
1146
  if (!result) {
992
1147
  throw new Error(`Module ${params.module_id} not found`);
993
1148
  }
994
- const response = await apiRequest(`/api/modules/${params.module_id}`, {
1149
+ const response = await apiRequest(`/api/company/modules/${params.module_id}`, {
995
1150
  method: "PUT",
996
1151
  body: JSON.stringify({ json_definition: params.definition }),
997
1152
  headers: { "X-Company-ID": result.companyId },
@@ -999,7 +1154,7 @@ const toolHandlers = {
999
1154
  return { success: true, module_id: params.module_id };
1000
1155
  },
1001
1156
  async gufi_module_create(params) {
1002
- const response = await apiRequest("/api/modules", {
1157
+ const response = await apiRequest("/api/company/modules", {
1003
1158
  method: "POST",
1004
1159
  body: JSON.stringify({ json_definition: params.definition }),
1005
1160
  headers: { "X-Company-ID": params.company_id },
@@ -1073,7 +1228,7 @@ const toolHandlers = {
1073
1228
  // Data (CRUD)
1074
1229
  // ─────────────────────────────────────────────────────────────────────────
1075
1230
  async gufi_rows(params) {
1076
- const companyId = await detectCompanyFromTable(params.table);
1231
+ const companyId = params.company_id || await detectCompanyFromTable(params.table);
1077
1232
  const limit = params.limit || 20;
1078
1233
  const offset = params.offset || 0;
1079
1234
  const body = {
@@ -1098,7 +1253,7 @@ const toolHandlers = {
1098
1253
  };
1099
1254
  },
1100
1255
  async gufi_row(params) {
1101
- const companyId = await detectCompanyFromTable(params.table);
1256
+ const companyId = params.company_id || await detectCompanyFromTable(params.table);
1102
1257
  const result = await apiRequest(`/api/tables/${params.table}/getOne`, {
1103
1258
  method: "POST",
1104
1259
  body: JSON.stringify({ id: params.id }),
@@ -1110,7 +1265,7 @@ const toolHandlers = {
1110
1265
  };
1111
1266
  },
1112
1267
  async gufi_row_create(params) {
1113
- const companyId = await detectCompanyFromTable(params.table);
1268
+ const companyId = params.company_id || await detectCompanyFromTable(params.table);
1114
1269
  const result = await apiRequest(`/api/tables/${params.table}`, {
1115
1270
  method: "POST",
1116
1271
  body: JSON.stringify(params.data),
@@ -1122,7 +1277,7 @@ const toolHandlers = {
1122
1277
  };
1123
1278
  },
1124
1279
  async gufi_row_update(params) {
1125
- const companyId = await detectCompanyFromTable(params.table);
1280
+ const companyId = params.company_id || await detectCompanyFromTable(params.table);
1126
1281
  const result = await apiRequest(`/api/tables/${params.table}/${params.id}`, {
1127
1282
  method: "PUT",
1128
1283
  body: JSON.stringify(params.data),
@@ -1130,7 +1285,7 @@ const toolHandlers = {
1130
1285
  return { success: true, row: result.data || result };
1131
1286
  },
1132
1287
  async gufi_row_delete(params) {
1133
- const companyId = await detectCompanyFromTable(params.table);
1288
+ const companyId = params.company_id || await detectCompanyFromTable(params.table);
1134
1289
  await apiRequest(`/api/tables/${params.table}/${params.id}`, {
1135
1290
  method: "DELETE",
1136
1291
  }, companyId);
@@ -1416,8 +1571,33 @@ async function generateViewContextMcp(viewId, includeConcepts) {
1416
1571
  tableStructures[dsKey] = tableInfo;
1417
1572
  }
1418
1573
  }
1574
+ // Build summary and next_actions
1575
+ const dsCount = Object.keys(dataSources).length;
1576
+ const autoCount = automations.length;
1577
+ const firstTable = Object.values(dataSources)[0];
1578
+ const summary = [
1579
+ `View "${view.name}" (ID: ${viewId})`,
1580
+ pkg ? `Package: "${pkg.name}"` : "Independent view",
1581
+ dsCount > 0 ? `${dsCount} dataSource(s): ${Object.keys(dataSources).join(", ")}` : "No dataSources configured",
1582
+ autoCount > 0 ? `${autoCount} automation(s) available` : "No automations",
1583
+ ].join(" | ");
1584
+ const nextActions = [];
1585
+ // Always first: pull for local editing
1586
+ nextActions.push(`Edit locally: gufi view:pull ${viewId} && gufi view:watch`);
1587
+ // If has tables, suggest viewing data
1588
+ if (firstTable) {
1589
+ nextActions.push(`View data: gufi_rows({ table: "${firstTable}", limit: 5 })`);
1590
+ }
1591
+ // If has automations, suggest viewing them
1592
+ if (autoCount > 0 && viewCompanyId) {
1593
+ nextActions.push(`See automations: gufi_automations({ company_id: "${viewCompanyId}" })`);
1594
+ }
1595
+ // Always: docs for field types
1596
+ nextActions.push(`Field types reference: gufi_docs({ topic: "fields" })`);
1419
1597
  const result = {
1420
1598
  type: "view",
1599
+ summary,
1600
+ next_actions: nextActions,
1421
1601
  view_id: viewId,
1422
1602
  name: view.name,
1423
1603
  view_type: view.view_type || "marketplace_view",
@@ -1463,8 +1643,33 @@ async function generatePackageContextMcp(packageId, includeConcepts) {
1463
1643
  source_module_id: mod.source_module_id,
1464
1644
  });
1465
1645
  }
1646
+ // Build summary and next_actions
1647
+ const summary = [
1648
+ `Package "${pkg.name}" (ID: ${packageId})`,
1649
+ `Version: ${pkg.version || "0.1.0"}`,
1650
+ `Status: ${pkg.status || "draft"}`,
1651
+ `${modulesInfo.length} module(s)`,
1652
+ `${views.length} view(s)`,
1653
+ ].join(" | ");
1654
+ const nextActions = [];
1655
+ // If has views, suggest editing one
1656
+ if (views.length > 0) {
1657
+ const firstView = views[0];
1658
+ nextActions.push(`Edit a view: gufi view:pull ${firstView.view_id} && gufi view:watch`);
1659
+ nextActions.push(`Get view context: gufi_context({ view_id: "${firstView.view_id}" })`);
1660
+ }
1661
+ // If has sandbox company, suggest exploring data
1662
+ if (pkg.sandbox_company_id) {
1663
+ nextActions.push(`Explore sandbox data: gufi_schema({ company_id: "${pkg.sandbox_company_id}" })`);
1664
+ }
1665
+ // If draft, suggest publishing workflow
1666
+ if (pkg.status === "draft" || !pkg.status) {
1667
+ nextActions.push(`When ready: gufi package:sync ${packageId} && gufi package:publish ${packageId}`);
1668
+ }
1466
1669
  const result = {
1467
1670
  type: "package",
1671
+ summary,
1672
+ next_actions: nextActions,
1468
1673
  package_id: packageId,
1469
1674
  name: pkg.name,
1470
1675
  version: pkg.version || "0.1.0",
@@ -1538,8 +1743,35 @@ async function generateCompanyContextMcp(companyId, includeConcepts) {
1538
1743
  entities,
1539
1744
  });
1540
1745
  }
1746
+ // Build summary and next_actions
1747
+ const totalEntities = modulesInfo.reduce((acc, m) => acc + (m.entities?.length || 0), 0);
1748
+ const summary = [
1749
+ `Company ID: ${companyId}`,
1750
+ `${modulesInfo.length} module(s)`,
1751
+ `${totalEntities} table(s)`,
1752
+ `${automations.length} automation(s)`,
1753
+ ].join(" | ");
1754
+ const nextActions = [];
1755
+ // Suggest viewing data from first table
1756
+ if (modulesInfo.length > 0 && modulesInfo[0].entities?.length > 0) {
1757
+ const firstTable = modulesInfo[0].entities[0].table;
1758
+ if (firstTable) {
1759
+ nextActions.push(`View data: gufi_rows({ table: "${firstTable}", limit: 5 })`);
1760
+ }
1761
+ }
1762
+ // If has modules, suggest editing one
1763
+ if (modulesInfo.length > 0 && modulesInfo[0].id) {
1764
+ nextActions.push(`Edit module structure: gufi_module({ module_id: "${modulesInfo[0].id}" })`);
1765
+ }
1766
+ // If has automations, suggest viewing them
1767
+ if (automations.length > 0) {
1768
+ nextActions.push(`View automation code: gufi_automation({ automation_id: "${automations[0].id}" })`);
1769
+ }
1770
+ nextActions.push(`Field types reference: gufi_docs({ topic: "fields" })`);
1541
1771
  const result = {
1542
1772
  type: "company",
1773
+ summary,
1774
+ next_actions: nextActions,
1543
1775
  company_id: companyId,
1544
1776
  modules: modulesInfo,
1545
1777
  automations: automations.map((a) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gufi-cli",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "CLI for developing Gufi Marketplace views locally with Claude Code",
5
5
  "bin": {
6
6
  "gufi": "./bin/gufi.js"