Commit Graph
71 Commits
Author SHA1 Message Date
yeuimu 07836c0165 feat(plugin): dynamic CSP connect-src from plugin manifests
Bundle plugins run inside the base page (not a sandboxed iframe), so their
declared apiOrigins must be in the PAGE's connect-src. Previously the page
CSP was hardcoded static — plugins connecting to new APIs required a code
change + rebuild.

- GET /api/plugin/csp-origins: union of all plugins' manifest apiOrigins
- [[...slug]].tsx getServerSideProps: fetches origins via ssrApi, merges
  with static fallbacks ('self' + 8001 hosts), builds CSP dynamically
- PUT /api/plugin/:pluginId accepts apiOrigins (merged into manifest JSON)
- CLI: plugin csp list / plugin csp set <id> --origins '[...]'
- @DisabledPermission on plugin GET/PUT routes (default-deny guard blocked
  PAT auth); ownership still enforced via manageablePluginCreatedBy()
2026-08-14 05:48:56 +00:00
yeuimu 5ed6569535 merge: plugin CLI commands + base mount + CSP apiOrigins + developer whitelist 2026-08-14 02:50:02 +00:00
yeuimu bc8c76851d docs(skill): add plugin module to SKILL.md + routing rules + description
- Module map: new Plugins row (list/install/uninstall, dev allow/revoke)
- Routing rules: 3 new plugin intents (custom UI, allow devs, external API)
- Description: mention dynamic plugins + dev whitelist + CSP
2026-08-13 15:39:56 +00:00
yeuimu 49836d2655 docs: add plugin CLI commands to skill reference 2026-08-13 15:29:41 +00:00
yeuimu 3eb66513ea feat(plugin): developer whitelist CLI + idempotent backend
- CLI: plugin dev list/allow/revoke (userId or email)
- Backend: PluginDeveloperService.addDeveloper is now idempotent
  (returns existing record instead of unique-constraint 500)
- Backend: removeDeveloper silently no-ops on P2025 (not found)
- Controller: route api/plugin-developers (avoids :pluginId collision),
  @DisabledPermission so admin check is the sole gate
2026-08-13 15:07:32 +00:00
yeuimu 1708e7997a feat: form-submitted trigger multi-form dropdown + skill/docs sync 2026-08-12 06:22:30 +00:00
yeuimu 73998173a8 docs(skill): update formSubmitted trigger docs for multi-form support
Reflect the formId(formId) -> formIds[] change across skill + CLI + docs:
- skill api-reference/trigger-types.md: formIds array config + legacy note
- skill guides (automation-guide.md, cli-reference.md): --form-ids <csv>
- inkreach-cli: add --form-ids option (csv parse), keep --form-id legacy
- docs/automation/triggers.md: P1 formSubmitted marked done
- docs/automation/README.md: formSubmitted config fields updated
2026-08-12 03:59:12 +00:00
yeuimu ef013690f3 feat(workflow): expose trigger user role to script actions
Scripts can now branch on WHO triggered the workflow and their role in the
base, without an extra API call (the workflow token has no role-read scope).

New triggerInput fields (user-initiated triggers only: buttonClick /
recordCreated / recordUpdated / recordCondition / formSubmitted):
- _triggerUserRoles: string[]  (enabled role display names in this base)
- _triggerUserIsAdmin: boolean (space owner / AM admin / AM-disabled)

Absent for scheduledTime / webhook (no user context).

Implementation:
- trigger-user-info.ts: resolveTriggerUserInfo(prisma, baseId, userId) —
  standalone, unit-tested (8 tests). Mirrors the admin logic in
  AuthorityMatrixPermissionService but returns only role names + bool.
- workflow-runner.service.ts: resolve once at first action node, merge into
  enrichedInput (both execute() and test() paths).
