- table get/update: 改用真实路由 /api/base/:baseId/table/:tableId(/name)
- view get/update/delete: table 域路由;view update 实现文档承诺的
--filter/--sort/--group/--column-meta(sort 自动包装 sortObjs)
- record create --fields 自动包装 {records:[{fields}]}
- record delete 单条走单删端点(修复单值 query 解析成 string 的 400),
支持位置参数;record list 加为 record get 别名
- record get-one / record get --record-id 走 table 域路由
- 移除 sql 命令:后端无 SQL 查询 API(404),技能文档 5 处同步改写
- plugin 技能 dev-workflow 内联 known-good webpack.config
(禁止 output.library.type=iife,评估轨迹中 with_skill 组也反复踩坑)
112 lines
12 KiB
Markdown
112 lines
12 KiB
Markdown
---
|
|
name: inkreach-teable
|
|
description: >-
|
|
Use this skill for hands-on work on a deployed inkreach-teable instance (a self-hosted Teable fork with its own automation engine — not teable cloud): adding or altering fields and views, cleaning or bulk-updating records, aggregating table data (monthly counts, group-bys), building automations that react to record changes, form submissions, buttons, or schedules and that can call external APIs, storing API keys as secrets so they aren't hardcoded, checking run history, and configuring change-summary email subscriptions. Trigger whenever the user names a business table (工单表/订单表/成员表, or any bse/tbl/fld/rec/viw/wfl ID) and wants to configure, query, script, automate, or subscribe to it — even if they never say "teable". Also use for this instance's SQL/REST access. Don't use for teable cloud pricing/comparisons, generic SQL/MySQL tuning, standalone Python/npm/CLI scripting, or unrelated webhook integrations.
|
|
---
|
|
|
|
# inkreach-teable operations
|
|
|
|
Operate a deployed inkreach-teable instance via the `inkreach-teable` CLI.
|
|
Respond in the user's language. Keep answers concise and action-oriented.
|
|
|
|
> **Critical**: the automation engine is **self-built and differs from official
|
|
> teable** — the official `teable` CLI corrupts or 404s on automations here.
|
|
> Exact key-name differences are in [Key Constraints](#3-key-constraints).
|
|
|
|
## 1. Prerequisites
|
|
|
|
- Install the CLI if missing: `npm i -g @inkreach/inkreach-teable` (public npm package). Offline fallback: `bash scripts/install.sh` relative to this skill dir in a repo clone.
|
|
- **Configure once**: `inkreach-teable auth login --endpoint https://table.inkreach.cc --token <PAT> [--base-id bseXXX]`; verify with `auth status`. PAT comes from `auth token create --name x` (full token shown **once**) or the web UI (Settings → Personal Access Tokens).
|
|
- `--json` on any command returns raw JSON (for agent parsing). Fallback for unknown commands: `inkreach-teable <cmd> --help`.
|
|
- **Read on demand**: consult the guide linked for your module when doing non-trivial work — no need to read everything up front.
|
|
|
|
## 2. Module & Command Navigation
|
|
|
|
| Module | What it solves | Entry commands | Detail doc |
|
|
|--------|---------------|----------------|------------|
|
|
| Tables & Fields | Create/modify structure; **inspect select-choice constraints** | `table create`, `field create`, `field list --with-options`, `field get` | [tables-fields.md](guides/tables-fields.md), [field-types.md](api-reference/field-types.md) |
|
|
| Records | Read/write row data | `record get` (alias `record list`), `record create/update/delete` | [tables-fields.md § Records](guides/tables-fields.md) |
|
|
| Views | Filtered/sorted perspectives | `view create/update` | [tables-fields.md § Views](guides/tables-fields.md) |
|
|
| View presets | View-scoped shared filter/sort bundles + per-user personal config, applied via toolbar | `preset create/update/list/delete` | [tables-fields.md § View Presets](guides/tables-fields.md) |
|
|
| Automation | Event-driven workflows | `workflow *`, `trigger set`, `action add` | [automation-guide.md](guides/automation-guide.md), [trigger-types.md](api-reference/trigger-types.md), [action-types.md](api-reference/action-types.md) |
|
|
| Secrets | API keys for script actions | `secret set/list/delete` | [automation-guide.md § Secrets](guides/automation-guide.md) |
|
|
| Execution History | Run results / rerun failures | `runs list/get/rerun` | [automation-guide.md § Testing](guides/automation-guide.md) |
|
|
| Manual Trigger | Test button-click/webhook | `fire button-click`, `fire webhook` | [automation-guide.md § Testing](guides/automation-guide.md) |
|
|
| Direct REST API | Integrate external scripts/services; endpoints the CLI lacks; script actions calling back | `curl` / `fetch` + `Authorization: Bearer <PAT>` | [rest-api.md](api-reference/rest-api.md) |
|
|
| Plugins | Dynamic plugins, dev whitelist, CSP | `plugin *` | [cli-reference.md § plugin](guides/cli-reference.md) |
|
|
| Subscriptions | Record digest/instant email | `subscription *` | [subscription.md](guides/subscription.md) |
|
|
| Dev/Deploy | Build, restart, gotchas | systemd / pnpm | [development.md](guides/development.md) |
|
|
|
|
Full command syntax: [cli-reference.md](guides/cli-reference.md). Instance access & credentials: [instance-access.md](guides/instance-access.md).
|
|
|
|
### Routing rules
|
|
|
|
| User intent | Correct approach | Do NOT |
|
|
|-------------|------------------|--------|
|
|
| Configure an automation | `workflow create` → `trigger set` → `action add` → `activate` | Editing DB rows |
|
|
| React to new records / field changes | `recordCreated` / `recordUpdated --field-ids` | Polling in a script; `recordCondition` ignores fields |
|
|
| React to a condition matching | Trigger `recordCondition` (NOT recordMatchesConditions) | Official-teable key names |
|
|
| Button click starts a workflow | `buttonClick` trigger + Button field (`options.workflow` object) | Other trigger types |
|
|
| Receive external HTTP | `webhook`; test via `fire webhook` | Expecting auth (backend ignores it) |
|
|
| Schedule recurring job | `scheduledTime` (only `timing.type` + `interval` honored). If the user asks for specific clock times or weekdays, say up front that the backend ignores them and propose an interval instead | triggerTime/weekdays (ignored silently — configuring them looks fine but never fires as intended) |
|
|
| Per-row transformation | `script` action reading `triggerInput` | Row-by-row record API |
|
|
| Send notification | `sendNotification` (in-app) | `sendEmail` (needs SMTP) unless email required |
|
|
| **Inspect select-choice constraints** | `field list --with-options`, `field get <tbl> <name>`, `field visible-choices` | `--json` + manual filtering |
|
|
| **Write a select-field value** | Verify the value exists in choices first (`field list --with-options`); need a new value → `field update --options` to add the choice, then write | Blind `record update` (400, or typecast silently resolves to null / mutationApplied=false — it never creates choices) |
|
|
| Read records for later writes | `record get` / `record list` (returns record IDs) | Official-teable SQL APIs (none here) |
|
|
| Analytics / aggregation | `record get --filter` + compute, script action, or grouped grid view | `sql` — this deployment has NO SQL query API (CLI 0.1.5 removed the dead command) |
|
|
| Store an API key for scripts | `secret set` → `process.env.NAME` | Hardcoding |
|
|
| Workflow didn't run | `runs list --status failed` → `runs get` | Blind re-activate |
|
|
| Call the instance from external code / a route the CLI lacks | Direct REST: `Authorization: Bearer <PAT>` + routes in [rest-api.md](api-reference/rest-api.md); unknown route → run the nearest CLI command with `--debug` and copy its request | Official teable API docs (different automation contract) |
|
|
|
|
## 3. Key Constraints
|
|
|
|
These differ from official teable and from the (stale) `docs/automation/triggers.md`.
|
|
|
|
1. **Filter key is `conditions`** (NOT `filter`): `trigger set --conditions '<json>'`, shape `{conjunction, filterSet:[{fieldId, operator, value}]}`.
|
|
2. **Watch-fields key is `fieldIds`** (NOT `watchFieldIds`); `[]` = watch all fields.
|
|
3. **Trigger category `recordCondition`** (NOT `recordMatchesConditions`).
|
|
4. **`scheduledTime` honors only `timing.type` + `timing.interval`** — triggerTime/weekdays/daysOfMonth/starting/ending/tz are ignored; `weeks` is hardcoded to Sunday.
|
|
5. **Webhook route is `/api/webhook/{baseId}/{workflowId}`** (no `/base/` segment); `authorization` config is UI-only, backend never validates. Fire: `fire webhook <baseId> <wfId>`.
|
|
6. **Node updates are whole-graph replacement** — `trigger set` / `action add/update/delete` do GET→modify→PUT internally; never hand-edit partial graphs.
|
|
7. **`activate` creates a snapshot** — node changes take effect only after re-activating. `hasDraft: true` = unactivated changes.
|
|
8. **`workflow delete` is soft** (cascades to nodes, tokens, trigger unregister); test workflows should be `deactivate`d.
|
|
9. **Secrets are write-only** — `secret list` never returns values; scripts read `process.env.<NAME>`.
|
|
10. **Button field binding**: `options.workflow` is an **object** `{id, name?}`, not a bare id string. The field's `isActive` snapshot can go stale; the API validates the workflow's DB `isActive` at click time (deactivated → 400).
|
|
11. **Script sandbox** has NO `fs`/`eval`/`Function`, but has `triggerInput`, `console`, `fetch`, `process.env` (secrets + `AUTOMATION_TOKEN` + `PUBLIC_ORIGIN`), and a controlled `require`. Call back into the instance via `triggerInput._accessToken` + `triggerInput._apiBaseUrl`. **npm deps**: declare with `action add/update --dependencies '[{"name":"axios","version":"1.6.0"}]'` (or `axios@1.6.0,dayjs`). Requires `npm` on the backend **service** PATH — systemd user units default to a PATH that omits the nvm bin dir, so deps fail with `spawn npm ENOENT`; fix by adding `Environment=PATH=<nvm-bin>:/usr/local/sbin:...` to `teable-backend.service`.
|
|
12. **Field options updates go through the convert API** — `field update --options` handles this; the plain PATCH update API strips `options`.
|
|
13. **No SQL query API exists** — the backend has no SQL endpoint; the CLI `sql` command was removed in 0.1.5. Aggregate via `record get --filter` + a script action, or a grouped grid view. Also: `table get/update` are base-scoped (`--base-id`, defaults to the configured base) and `view get/update/delete` + `record get-one` are table-scoped (`--table-id`).
|
|
|
|
## 4. Quick Syntax
|
|
|
|
```bash
|
|
inkreach-teable auth login --endpoint https://table.inkreach.cc --token <PAT> # once
|
|
inkreach-teable table create --name "Tasks" --fields '[{"name":"Title","type":"text"},{"name":"Status","type":"singleSelect","options":{"choices":["Todo","Done"]}}]'
|
|
inkreach-teable record create --table-id tblXXX --fields '{"Title":"a"}' # 单条;批量用 --records '[{"fields":{...}}]'
|
|
inkreach-teable record list --table-id tblXXX [--filter '<json>'] # 查询/分页(= record get)
|
|
inkreach-teable record delete --table-id tblXXX recXXX [recYYY ...] # 也可 --record-ids 'recA,recB'
|
|
inkreach-teable workflow create --name "On Go click" # → wflXXX
|
|
inkreach-teable trigger set wflXXX --type buttonClick --table-id tblXXX --field-ids '["fldXXX"]'
|
|
inkreach-teable action add wflXXX --type script --code 'return triggerInput.record.fields'
|
|
inkreach-teable workflow activate wflXXX
|
|
inkreach-teable fire button-click tblXXX recXXX fldXXX && inkreach-teable runs list wflXXX
|
|
# webhook 触发器的外部调用地址(无鉴权,激活后生效): {endpoint}/api/webhook/{baseId}/{workflowId} —— 用 fire webhook <baseId> <wflXXX> 本地测试
|
|
```
|
|
|
|
## 5. Common Errors & Recovery
|
|
|
|
| Symptom | Cause | Fix |
|
|
|---------|-------|-----|
|
|
| `MISSING_BASE_ID` | No base id resolved | Pass `--base-id`, or `auth login --base-id` |
|
|
| `401` / access denied | Token invalid/expired or lacks scope | `auth status`; recreate PAT |
|
|
| `403` | Base role too low | Grant owner/creator role in web UI |
|
|
| Workflow never fires | Not activated / trigger misconfigured | `workflow get` → `isActive`; verify trigger type + tableId/fieldIds |
|
|
| `scheduledTime` wrong time | Backend ignores most timing fields | Only `timing.type`+`interval` work |
|
|
| button-click 400 "not active" | Workflow deactivated since field created | `workflow activate <id>` |
|
|
| `runs list` shows failed | Action error | `runs get <wfId> <execId>` → `nodeResults[].error` |
|
|
| Script deps fail `spawn npm ENOENT` | `npm` not on service PATH | See Key Constraint 11 |
|
|
| Record write 400 "does not meet the current row conditions" | Value violates choice `visibilityFilter` | `field visible-choices` to see allowed options |
|
|
| `sql: unknown command` / 404 on a SQL endpoint | No SQL query API on this deployment | Aggregate via script action or `record get --filter` |
|
|
| `record list` works like `record get` | Intentional alias (CLI ≥0.1.5) | — |
|
|
| Select-field write "succeeds" but value unchanged (or becomes null) | Value not in choices — without typecast the API 400s; with typecast it resolves to null and no-ops (`mutationApplied=false`), never creates the choice | `field list --with-options` to confirm; `field update --options` to add the choice, then write |
|