# migpt_fs_api

API REST de solo lectura para que `nimach_gpt_dev` pueda navegar proyectos, buscar archivos, buscar contenido y leer código fuente desde Apache2/PHP7 en Debian.

## Decisiones principales

- PHP 7 puro, sin frameworks.
- Endpoints reales separados, sin router dinámico.
- Autenticación por `Authorization: Bearer <token>`.
- Todas las funciones operativas son de solo lectura.
- Root configurable en `config.inc.php`.
- Cada request debe indicar `project`, que corresponde a una subcarpeta directa de `root_path`.
- Las carpetas bloqueadas aplican solo a proyectos de primer nivel.
- `ndangelo` viene bloqueado por defecto.
- No se excluye automáticamente ninguna carpeta interna del proyecto.
- `project-map.php` calcula el mapa en vivo en cada request.

## Regla operativa obligatoria para migpt

Antes de comenzar el análisis de cualquier consigna sobre un proyecto, `migpt` debe ejecutar primero:

```bash
curl -s -X POST 'https://HOST/api/project-map.php' \
  -H 'Authorization: Bearer TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"project":"PROYECTO","path":"","max_depth":0}'
```

Motivo: el mapa se calcula en vivo y debe reflejar el estado real del filesystem antes de que `migpt` empiece a razonar sobre archivos. Durante la operación de `migpt`, se asume que ningún archivo será modificado externamente.

## Instalación

1. Copiar la carpeta `migpt_fs_api` al DocumentRoot o a un Alias de Apache.

Ejemplo:

```bash
sudo mkdir -p /var/www/html/migpt_fs_api
sudo cp -R migpt_fs_api/* /var/www/html/migpt_fs_api/
```

2. Editar `config.inc.php`:

```php
'root_path' => '/mnt/migpt_root_path',
'blocked_projects' => array('ndangelo'),
'bearer_tokens' => array('TOKEN_LARGO_ALEATORIO')
```

3. Verificar que Apache/PHP pueda leer el root:

```bash
sudo -u www-data test -r /mnt/migpt_root_path && echo OK
```

4. Probar health:

```bash
curl -s 'https://HOST/migpt_fs_api/health.php'
```

5. Probar autenticación:

```bash
curl -s 'https://HOST/migpt_fs_api/projects.php' \
  -H 'Authorization: Bearer TOKEN_LARGO_ALEATORIO'
```

## Contrato general de respuesta

Todas las respuestas usan el mismo formato:

```json
{
  "ok": true,
  "error": null,
  "meta": {
    "operation": "read",
    "project": "nettuno_reales",
    "relative_path": "src/app.php",
    "root_path": "/mnt/migpt_root_path",
    "generated_at": "2026-05-02T22:00:00-03:00",
    "execution_ms": 12.3
  },
  "data": {}
}
```

Error:

```json
{
  "ok": false,
  "error": {
    "code": "PATH_TRAVERSAL_BLOCKED",
    "message": "No se permite navegar fuera del proyecto.",
    "details": {}
  },
  "meta": {},
  "data": null
}
```

## Seguridad de paths

Una request nunca trabaja directamente contra `/mnt/migpt_root_path`, sino contra:

```text
/mnt/migpt_root_path/<project>/<path>
```

Reglas:

- `project` debe ser una carpeta de primer nivel.
- `project` no puede contener `/`, `\`, `.` ni `..`.
- Si `project` está en `blocked_projects`, se rechaza toda la request.
- `path` no puede usar `../`.
- La ruta real resuelta debe quedar dentro del proyecto.
- Los symlinks solo son aceptables si resuelven dentro del proyecto.

## Endpoints

### `health.php`

Método: `GET`  
No requiere token.

Devuelve estado básico del servicio y del root configurado.

---

### `projects.php`

Método: `GET`  
Requiere token.

Lista proyectos de primer nivel, indicando si están bloqueados.

```bash
curl -s 'https://HOST/migpt_fs_api/projects.php' \
  -H 'Authorization: Bearer TOKEN'
