Skip to content

fix(cli)!: os cloud login --json 改为 NDJSON 事件流,授权前交出 verification URL - #6838

Merged
os-project-manager merged 6 commits into
mainfrom
claude/issue-6730-cloud-login-json-ndjson
Aug 9, 2026
Merged

fix(cli)!: os cloud login --json 改为 NDJSON 事件流,授权前交出 verification URL#6838
os-project-manager merged 6 commits into
mainfrom
claude/issue-6730-cloud-login-json-ndjson

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#6730

实施 2026-08-08 维护者裁定(#6730 comment 5226489062)取岔口 1:os cloud login --jsonos login --json#6531 / PR #6727)同一契约 —— NDJSON 事件流,授权前交出 verification URL。形状与出口一律照抄 PR #6727,不另起一套。

前提是实测的,不是从 silent: flags.json 推出来的

合并后的树上,把两个源文件 revert 回 origin/main,对一个真实的 RFC 8628 端点跑 os cloud login --json --no-browser(PTY 驱动),stdout 全文:

{
"success": true,
"email": "device@example.com",
"userId": "usr_6730",
"url": "http://127.0.0.1:41839"
}
  • JSON.parse(<整个 stdout>): OK —— 形式上无可指摘,单文档。
  • 逐行解析: 6 行全部失败(2 空格缩进)。
  • verification_uri 是否出现在 stdout: false。出现在 stderr: false。user_code WXYZ-6730: false

即缺陷不是「文档畸形」,而是事件缺席:device flow 在脚本里唯一有用的那一半被 silent 关掉了,什么都没补上。消费者拿到的是一份描述「它无从触发的那次授权」的合法 JSON。

改动

  1. 单一写出口。该命令全部四处--json 写点走 emitRecord()emitJson(payload, exitCode, { compact: true }) 的唯一封装)—— 不只是 device flow 那两处。失败记录是在 device 记录之后才可能到达的(拒批、码过期、poll 失败),留一处缩进就会在消费者最没法恢复的那条路径上重建两文档流。测试里有一条源码 pin 守住这个出口。
  2. 共享 device flow 增加 onDeviceCode({ record }),把服务端原样字段(device_code / user_code / verification_uri / verification_uri_complete / expires_in)交给调用方,与 os login --json 的记录逐字段同形;回调改为 await,因为 emitJson 只在 stdout 真正 drain 后才 resolve —— 管道是异步缓冲的,不 await 等于把「自动化最需要先拿到的那条记录」交给运气。人类模式不传该回调,仍走原打印器。
  3. 例外是声明式的--json--help 文案(已实测渲染)+ content/docs/deployment/cli.mdxos cloud login 小节 + content/docs/deployment/index.mdx 里 cloud 发布流程处的提示与回指。全仓提到 os cloud login 的文档页只有这两个(grep 确认),permissions/authentication.mdx 从未提及本命令,故未触碰(也避开 PR fix(cli): os login --json 声明为 NDJSON 事件流,每行一份可解析文档 (#6531) #6727 的地盘)。
  4. 破坏性如实披露:changeset 正文写明 wire 形状变化、谁会坏、怎么改。

版本号: minor,且明确不抄 #6727patch

#6727patch 的前提是「原来就没有能用的东西被弄坏」——它的 device flow 输出本就不可解析。这里前提相反:单文档读法今天是能用的,device flow 路径上会被打断。major 不是可选项:本仓所有可发布包锁步版本,launch window 期间破坏性变更一律 minorscripts/check-changeset-no-major.mjs 会拒 major。所以承担警示职责的是正文披露而非版本号。

changeset 另带 ADR-0087 处置标记 not-required (no-migration-prescription):变的是一个 CLI 命令 stdout 的流形状,没有可授权键 / 导出符号 / 存储值发生位移,objectstack migrate meta 无物可转换;真正触达这些消费者的渠道是 CHANGELOG 正文、--help 与 CLI 参考页,三者本 PR 都带上了。

复现纪律与「顺序」的钉法

device flow 只在 process.stdin.isTTY 为真时才走,管道 stdin 根本到不了那些写点,所以测试用 script(1) 开 PTY,命令内部把 fd 1 / fd 2 重定向到文件(fd 0 是 TTY,fd 1/2 可捕获且非 TTY —— 也正是真实用户把交互式 os cloud login --json 接进消费者时的形状)。script(1) 缺失时该文件报错而非 skip

顺序断言是时间性的,不是数组下标:假端点扣住 token,直到测试自己从子进程 stdout 上读到 device 记录才放行。于是「URL 先于授权」是这次运行自身的历史。下标断言抓不到「缓冲成一份尾部文档」的回归——因为合并后的文档里 URL 字段同样排在前面。这一点是实测过的,见下面 R3。

验证

预测在动手前落盘,本轮沿用未改写。合并 origin/main(19 个提交)后全部重测,上一轮的测量一律作废。

方向预测实测
正向12 GREEN12/12 通过
R1 revert 源码(保留文档+测试)8 RED / 4 GREEN8 RED / 4 GREEN,逐条命中
R2 只 revert 文档2 RED(B3/B4)2 RED / 10 GREEN,逐条命中
R3 模拟被否决的「缓冲成单文档」路线4 RED(记录数 / 时序 / 行数 / 拒批路径)4 RED / 8 GREEN,逐条命中

R1 里时序 pin 的失败信息直接点名成因:the device record never reached stdout early: expected true to be false

R3 是本 PR 最想留下的证据:「每行可解析」与「URL 出现在 stdout」两条仍然 GREEN,只有时序 pin 变 RED —— 这正是顺序断言不能写成数组下标的原因。

诚实排除(两个方向都绿,不构成 R1 的证据):拒批路径的 exit 1、人类模式打印 URL、以及 R1 下未被 revert 的两条文档 pin。

门禁(真实输出,非声称):pnpm lint 0;pnpm --filter @objectstack/cli typecheck 0;CLI 全量 98 文件 / 1029 测试全通过lint.ymlcheck:* 全套 54 项全绿check:i18n-coveragecheck:type-check-debt 首轮红,两者都自陈缺完整 build closure —— lint.yml 在这两步前会先跑 turbo run build --filter='./packages/*' --filter='./packages/*/*';补跑该 build 后两项均转绿,未改任何基线);工作区 typecheck 120/120;pr-automation.yml 的三条 changeset 门禁(adr-0087-registration / no-major / empty-changeset)全绿。

字节自查:6 个改动文件逐个 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'全部 clean,零命中。测试里关于回车与 ESC 的断言写成 /[\r�]/ 转义文本,而非字节本身(PR #6727 的教训)。

不碰

packages/cli/src/commands/login.ts#6531 / PR #6727)、content/docs/releases/packages/rest/#6306 另有 agent)。


🤖 Generated with Claude Code

https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx


Generated by Claude Code

os-project-managerand others added 6 commits August 8, 2026 14:30
#6730)
- 全部四个 --json 写点统一走 emitRecord() 单一写出口
- device flow 经 onDeviceCode 在轮询前发出 RFC 8628 记录
- --help / cli.mdx / deployment index.mdx 三处声明该例外
- PTY 驱动的 e2e,时序钉由端点扣住 token 直到测试读到记录
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx
`check:adr-0087-registration`(pr-automation.yml)要求每条声明 BREAKING 的
changeset 在正文里写明它与 ADR-0087 台账的关系。本条变的是一个 CLI 命令
stdout 的流形状:没有可授权键、没有导出符号、没有存储值发生位移,
`objectstack migrate meta` 无物可转换,故 not-required
(no-migration-prescription),并写明真正触达消费者的三个渠道。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx
`check-changeset-no-major.mjs`:所有可发布包锁步版本,launch window 期间
破坏性变更一律走 minor,major 被门禁拒。补这一句是为了让评审者不必再问
「为什么不是 major」,并点明真正承担警示职责的是正文披露而非版本号。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uFVNMmTxLpmfQYiuKM1Yx
@vercel

vercelBot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 8, 2026 11:50pm

Request Review

@github-actionsgithub-actionsBot added size/l documentation Improvements or additions to documentation tests tooling labels Aug 8, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli.

21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx(via packages/cli)
  • content/docs/api/client-sdk.mdx(via @objectstack/cli)
  • content/docs/api/data-flow.mdx(via @objectstack/cli)
  • content/docs/api/environment-routing.mdx(via @objectstack/cli)
  • content/docs/api/error-catalog.mdx(via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx(via packages/cli)
  • content/docs/deployment/backup-restore.mdx(via @objectstack/cli)
  • content/docs/deployment/cli.mdx(via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx(via @objectstack/cli)
  • content/docs/deployment/validating-metadata.mdx(via packages/cli)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/cli)
  • content/docs/kernel/runtime-services/index.mdx(via packages/cli)
  • content/docs/permissions/authentication.mdx(via @objectstack/cli)
  • content/docs/plugins/index.mdx(via @objectstack/cli)
  • content/docs/plugins/packages.mdx(via @objectstack/cli)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx(via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx(via @objectstack/cli)
  • content/docs/releases/v16.mdx(via @objectstack/cli)
  • content/docs/releases/v17.mdx(via @objectstack/cli)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-project-manager
os-project-manager marked this pull request as ready for review August 8, 2026 23:51
@os-project-manager
os-project-manager added this pull request to the merge queueAug 9, 2026
Merged via the queue into main with commit 93fcd02Aug 9, 2026
26 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-6730-cloud-login-json-ndjson branch August 9, 2026 00:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

2 participants

@os-project-manager@claude