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:
Vendored
+40
-5
@@ -9,6 +9,7 @@ exports.baseResourceCommands = void 0;
|
||||
const commander_1 = require("commander");
|
||||
const ctx_1 = require("../lib/ctx");
|
||||
const output_1 = require("../lib/output");
|
||||
const field_normalize_1 = require("../lib/field-normalize");
|
||||
function baseResourceCommands() {
|
||||
return [baseCmd(), tableCmd(), fieldCmd(), recordCmd(), viewCmd()];
|
||||
}
|
||||
@@ -103,8 +104,20 @@ function tableCmd() {
|
||||
const opts = o;
|
||||
const baseId = (0, ctx_1.requireBaseId)(ctx, opts.baseId);
|
||||
const body = { name: opts.name };
|
||||
if (opts.fields)
|
||||
body.fields = JSON.parse(opts.fields);
|
||||
if (opts.fields) {
|
||||
body.fields = (0, field_normalize_1.normalizeFieldRoArray)(JSON.parse(opts.fields));
|
||||
// Resolve foreignTableName references against existing tables in the base.
|
||||
const fields = body.fields;
|
||||
const tables = await ctx.client.listTables(baseId).catch(() => []);
|
||||
for (const f of fields) {
|
||||
const options = f?.options;
|
||||
if (options && typeof options.foreignTableName === 'string' && !options.foreignTableId) {
|
||||
const t = (0, field_normalize_1.findTableByNameOrId)(tables || [], options.foreignTableName);
|
||||
if (t)
|
||||
options.foreignTableId = t.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
const table = await ctx.client.createTable(baseId, body);
|
||||
if (ctx.json)
|
||||
(0, output_1.printJson)(table);
|
||||
@@ -188,13 +201,34 @@ function fieldCmd() {
|
||||
.description('Create a new field')
|
||||
.requiredOption('--table-id <id>', 'Table id')
|
||||
.requiredOption('--name <name>', 'Field name')
|
||||
.requiredOption('--type <type>', 'Field type (singleLineText, number, singleSelect, link, formula, etc.)')
|
||||
.option('--options <json>', 'Field options JSON (type-specific)')
|
||||
.option('--type <type>', 'Field type — full value (singleLineText, singleSelect, link…) or alias (text, sel, num…). Omitted: inferred from --options shape / --name')
|
||||
.option('--options <json>', 'Field options JSON (type-specific; select choices accept plain strings)')
|
||||
.option('--description <d>', 'Field description')
|
||||
.option('--lookup-options <json>', 'Lookup options JSON (names like linkFieldName/lookupFieldName are resolved to IDs)')
|
||||
.option('--is-lookup', 'Mark the field as a lookup field')
|
||||
.action((0, ctx_1.run)(async (ctx, _args, o) => {
|
||||
const opts = o;
|
||||
const body = { name: opts.name, type: opts.type };
|
||||
const body = { name: opts.name };
|
||||
if (opts.options)
|
||||
body.options = JSON.parse(opts.options);
|
||||
if (opts.description)
|
||||
body.description = opts.description;
|
||||
if (opts.lookupOptions)
|
||||
body.lookupOptions = JSON.parse(opts.lookupOptions);
|
||||
if (opts.isLookup)
|
||||
body.isLookup = true;
|
||||
body.type = opts.type
|
||||
? (0, field_normalize_1.resolveFieldType)(opts.type)
|
||||
: (0, field_normalize_1.inferFieldType)(opts.name, body.options);
|
||||
(0, field_normalize_1.normalizeFieldRo)(body);
|
||||
const errors = await (0, field_normalize_1.resolveFieldReferences)(body, {
|
||||
listTables: (baseId) => ctx.client.listTables(baseId),
|
||||
listFields: (tableId) => ctx.client.listFields(tableId),
|
||||
baseId: ctx.baseId,
|
||||
tableId: opts.tableId,
|
||||
});
|
||||
if (errors.length)
|
||||
throw new Error(errors.join('; '));
|
||||
const field = await ctx.client.createField(opts.tableId, body);
|
||||
if (ctx.json)
|
||||
(0, output_1.printJson)(field);
|
||||
@@ -235,6 +269,7 @@ function fieldCmd() {
|
||||
};
|
||||
if (opts.name)
|
||||
body.name = opts.name;
|
||||
(0, field_normalize_1.normalizeFieldRo)(body);
|
||||
const field = await ctx.client.convertField(tableId, fieldId, body);
|
||||
if (ctx.json)
|
||||
(0, output_1.printJson)(field);
|
||||
|
||||
Reference in New Issue
Block a user