```

---

### `project-map.php`

Método: `POST`  
Requiere token.

Genera un mapa vivo del proyecto.

```json
{
  "project": "nettuno_reales",
  "path": "",
  "max_depth": 0,
  "recent_limit": 50,
  "largest_limit": 50,
  "include_hash": false
}
```

`max_depth = 0` significa sin límite.

Devuelve:

- cantidad de archivos;
- cantidad de directorios;
- tamaño total;
- distribución por extensión;
- carpetas raíz;
- archivos más grandes;
- archivos recientes;
- distribución por carpeta superior.

---

### `list.php`

Método: `POST`

Lista el contenido directo de un directorio.

```json
{
  "project": "nettuno_reales",
  "path": "app/controllers",
  "include_hash": false
}
```

---

### `tree.php`

Método: `POST`

Recorre árbol de directorios.

```json
{
  "project": "nettuno_reales",
  "path": "",
  "max_depth": 3,
  "max_results": 0,
  "include_hash": false
}
```

`max_results = 0` significa sin límite.

---

### `stat.php`

Método: `POST`

Devuelve metadata completa de archivo o carpeta.

```json
{
  "project": "nettuno_reales",
  "path": "app/config.php",
  "include_hash": true
}
```

Metadata incluida:

- nombre;
- tipo;
- path relativo;
- tamaño;
- fecha modificación;
- permisos;
- owner uid;
- group gid;
- readable/writable;
- mime;
- hash opcional.

---

### `read.php`

Método: `POST`

Lee un archivo completo, por líneas o por bytes.

#### Lectura completa

```json
{
  "project": "nettuno_reales",
  "path": "app/config.php",
  "mode": "full"
}
```

#### Lectura por líneas

```json
{
  "project": "nettuno_reales",
  "path": "app/config.php",
  "mode": "lines",
  "start_line": 20,
  "end_line": 80
}
```

#### Lectura por bytes

```json
{
  "project": "nettuno_reales",
  "path": "app/config.php",
  "mode": "bytes",
  "offset": 0,
  "length": 4096
}
```

Si `length = 0`, lee desde `offset` hasta EOF.

---

### `read-multiple.php`

Método: `POST`

Lee múltiples archivos en una sola request.

```json
{
  "project": "nettuno_reales",
  "files": [
    {"path":"app/config.php","mode":"full"},
    {"path":"app/Stock.php","mode":"lines","start_line":10,"end_line":90},
    {"path":"logs/app.log","mode":"bytes","offset":0,"length":2048}
  ]
}
```

---

### `search-files.php`

Método: `POST`

Busca archivos por path/nombre relativo.

```json
{
  "project": "nettuno_reales",
  "path": "",
  "query": "PedidoController",
  "regex": false,
  "case_sensitive": false,
  "extensions": ["php"],
  "max_results": 200,
  "include_hash": false
}
```

---

### `search-content.php`

Método: `POST`

Busca contenido dentro de archivos.

```json
{
  "project": "nettuno_reales",
  "path": "",
  "query": "calcularStock",
  "regex": false,
  "case_sensitive": false,
  "extensions": ["php", "js", "sql"],
  "include_dirs": [],
  "exclude_dirs": [],
  "max_file_size_mb": 0,
  "max_results": 200,
  "context_lines": 3
}
```

Notas:

- `extensions: []` busca en todas las extensiones.
- `include_dirs: []` no limita por carpeta.
- `exclude_dirs: []` no excluye nada.
- `max_file_size_mb: 0` significa sin límite.
- `max_results: 0` significa sin límite.

---

### `batch.php`

Método: `POST`

Ejecuta varias operaciones de solo lectura en una request.

```json
{
  "project": "nettuno_reales",
  "operations": [
    {
      "id": "mapa",
      "action": "project-map",
      "path": "",
      "max_depth": 2
    },
    {
      "id": "buscar_stock",
      "action": "search-content",
      "query": "calcularStock",
      "extensions": ["php"],
      "context_lines": 2
    },
    {
      "id": "leer_config",
      "action": "read",
      "path": "config/app.php",
      "mode": "full"
    }
  ]
}
```

Acciones soportadas:

- `list`
- `tree`
- `stat`
- `read`
- `read-multiple`
- `search-files`
- `search-content`
- `project-map`

## Recomendación de uso para nimach_gpt_dev

Flujo robusto sugerido:

1. `projects.php` para verificar que el proyecto existe y no está bloqueado.
2. `project-map.php` como primer request real del prompt.
3. `search-files.php` para ubicar archivos candidatos.
4. `search-content.php` para encontrar referencias concretas.
5. `read.php` o `read-multiple.php` para leer archivos o rangos.
6. `stat.php` con `include_hash:true` antes de entregar parches críticos, para dejar huella del estado leído.

## Limitaciones intencionales

- No escribe archivos.
- No borra archivos.
- No ejecuta comandos shell.
- No hace git pull, git diff ni git status.
- No usa base de datos.
- No cachea el mapa.
- No indexa contenido en segundo plano.

Esto reduce superficie de ataque y evita que `migpt` modifique el entorno por API.