- skill action-types.md: document the fields + script branching example.
2026-08-11 10:08:12 +00:00
yeuimu cf25c8ff93 feat(cli): support --dependencies for script actions
- action add/update: new --dependencies <json> option
- parseDependencies accepts JSON, name@version shorthand, or bare names
- update is incremental; --dependencies replaces the whole array
- docs: deployment/systemd.md + skill SKILL/action-types/development
  document the npm-deps feature and the service-PATH requirement
  (spawn npm ENOENT without nvm bin dir on PATH)
2026-08-11 05:51:27 +00:00
yeuimu aff4d70b71 chore(cli): rebuild dist for search[] tuple fix 2026-08-07 18:44:54 +00:00
yeuimu e5975fe5bc docs(skill): add filter operator reference by field type
Add comprehensive operator-to-field-type mapping table covering:
- text/number/boolean/date base operators
- select/link/user field-specific operators (isAnyOf, hasAnyOf, etc.)
- date sub-operators (today, pastWeek, exactDate, etc.)
- conjunction (and/or) + nesting
- Warning: isAnyOf not valid for text fields — use OR conjunction
2026-08-07 18:00:37 +00:00
yeuimu 6527602272 fix(cli): search param uses search[] tuple format
The records API requires search[]=value (tuple), not search=value
(string). Without this, the CLI returned 400 'expected tuple, received
string'. Same fix already exists in the workflow getRecords action.
2026-08-07 17:55:03 +00:00
yeuimu e1d6b03a61 fix: getRecords action page→take/skip + prisma engine fix + CLI fixes
- getRecords automation action: translate page/pageSize to skip/take
  before calling the records API (which ignores page/pageSize, causing
  pagination to always return first 100 records)
- Add postbuild script to restore correct prisma engine binary after
  nest build (which generates an incompatible engine causing SIGSEGV)
- CLI fixes (from earlier commits):
  - deleteRecords: query params instead of JSON body
  - deleteTable: add /base/{baseId} prefix
2026-08-07 16:55:18 +00:00
yeuimu 0f3c88126c fix(cli): table delete uses correct route /api/base/{baseId}/table/{tableId}
CLI was sending DELETE /api/table/{tableId} but the only
controller is at api/base/:baseId/table, causing 404.
2026-08-07 10:55:16 +00:00
yeuimu be21be9465 fix(cli): batch record delete sends recordIds as query params
The API controller reads recordIds from @Query(), not @Body.
CLI was sending { records: ids } as JSON body, causing:
'expected array, received undefined at "recordIds"'

Fixed: rename deleteRecord→deleteRecords, send recordIds as
repeated query params (?recordIds=rec1&recordIds=rec2).
2026-08-07 10:32:25 +00:00
yeuimu 0891bda134 feat(cli): add inkreach-teable plugin commands
plugin list: list registered plugins (id/name/status/runtimeType)
plugin register: register by URL (--name --url --positions)
plugin config list: list base configs (pluginId/tableId/enabled/form/write)
plugin config enable/disable: enable/disable per table or base-wide

Added 5 client methods: getPlugins, registerPlugin, listPluginConfigs,
upsertPluginConfig for CRUD.
2026-08-06 09:03:04 +08:00
yeuimu 584b75ba69 fix(skill): trim inkreach-teable description under 1024-char limit
The skill description was 1033 chars, exceeding pi's 1024-char limit and
causing a 'Skill conflicts: description exceeds 1024 characters' warning,
which prevents the skill from loading/triggering reliably.

Shortened to 990 chars while preserving all trigger-relevant keywords
(inkreach-teable/Teable, ID patterns bseXXX/tblXXX/..., configure
tables/automations, dev/deploy, systemd). Also fixed YAML folded-scalar
artifacts that injected stray spaces after slashes
('/ formSubmitted', '/ httpRequest') by avoiding line breaks after '/'.
2026-08-05 09:22:26 +00:00
yeuimu 3e06a10fe0 skill(iter-1): fix CLI getRecords flag + docs from eval feedback
Ran 4 end-to-end evals (skill-creator flow): all 23 assertions passed (100%).
The evals exposed 3 issues, now fixed:

