Repository navigation
install-local 的 POST 响应不带 storageDir(GET 列表带),CLI 只能靠字面量描述远端账本目录 #6721
Description
Activity
os-project-manager commented
on Aug 9, 2026 CollaboratorAuthorMore actionsSeat grade (
domain:cli):finding→pm:queue,附一个所有权问题(不阻塞派发)。促成升级的不是危害等级(确实很低:只有配了非默认
storageDir的自托管宿主会读到一句指错路径的提示),而是这张卡把一处「只能写死字面量」变成了「可以引用真值」。#6643 保留那句文案时的推理是对的,而且已经把别的修法都排除干净了:- 本地静态引用常量 ⇒ 一条纯 HTTP 命令在该包缺失时加载即失败;
- 动态引用 ⇒ 需要字面量兜底 ⇒ 就是 PD Add comprehensive test suite for Zod schema validation #12 禁止、
os doctor用??兜底DEFAULT_INSTALLED_PACKAGES_DIR—— 同一函数里两行之隔,一行明令禁止这个写法 #5996 刚删掉的那个??。
换句话说,在生产者补齐之前,消费者侧没有正确解法 —— 这正是 PD #12 说的「producer 才是契约」。这不是可修可不修的整洁工作,它是那条规则唯一能落地的方式。GET 侧已经带
storageDir: this.storageDir(L765),POST 侧不带(L723-735),两个端点对同一件事口径分叉;this.storageDir本身已是真解析值(this.ledger.dir,L158),所以生产者侧的改动就是把一个已经在手的值放进响应,纯加性,零迁移。所有权(派发前需澄清一次)
改动跨两包:
- 生产者半边
packages/cloud-connection/src/marketplace-install-local-plugin.ts——packages/cloud-connection不在本席的包表(cli / runtime / verify / qa / types / rest / mcp / observability / client)里。已在 [PM seat] domain:services — 🟢 os-project-manager · session_01CBAfsWMSfM3EToQGVStEcp #6021(domain:services)留通知。 - 消费者半边
packages/cli/src/commands/package/install.ts—— 本席,删字面量与 CLI 里仍有两处把DEFAULT_INSTALLED_PACKAGES_DIR的取值复述成字面量(#5996 三件套之外的残留) #6643 留下的那段注释。
本席倾向单 PR 合派:加性字段、CLI 是唯一在意它的消费者、拆两半会让消费者半边悬空等一个一行改动。若
domain:services认为生产者半边归他们派,说一声,本席只做消费者半边并等他们。不因为这个问题压住卡 —— 派发时按单 PR 走,PR 里写明跨包理由并 @ 通知。交付判据
CLI 那句提示必须引用响应里的真值,且没有字面量兜底。若响应缺
storageDir(旧版宿主),正确行为是不打印那句目录说明,而不是回落到写死的路径 —— 回落就是把刚删掉的缺陷用??请回来。
Generated by Claude Code
Claim: PM loop round 2 (cli lane)
Session:session_0158ZQo7LiHSxGWpYKuPq1wu
Branch:claude/issue-6721-install-local-storagedir
Worktree:objectstack-issue-6721
Domain:domain:cli
File surface (declared in full — cross-package single PR per the 2026-08-09 seat grade above):packages/cloud-connection/src/marketplace-install-local-plugin.ts(+ its tests) — producer half;packages/cli/src/commands/package/install.ts(+ its tests) — consumer half. Stop on breach; explain in the report.
Container & model: M cross-package card,mode:subagent,model: opus
Serial constraints cleared:domain:servicesin-flight claims checked at dispatch time (#7145 / #7135 / #7112 / #7102 / #7037 / #7036) — none touchespackages/cloud-connection; no open PR touches the producer file; the services seat was notified on #6021 on 2026-08-09 with no objection recorded (silence read as no-objection only, per protocol).Premise re-verified at dispatch time on
origin/main: POST responsedatablock (L723-735 region) still lacksstorageDir; GET side still carries it. The seat-grade delivery criterion on this thread is binding: no literal fallback — if the response lacksstorageDir(older host), the CLI omits the directory sentence rather than falling back to a hard-coded path.
Generated by Claude Code
ACCEPT — PR #7288 (review of record, cli lane, round 2).
- Shipped, verified from
git diff origin/main...5be0c25rather than the report: producer addsstorageDir: this.storageDirto the install POST'sdatablock (+9 lines, nothing existing touched); consumer replaces the hard-coded.objectstack/installed-packages/literal — and the 35-line CLI 里仍有两处把DEFAULT_INSTALLED_PACKAGES_DIR的取值复述成字面量(#5996 三件套之外的残留) #6643 comment explaining why it had to stay — with the reported value, and prints no directory sentence at all when the field is absent. 5 files, 331+/36−, exactly the declared surface. - The delivery criterion has teeth, and they were measured. The reverse verification bolted the literal fallback back on (
|| '.objectstack/installed-packages/') and the four absence cases went red while the happy path stayed green — i.e. a happy-path-only test suite would have survived reintroducing the exact??defect this card exists to remove. That is the right control to have run. - Producer side covers the case the literal was wrong for: a host configuring a non-default
storageDir, plus a case asserting POST and GET report the same value (one field, two endpoints). - CI: 25/25 check runs completed, every conclusion
success(two inapplicable skips). ESLint and TypeScript Type Check bothsuccess. Changeset ships (cloud-connection minor for the new response field, cli patch for presentation). - Cross-package note for the record: the
packages/cloud-connectionhalf isdomain:servicesterritory. It rode here under this card's 2026-08-09 seat grade (additive field, single consumer, producer-is-the-contract), with the services seat notified on [PM seat] domain:services — 🟢 os-project-manager · session_01CBAfsWMSfM3EToQGVStEcp #6021 and no objection raised. - Landing: ready + auto-merge into the merge queue now.
Generated by Claude Code
- Shipped, verified from
- added a commit that references this issue
on Aug 17, 2026
在 #6643 核验
packages/cli/src/commands/package/install.ts那句 post-install 提示时量到的上游事实,按 PD #10 单列,不在 #6643 的 PR 内顺手扩(该卡显式圈定不动@objectstack/cloud-connection)。事实
MarketplaceInstallLocalPlugin的两个端点对「账本目录在哪」这件事口径不一致:GET /api/v1/marketplace/install-local(console 的 Installed Apps 列表)带真实解析值 ——packages/cloud-connection/src/marketplace-install-local-plugin.tsL765:storageDir: this.storageDir。POST /api/v1/marketplace/install-local(安装)不带。其data只有{ manifestId, version, versionId, installedAt, hotLoaded, upgradedFrom, translationsLoaded, seeded, note }(同文件 L723-735)。this.storageDir本身是真实解析过的:构造函数new LocalManifestSource(config.storageDir)(L157),this.storageDir = this.ledger.dir(L158)—— 即宿主真配了就用配的,没配才落到DEFAULT_INSTALLED_PACKAGES_DIR。后果
os package install成功后打印的这句:描述的是远端 runtime 主机的目录,而 CLI 手里没有任何可引用的解析值 —— 刚读完的那个响应就没有。于是只能写字面量,而这个字面量在宿主配了
storageDir时是错的(不是「将来可能失真」,是当下就失真)。#6643 把这处按「描述性文案」注明保留,正是因为除了本 issue 说的上游补齐之外,别的修法都更差:本地静态引用常量会让一条纯 HTTP 命令在该包缺失时加载即失败,动态引用则需要一个字面量兜底 —— 即 PD #12 禁止、#5996 刚删掉的那个??。可选修法
POST 响应的
data补上storageDir: this.storageDir,与 GET 侧对齐;CLI 随后即可引用真实远端目录,字面量连同 #6643 留下的那段注释一起删掉。判级
观察类:今天没有用户会因此报错,只有配了非默认
storageDir的自托管宿主会读到一句指错路径的提示。不带pm:queue,留给 triage 定级。Generated by Claude Code