feat(cli+skill): make documented field UX real + fix skill doc drift
CLI (packages/inkreach-cli):
- new src/lib/field-normalize.ts: type aliases (sel/num/text/mul/…),
select string-choices -> {name}, compact --fields 'Name:type:choices'
expansion, smart type inference from --options shape / --name
(--type now optional), name->ID resolution for foreignTableName /
linkFieldName / lookupFieldName (incl. link-field foreignTableId
backfill + unknown-key stripping), rating/number/button required-
option defaults
- field create: +--description/--lookup-options/--is-lookup
- field update --options + table create --fields route through the
normalizer; DEFAULT_ENDPOINT :3000 -> :3003
- 20 unit tests (field-normalize.spec.ts, vitest); live-verified:
string choices, alias, foreignTableName, lookup-by-names, compact
format, inference (priority->singleSelect, max:5->rating)
Skill docs (.agents/skills/inkreach-teable):
- ports :3000 -> :3003 everywhere (backend real port; :3000 is an
unrelated container on this host)
- remove dead hr_admin account; note throwaway signup + real admin
- plugin register: actual URL-based flags; document plugin csp
list/set; view/dashboard install requires config enable first
- field-types.md marked verified-2026-08 (aliases/inference/name
resolution now implemented + tested)
- development.md: webpack dist/index.js cache trap; PGPASSWORD
placeholder instead of wrong literal
This commit is contained in:
@@ -31,7 +31,7 @@ Respond in the user's language. Keep answers concise and action-oriented.
|
||||
## 1. Prerequisites & Constraints
|
||||
|
||||
- All operations use the `inkreach-teable` CLI. Install via `bash scripts/install.sh` (relative to this skill dir) if `inkreach-teable` is not found.
|
||||
- **Endpoint + token**: configure once with `inkreach-teable auth login --endpoint <url> --token <PAT>`. Default endpoint is `http://localhost:3000`. Verify with `inkreach-teable auth status`.
|
||||
- **Endpoint + token**: configure once with `inkreach-teable auth login --endpoint <url> --token <PAT>`. Default endpoint is `http://localhost:3003`. Verify with `inkreach-teable auth status`.
|
||||
- **Getting a PAT**: `inkreach-teable auth token create --name my-cli` (returns the full token **only once**). Scopes default to automation+table+record read/write. Or create via the web UI (Settings → Personal Access Tokens).
|
||||
- **`--base-id`**: omit if a default was set via `auth login`; CLI uses it automatically. Ask user only if a command fails with MISSING_BASE_ID.
|
||||
- **`--json` mode**: add `--json` to any command for raw JSON output (for agent parsing).
|
||||
@@ -82,7 +82,7 @@ Respond in the user's language. Keep answers concise and action-oriented.
|
||||
|
||||
```bash
|
||||
# Configure access (once)
|
||||
inkreach-teable auth login --endpoint http://localhost:3000 --token <PAT>
|
||||
inkreach-teable auth login --endpoint http://localhost:3003 --token <PAT>
|
||||
|
||||
# Create a table
|
||||
inkreach-teable table create --name "Tasks" --base-id bseXXX \
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
Complete reference of all Teable field types, aliases, option shapes, and smart inference rules.
|
||||
|
||||
> ✅ **Verified 2026-08**: aliases, string choices, compact `--fields` format, smart
|
||||
> inference, and name resolution (`foreignTableName`/`linkFieldName`/`lookupFieldName`)
|
||||
> are implemented in the CLI (`packages/inkreach-cli/src/lib/field-normalize.ts`)
|
||||
> and covered by unit tests (`field-normalize.spec.ts`, 20 cases).
|
||||
|
||||
---
|
||||
|
||||
## Type Overview
|
||||
|
||||
@@ -6,7 +6,7 @@ Complete command reference for `inkreach-teable`. Global options apply to all co
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--endpoint <url>` | Backend URL (default `http://localhost:3000`) |
|
||||
| `--endpoint <url>` | Backend URL (default `http://localhost:3003`) |
|
||||
| `--token <pat>` | Personal Access Token |
|
||||
| `--base-id <id>` | Default base id |
|
||||
| `--json` | Output raw JSON (for agent parsing) |
|
||||
@@ -46,7 +46,9 @@ inkreach-teable table delete <tableId>
|
||||
# field (get/update/delete take <tableId> <fieldId> — 2026-08 fix; old /api/field/:id routes never existed)
|
||||
inkreach-teable field list <tableId>
|
||||
inkreach-teable field get <tableId> <fieldId>
|
||||
inkreach-teable field create --table-id <tid> --name <n> --type <t> [--options '<json>']
|
||||
inkreach-teable field create --table-id <tid> --name <n> [--type <t|alias>] [--options '<json>'] \
|
||||
[--description <d>] [--lookup-options '<json>'] [--is-lookup]
|
||||
# --type optional: inferred from --options shape / --name when omitted
|
||||
inkreach-teable field update <tableId> <fieldId> [--name <n>] [--options '<json>'] # --options goes via convert API
|
||||
inkreach-teable field visible-choices <tableId> <recordId> <fieldId> # evaluate select-choice visibilityFilter
|
||||
inkreach-teable field delete <tableId> <fieldId>
|
||||
@@ -174,8 +176,11 @@ Manage plugins and developer whitelist.
|
||||
# List plugins registered in the base
|
||||
inkreach-teable plugin list
|
||||
|
||||
# Register a plugin (set runtimeType, positions, logo)
|
||||
inkreach-teable plugin register --name <name> --positions '["base","panel"]'
|
||||
# Register a URL-served plugin (runtimeType=url; status published immediately)
|
||||
# positions: "base"|"panel"|"view"|"dashboard"|"contextMenu"
|
||||
inkreach-teable plugin register --url <url> --name <name> [--positions '["panel"]'] [--logo <url>] [--description <d>]
|
||||
# Bundle (upload) plugins use a different flow — see skill guides/tables-fields.md
|
||||
# or api docs: create kebab-id plugin (developer whitelist) → upload → admin publish.
|
||||
|
||||
# Developer whitelist (admin only)
|
||||
inkreach-teable plugin dev list
|
||||
@@ -184,12 +189,19 @@ inkreach-teable plugin dev revoke <userIdOrEmail> # remove
|
||||
|
||||
# Install / uninstall (creates a base-level mount node)
|
||||
inkreach-teable plugin install --plugin <pluginId> --name "My Plugin" --position base
|
||||
# ⚠️ For view/dashboard-position plugins, run `plugin config enable` BEFORE
|
||||
# install, or the install API returns 403 RESTRICTED_RESOURCE
|
||||
# 'Plugin is not enabled for this base'.
|
||||
inkreach-teable plugin installs # list installs in current base
|
||||
inkreach-teable plugin uninstall --install <installId>
|
||||
|
||||
# Enable/disable plugins
|
||||
inkreach-teable plugin config enable --plugin <pluginId>
|
||||
inkreach-teable plugin config disable --plugin <pluginId>
|
||||
|
||||
# CSP apiOrigins (external origins plugins may fetch)
|
||||
inkreach-teable plugin csp list
|
||||
inkreach-teable plugin csp set <pluginId> --origins '["http://192.168.x.x:8001"]'
|
||||
```
|
||||
|
||||
Developer whitelist is admin-only (requires `user.isAdmin=true`). Routes:
|
||||
|
||||
@@ -13,10 +13,10 @@ inside NestJS is unstable and will hang or OOM-crash.
|
||||
|
||||
| Service | Command | Port | Mode |
|
||||
|---------|---------|------|------|
|
||||
| `teable-backend.service` | `node dist/index.js` | `:3000` | `NODE_ENV=production`, `BACKEND_SKIP_NEXT_START=true` |
|
||||
| `teable-backend.service` | `node dist/index.js` | `:3003` | `NODE_ENV=production`, `BACKEND_SKIP_NEXT_START=true` |
|
||||
| `teable-frontend.service` | `next start -p 3002 -H 0.0.0.0` | `:3002` | `NODE_ENV=production` |
|
||||
|
||||
Users access `:3002`; the backend `:3000` serves the API only.
|
||||
Users access `:3002`; the backend `:3003` serves the API only.
|
||||
|
||||
## Build & Restart
|
||||
|
||||
@@ -37,7 +37,7 @@ systemctl --user restart teable-frontend.service
|
||||
Browser cache is aggressive — hard-refresh (Ctrl+Shift+R) after a rebuild.
|
||||
|
||||
### Recover from OOM crash
|
||||
If `:3000` is unreachable but systemd says `active`:
|
||||
If `:3003` is unreachable but systemd says `active`:
|
||||
```bash
|
||||
systemctl --user stop teable-backend.service
|
||||
pkill -9 -f 'dist/index.js'
|
||||
@@ -46,6 +46,13 @@ systemctl --user start teable-backend.service
|
||||
|
||||
## Known Gotchas (from real debugging)
|
||||
|
||||
### Webpack cache may not rewrite `dist/index.js` after a workspace package rebuild
|
||||
After rebuilding a workspace package (e.g. `@teable/openapi` dist), `pnpm build` in
|
||||
`apps/nestjs-backend` can report "compiled successfully" while leaving `dist/index.js`
|
||||
untouched (node_modules paths are treated as immutable cache inputs). Symptom: backend
|
||||
behavior unchanged after a code change. Fix: `rm apps/nestjs-backend/dist/index.js`
|
||||
then rebuild, and verify with `grep '<your-new-string>' dist/index.js`.
|
||||
|
||||
### Node v24 fetch drops the Authorization header
|
||||
The global `fetch()` on Node v24 (undici) drops the `Authorization` request
|
||||
header in certain cases (redirects, proxies). **Use `node:http`/`node:https`**
|
||||
@@ -121,16 +128,16 @@ due to the auth-header bug. Test workflows are **deactivated, not deleted**
|
||||
|
||||
```bash
|
||||
# Count workflows by active state
|
||||
PGPASSWORD=teable psql -h localhost -U teable -d teable -c \
|
||||
PGPASSWORD=<ask-maintainer> psql -h localhost -U teable -d teable -c \
|
||||
"SELECT is_active, count(*) FROM workflow WHERE deleted_time IS NULL GROUP BY is_active;"
|
||||
|
||||
# Find button fields and their bound workflows
|
||||
PGPASSWORD=teable psql -h localhost -U teable -d teable -c \
|
||||
PGPASSWORD=<ask-maintainer> psql -h localhost -U teable -d teable -c \
|
||||
"SELECT id, name, options->'workflow'->>'id' AS wf_id, options->'workflow'->>'isActive' AS active
|
||||
FROM field WHERE type='button';"
|
||||
|
||||
# Recent executions
|
||||
PGPASSWORD=teable psql -h localhost -U teable -d teable -c \
|
||||
PGPASSWORD=<ask-maintainer> psql -h localhost -U teable -d teable -c \
|
||||
"SELECT id, workflow_id, status, started_at FROM workflow_execution
|
||||
ORDER BY started_at DESC LIMIT 10;"
|
||||
```
|
||||
|
||||
@@ -8,29 +8,30 @@ endpoint/ports for your own deployment.
|
||||
|
||||
| Service | URL / Port | Mode | Purpose |
|
||||
|---------|-----------|------|---------|
|
||||
| Backend API | `http://localhost:3000` | production (`NODE_ENV=production`) | REST API, automation engine, websocket |
|
||||
| Backend API | `http://localhost:3003` | production (`NODE_ENV=production`) | REST API, automation engine, websocket |
|
||||
| Frontend | `http://localhost:3002` | production | End-user web UI (Next.js) |
|
||||
| PostgreSQL | `localhost:5432` | — | Database (db: `teable`, user: `teable`) |
|
||||
| Redis | `localhost:6379` | — | BullMQ queue for automation runs, distributed lock |
|
||||
|
||||
- The frontend reads `SOCKET_PORT=3000` from `.env` to point its websocket at the backend. Don't let it fall back to `3001`.
|
||||
- End users browse `:3002`. The backend `:3000` is the API only (`BACKEND_SKIP_NEXT_START=true` disables the embedded Next server).
|
||||
- The frontend reads `SOCKET_PORT` from `.env` to point its websocket at the backend — verify it equals the backend port (3003 on this host), not the default 3001.
|
||||
- End users browse `:3002`. The backend `:3003` is the API only (`BACKEND_SKIP_NEXT_START=true` disables the embedded Next server).
|
||||
- ⚠️ Port map differs from upstream Teable docs (:3000) — on this host `:3000` is held by an **unrelated container** (`inkreach-web`). Always verify with `ss -tlnp` before assuming.
|
||||
|
||||
## Health Checks
|
||||
|
||||
```bash
|
||||
# Backend API up?
|
||||
curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/api/auth/signin -X POST \
|
||||
curl -s -o /dev/null -w '%{http_code}' http://localhost:3003/api/auth/signin -X POST \
|
||||
-H 'Content-Type: application/json' -d '{}' # expect 401 (endpoint exists, bad creds)
|
||||
|
||||
# Frontend up?
|
||||
curl -s -o /dev/null -w '%{http_code}' http://localhost:3002 # expect 307 or 200
|
||||
|
||||
# Ports listening?
|
||||
ss -tlnp | grep -E ':3000|:3002|:5432|:6379'
|
||||
ss -tlnp | grep -E ':3003|:3002|:5432|:6379'
|
||||
```
|
||||
|
||||
If `:3000` is unreachable but systemd shows `active`, the worker likely OOM-crashed while the `pnpm` parent stayed alive:
|
||||
If `:3003` is unreachable but systemd shows `active`, the worker likely OOM-crashed while the `pnpm` parent stayed alive:
|
||||
```bash
|
||||
systemctl --user stop teable-backend.service
|
||||
pkill -9 -f 'dist/index.js'
|
||||
@@ -58,14 +59,15 @@ Note: `auth token list/create` may require a **session** (browser login) rather
|
||||
|
||||
### Configure the CLI
|
||||
```bash
|
||||
inkreach-teable auth login --endpoint http://localhost:3000 --token <PAT> --base-id bseXXX
|
||||
inkreach-teable auth login --endpoint http://localhost:3003 --token <PAT> --base-id bseXXX
|
||||
inkreach-teable auth status # verify
|
||||
```
|
||||
|
||||
## Reference Credentials (local dev)
|
||||
|
||||
> Never commit real secrets. The reference dev instance uses:
|
||||
> - Admin: `hr_admin@xingchen.tech` / (ask maintainer) — for browser login only.
|
||||
> - ⚠️ The old admin account `hr_admin@xingchen.tech` **no longer exists** (verified 2026-08). Current users: `inkreach@inkreach.pod` (admin) — password: ask maintainer, browser login only.
|
||||
> - Throwaway accounts for testing can be created via `POST /api/auth/signup` (open on this instance).
|
||||
> - Base: `bseeZR7yiDNeMPCa4CN` (人事薪资管理) — the test base with ~600 automations.
|
||||
> - Test table: `tblzPOXQvUruQosKNP5` (has button fields for automation testing).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user