1. CLI bug: getRecords/createRecord/updateRecord --target-table flag was
   read as opts['target-table'] but commander stores it camelCase
   (opts.targetTable). Added a pick() helper accepting both forms.
2. trigger-types.md: buttonClick output said record.fields.* implying all
   fields; actually record.fields only contains the button field's count.
   Documented the back-channel API fetch pattern for other fields.
3. automation-guide.md: documented that 'workflow test' uses mock input
   with empty fields, so upstream outputs are absent in test mode — use
   real fire for data-dependent validation.

Also: corrected button field options (workflow.id object, not workflowId).
2026-08-05 10:48:33 +08:00
yeuimu d3790ab856 refactor: rename skill 'inkreach-teable-ops' -> 'inkreach-teable'
Rename the skill directory and update all references (SKILL.md frontmatter
name, AGENTS.md, design doc, install.sh). Git tracks this as a rename so
history is preserved.
2026-08-05 10:35:04 +08:00
yeuimu 3810c33d69 refactor: rename CLI command 'inkreach' -> 'inkreach-teable'
Rename the command (and its config namespace) to match the project name:

- bin:          inkreach        -> inkreach-teable
- program name: inkreach        -> inkreach-teable
- config dir:   ~/.inkreach/    -> ~/.inkreach-teable/
- env vars:     INKREACH_*      -> INKREACH_TEABLE_*
- all docs (SKILL.md, guides, api-reference, AGENTS.md, design doc, install.sh)

Unchanged (intentional):
- npm package name: @inkreach/teable-cli
- package directory: packages/inkreach-cli/
- skill name: inkreach-teable-ops
- organization/authors: 'inkreach' (npm scope @inkreach)

Existing config auto-migrated (~/.inkreach -> ~/.inkreach-teable). Verified
end-to-end: auth status, workflow list (636), build clean.
2026-08-05 10:14:26 +08:00
yeuimu 5fa843df05 feat: add inkreach CLI + inkreach-teable-ops skill
A self-built CLI and companion agent skill for operating a deployed
inkreach-teable instance — configuring tables, fields, records, views, and
the project's OWN automation engine.

Why not the official 'teable' CLI:
  inkreach-teable's automation is self-built with a different contract:
  - conditions (not filter), fieldIds (not watchFieldIds)
  - recordCondition (not recordMatchesConditions)
  - webhook route /api/webhook/{baseId}/{wfId} (not the /base//workflow/ form)
  - scheduledTime backend honors only timing.type + timing.interval
  The official CLI targets the upstream contract and 404s/misconfigures here.
  Table/field/record/view APIs ARE upstream-compatible, but automation is not.

inkreach CLI (packages/inkreach-cli/):
  - Node.js + commander, zero extra runtime deps
  - Uses node:http (NOT fetch — Node 24 fetch drops Authorization header)
  - Commands: auth (login/status/token), base/table/field/record/view,
    workflow (list/get/create/update/delete/activate/deactivate/test),
    trigger set (8 types, builds correct config keys), action add/update/delete
    (6 types), secret, runs (list/get/rerun), fire (button-click/webhook), sql
  - --json mode for agent parsing; GET->modify->PUT whole-graph for node edits
  - Verified end-to-end: create workflow -> set webhook trigger -> add script
    action -> activate -> fire webhook -> runs list (succeeded)

inkreach-teable-ops skill (.agents/skills/inkreach-teable-ops/):
  - SKILL.md entry: module map, routing rules, 11 key constraints (the real
    contract keys), execution rules, error recovery
  - guides/: cli-reference, automation-guide, tables-fields, instance-access,
    development (build/restart, known gotchas)
  - api-reference/: trigger-types (8 triggers, exact config), action-types
    (6 actions, sandbox globals), field-types (21 types incl. Button)
  - metadata.json + install.sh
2026-08-05 02:04:39 +08:00