@tablize/cli
v0.3.0-beta.15
Published
Tablize CLI — durable data pipelines for coding agents: the process lives on the server so your agent leases small batches and resumes instead of restarting, every attempt lands on one ledger, and an optional golden gate decides what counts.
Readme
tablize CLI(node)
agent 面的 CLI —— 表 · 变换 · 批次 · 血缘,全是打 REST。
它解决的是这个:agent 处理长表时,整表进上下文会把注意力摊薄、会话一断就得重来。
tablize 把流程固化在服务端 —— agent 一小批一小批领活(batch pull → 算 →
batch submit),手上只有派给它的那几行,跑断了是 tablize context 续跑而不是重跑。
每一次尝试、每个模型、每次标准改动都落在同一本账上。金标门是可选的加固件:
建线时不给金标,这条线就没有门(--gate none,行落成「未验收」);
给了金标就是 enforce,错一条拒整批,见
ADR 0066。档位不是建线时定死的 ——
transform gate --mode … --reason … 能移动它(理由必填、落到规则层时间线;
与 revise / goldens 不同,它不 bump 配方版本,所以什么都不重排、已做的活还算数)。
npm i -g @tablize/cli
tablize install # 铺 agent skill(**不**跑 postinstall,见下)
tablize --helpmacOS / Linux / Windows 同一个产物。
为什么是 node 而 Rust 那份还在
命令面按受众切成两半(ADR 0065):
agent 面(这里)——
line/table/transform/batch/lineage/task/query/pipeline/context/workspace/whoami/login/import/export/doctor/diagnose/install/update。全部是 HTTP,所以 node 写得动, 且 Windows 第一天就有(原生二进制那条一直只支持 macOS + Linux,Windows 用户从来装不上)。 一个产物、不用交叉编译、不用签名。line(ADR 0070) 只在这一份里有 —— Rust 那份停在 0.2 的命令面。它是pipeline init的继任者: 声明名字 + 位置 + 采集契约,一张表都不建,位置在第一次写入时才物化。admin面 ——store check/columnar/formula/migrate/openapi dump/deploy/healthz。要在进程内开磁盘上的 store、接同一个列存服务、从 Rust 类型出 OpenAPI,只能是 Rust。它跑在服务端那台机器上,而那台机器本来就有 Rust 二进制。 装法:npm i -g @tablize/admin→ 命令名tablize-admin(名字不撞)。
两份实现共用的三样东西
过渡期两份同时在世,所以这三处必须逐字相同,不是「最好一致」:
~/.config/tablize/config.json—— 同一个文件、同一批 key(含userId/expiresAt)、同一个回退顺序(flag > env >.tablize> 文件)。用户能在两者之间来回 切而不用重新 login。.tablize项目绑定同理(向上查找)。- skill 树的内容摘要 —— 配方是「按路径排序,每个文件喂 路径字节 ·
0x00· 长度的 u64 小端 · 内容」。摘要漂一位,两边的doctor就会互相把对方装的 skill 报成E_SKILL_STALE,而且重装多少次都清不掉。tests/install.test.ts用一个独立算出来的 期望值钉住配方,另一条钉住「npm 包里的文件集 = git 里的减去共享排除表」。 .tablize-install.json的字段 —— 两边的doctor都要读它。
.gitignore不随 skill 发 —— npm 无条件把这个名字从 tarball 里剔掉,没有开关。两边的 排除表因此一起加上了它,否则文件集差一个、摘要必然不等。
doctor 第一层问的是「哪一份」,不是「哪个字节」
Rust 版第一层是「装的 = 跑的?」,它自己把二进制拷上 PATH,所以能比字节。这一份没有那个 动作(npm 干完了),而真正会咬人的是另一件事,现在就在咬:
~/.local/bin/tablize(老curl | sh装的原生二进制)在很多机器上排在 npm 的全局 bin 前面。以前装过的人npm i -g @tablize/cli之后跑的还是那个旧二进制,一句提示都没有, 而它答的是 0.1/0.2 的命令面。
所以第一层改问 PATH 第一名是哪一份实现,判据是读文件头的魔数(Mach-O / ELF / PE →
native;#!…node → node)。发现原生时报 E_BIN_NATIVE_SHADOW 并给出那条 rm。
install 的 binary 那一半同理:不搬文件,只回答「PATH 上跑起来的会是哪一份」。
Rust 版的 --bin-dir / --no-build 在这里不存在 —— 留着就是两个假 flag。
install 不进 postinstall:装个包不该悄悄改用户的 agent 配置。
复刻的代价,写在这里
这份是复刻,不是共享类型。移植过程中被服务端打回两次,另有四处是逐字段核过 Rust 版
之后才发现的偏差 —— 每一条现在都是 tests/wire.test.ts 里的一条断言,而且期望值抄自
Rust 源码 / 服务端 DTO,不是抄自这份实现自己:
- 单元格类型在 header 的
meta(外部标签枚举)里,不在kind里 ——kind是 header 的角色(row/ 公式 / lookup)。当类型读会让每列都变成row,于是每次写入都被拒。 - dedupe 的 body 是
onHeaderIds/projectHeaderIds,不是on/project。 encode的三处「宽进」曾被写成「严拒」 —— Rust 把 number 原样转发字符串、认不出的 布尔词落false、未知 kind 落text,让服务端说不。抢着判会拒掉服务端本来收的值。- 日期不能用
Date.parse读不带时区的 datetime —— 它按本地时区算,Rust 按 UTC。 同一条命令在两台机器上写进去的是两个时刻,不报错、跨机器才显形。 - 配置文件的过期时间键是
expiresAt,不是tokenExpiresAt。一个字母让会话轮转永远 读不到过期时刻。 - 连接 flag 也要挂在顶层 —— clap 那边是
global = true,tablize --url X table list必须成立。
Rust 那份不会犯这些错,因为它 use tablize_types —— 类型是同一份。所以这一侧必须有测试
替代编译器。 这是选 node 换来 Windows 与单产物时,实际付出的那笔账。
开发
npm ci
npm run check # tsc --noEmit(src + tests)
npm test # 103 条:命令面形状 / 线上形状 / skill 发放 / 入口判定 /
# 线寻址 / 列级证据 / 配置写路径 / 未送达重试
npm run build && node dist/main.js --helpbash scripts/ci-local.sh 是仓库的合并判据,里面有 cli typecheck 与 cli test 两道闸。
