feat(cli): base/space 命令 + 执行守则 + eval harness 入仓 + 多轮 eval (0.1.9)
- 新命令: space list/create、base create/delete(实测通过,冒烟覆盖) - SKILL.md §0 执行守则:完成全部步骤再答复/不谎报/分批/撤销指引 (snapshot 无恢复 API,用 deactivate+节点改回) - hint 补 429 限流与超时模式 - evals/ 入仓: 14+6 题 harness 参数化(EVAL_ROOT/EVAL_ENV/EVAL_MODEL/ EVAL_CFG/auto_skill 触发模式)+ 多轮修正式 eval 与灵活判分 - 判分器加固: workflow list 错误负载不崩、官方 CLI 探测(command -v)不算使用 - 实测: auto 触发批(入仓版重跑) 11/11、99.0% 首试、100% ≤2 次; 多轮修正 2/2+3/3(修改而非重建);冒烟 85 用例含 token 路由(低权会话) - 运维事实入档: POST/DELETE /api/plugin 为管理员专属(PAT 403)
This commit is contained in:
@@ -50,7 +50,7 @@ async function fieldNameMap(client: Client, tableId: string): Promise<Record<str
|
||||
}
|
||||
|
||||
export function baseResourceCommands(): Command[] {
|
||||
return [baseCmd(), tableCmd(), fieldCmd(), recordCmd(), viewCmd(), presetCmd()];
|
||||
return [baseCmd(), spaceCmd(), tableCmd(), fieldCmd(), recordCmd(), viewCmd(), presetCmd()];
|
||||
}
|
||||
|
||||
// ===================== base =====================
|
||||
@@ -82,6 +82,35 @@ function baseCmd(): Command {
|
||||
})
|
||||
);
|
||||
|
||||
cmd
|
||||
.command('create')
|
||||
.description('Create a base in a space')
|
||||
.requiredOption('--space-id <id>', 'Space id (see `space list`)')
|
||||
.requiredOption('--name <name>', 'New base name')
|
||||
.action(
|
||||
run(async (ctx, _a, o) => {
|
||||
const opts = o as { spaceId: string; name: string };
|
||||
const base = await ctx.client.createBase(opts.spaceId, opts.name);
|
||||
if (ctx.json) printJson(base);
|
||||
else {
|
||||
const b = base as Record<string, unknown>;
|
||||
printKv([['id', b.id], ['name', b.name]]);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
cmd
|
||||
.command('delete <baseId>')
|
||||
.description('Soft-delete a base (DESTRUCTIVE: hides all its tables)')
|
||||
.action(
|
||||
run(async (ctx, args) => {
|
||||
const baseId = args[0] as string;
|
||||
await ctx.client.deleteBase(baseId);
|
||||
if (ctx.json) printJson({ ok: true, id: baseId });
|
||||
else process.stdout.write(`✓ Base ${baseId} deleted (soft)\n`);
|
||||
})
|
||||
);
|
||||
|
||||
cmd
|
||||
.command('get <baseId>')
|
||||
.description('Get base details')
|
||||
@@ -100,6 +129,54 @@ function baseCmd(): Command {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
// ===================== space =====================
|
||||
|
||||
function spaceCmd(): Command {
|
||||
const cmd = new Command('space');
|
||||
cmd.description('Manage spaces (top-level containers for bases)');
|
||||
|
||||
cmd
|
||||
.command('list')
|
||||
.description('List spaces you can access')
|
||||
.action(
|
||||
run(async (ctx) => {
|
||||
const list = (await ctx.client.listSpaces()) as Array<Record<string, unknown>>;
|
||||
if (ctx.json) printJson(list);
|
||||
else {
|
||||
if (!list.length) {
|
||||
process.stdout.write('No spaces found.\n');
|
||||
return;
|
||||
}
|
||||
printTable(
|
||||
[
|
||||
{ key: 'id', header: 'ID' },
|
||||
{ key: 'name', header: 'NAME' },
|
||||
],
|
||||
list.map((sp) => ({ id: truncate(sp.id), name: truncate(sp.name, 40) }))
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
cmd
|
||||
.command('create')
|
||||
.description('Create a space')
|
||||
.requiredOption('--name <name>', 'New space name')
|
||||
.action(
|
||||
run(async (ctx, _a, o) => {
|
||||
const opts = o as { name: string };
|
||||
const sp = await ctx.client.createSpace(opts.name);
|
||||
if (ctx.json) printJson(sp);
|
||||
else {
|
||||
const s2 = sp as Record<string, unknown>;
|
||||
printKv([['id', s2.id], ['name', s2.name]]);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
// ===================== table =====================
|
||||
|
||||
function tableCmd(): Command {
|
||||
|
||||
@@ -54,6 +54,18 @@ export class Client {
|
||||
getBase(baseId: string) {
|
||||
return this.call<unknown>('GET', `/api/base/${baseId}`);
|
||||
}
|
||||
createBase(spaceId: string, name: string) {
|
||||
return this.call<unknown>('POST', '/api/base', { spaceId, name });
|
||||
}
|
||||
deleteBase(baseId: string) {
|
||||
return this.call<{ id: string }>('DELETE', `/api/base/${baseId}`);
|
||||
}
|
||||
listSpaces() {
|
||||
return this.call<unknown[]>('GET', '/api/space');
|
||||
}
|
||||
createSpace(name: string) {
|
||||
return this.call<unknown>('POST', '/api/space', { name });
|
||||
}
|
||||
|
||||
// ---- table ----
|
||||
listTables(baseId: string) {
|
||||
|
||||
@@ -28,6 +28,10 @@ export function buildHint(status: number, message: string): string | undefined {
|
||||
return '违反了字段的 visibilityFilter(行级条件)—— `inkreach-teable field visible-choices <tableId> <recordId> <field>` 查看该行可见选项。';
|
||||
if (/expected array, received/i.test(m))
|
||||
return '参数形状不符 —— 批量接口要数组;单条可改用 --fields,批量用 --records。';
|
||||
if (status === 429)
|
||||
return '触发限流 —— 稍等后重试;批量操作请降低并发或分批执行。';
|
||||
if (/timeout|ETIMEDOUT|ECONNRESET/i.test(m))
|
||||
return '请求超时/连接中断 —— 先用只读命令(如 table list)确认服务可达,再重试原操作。';
|
||||
if (/VALIDATION|Validation error/i.test(m) && status === 400)
|
||||
return '请求校验失败 —— 用 --json 查看完整错误;对照 `<cmd> --help` 的参数示例。';
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user