Skip to content

feat(cloud-connection,cli): install-local POST reports storageDir, os package install quotes it - #7288

Merged
os-help merged 1 commit into
mainfrom
claude/issue-6721-install-local-storagedir
Aug 10, 2026
Merged

feat(cloud-connection,cli): install-local POST reports storageDir, os package install quotes it#7288
os-help merged 1 commit into
mainfrom
claude/issue-6721-install-local-storagedir

Conversation

@os-help

Copy link
Copy Markdown
Collaborator

Fixes#6721

What changed

Two endpoints of MarketplaceInstallLocalPlugin disagreed about one fact, and the
disagreement was load-bearing for os package install.

Producerpackages/cloud-connection/src/marketplace-install-local-plugin.ts.
The install POST's data block now carries storageDir: this.storageDir, read from
the same field the GET listing (handleList) already served. this.storageDir is
this.ledger.dir, resolved once in the ctor by LocalManifestSource — the host's
configured storageDir when it set one, DEFAULT_INSTALLED_PACKAGES_DIR when it did
not. The change is purely additive: an already-in-hand value put into a response, no
existing key touched, no migration, nothing obliged to read it.

Consumerpackages/cli/src/commands/package/install.ts. The post-install hint
quotes the reported directory instead of a literal:

 The manifest is cached on the runtime host and re-registers on every
boot (survives restarts):
/srv/objectstack/state/ledger-packages

When the response has no storageDir — a runtime older than the producer half — the
CLI prints no directory sentence. There is no fallback. The long #6643 comment
block explaining why the literal had to stay is deleted along with the literal.

Why one PR across two packages

The 2026-08-09 seat grade on #6721 ruled this shape, and the reason is the rule itself
rather than convenience:

  • The producer is the contract.CLI 里仍有两处把 DEFAULT_INSTALLED_PACKAGES_DIR 的取值复述成字面量(#5996 三件套之外的残留) #6643 measured that no consumer-side answer exists.
    A constant resolved in the CLI describes the machine typing the command, not the
    remote host that stored the manifest; it is in any case only the plugin's default,
    wrong the moment a host configures storageDir; and a static import of
    @objectstack/cloud-connection would make a pure-HTTP command fail at module load
    wherever that package is absent or unbuilt. Every CLI reference to that package is a
    guarded dynamic load for exactly this reason. So the consumer half cannot be correct
    until the producer half lands — splitting the PR would leave it dangling on a
    one-line change.
  • Single consumer. A repo-wide sweep for install-local finds the plugin and
    packages/cli/src/commands/package/install.ts; the other hits
    (packages/runtime/src/domains/packages.ts, packages/client/src/index.ts,
    packages/objectql/src/plugin.ts) are prose references to the manifest shape, not
    readers of this response. Nothing else observes the new field.
  • Additive field. Adding a key to a success envelope cannot break a reader that
    does not know about it, so the producer half carries no compatibility risk of its own.

The binding delivery criterion from that seat grade, quoted verbatim:

CLI 那句提示必须引用响应里的真值,且没有字面量兜底。若响应缺 storageDir(旧版宿主),正确行为是不打印那句目录说明,而不是回落到写死的路径 —— 回落就是把刚删掉的缺陷用 ?? 请回来。

That is why the absent case prints nothing rather than degrading gracefully into the
old string: a ?? '.objectstack/installed-packages/' would read as a kindness to older
hosts and would reinstate precisely the defect Prime Directive #12 forbids and #5996
deleted — a consumer inventing a value the producer declined to state. An empty or
non-string value is treated as the same "the host did not state it" case, not as a
reason to print a blank path.

Changeset level

.changeset/install-local-post-storage-dir.md bumps @objectstack/cloud-connection
minor and @objectstack/clipatch. The producer half adds a new field to a
public HTTP response — additive capability, so minor. The consumer half changes only
what an existing command prints, and changes it from a wrong path to a right one (or
to silence) — a presentation fix, so patch.

Tests

New, both halves:

  • packages/cloud-connection/src/marketplace-install-local-storage-dir.test.ts — POST
    data.storageDir equals the resolved ledger dir for a host with a non-default
    storageDir (the configuration the old literal misreported, and the only one that
    separates "quotes the resolved value" from "restates the default"); equals the ctor
    default when the host configured nothing (run under a chdir into a temp dir, since
    that path genuinely writes relative to process.cwd()); and equals the GET listing's
    value string-for-string, which is the divergence this closes.
  • packages/cli/test/package-install-storage-dir.test.ts — the sentence quotes the
    response value verbatim; the sentence is absent when the response omits
    storageDir, and absent for empty / whitespace / null, while the install itself is
    still reported.

Reverse verification

Predicted direction before running, and both matched.

  • Delete storageDir from the POST response ⇒ all 3 producer cases red
    (expected undefined to be '/tmp/mil-storage-dir-…'). Restored.
  • Bolt the literal fallback back on (|| '.objectstack/installed-packages/') ⇒ the 4
    absence cases red (expected … not to contain 'cached') while the happy path stays
    green. That is the delivery criterion's teeth: a happy-path-only test would have
    stayed green through this edit. Restored.

Local gates

pnpm --filter @objectstack/cloud-connection test Test Files 16 passed (16) Tests 112 passed (112)
pnpm --filter @objectstack/cli test Test Files 106 passed (106) Tests 1144 passed (1144)
pnpm --filter @objectstack/cli typecheck Done
pnpm turbo run build --concurrency=2 Tasks: 72 successful, 72 total
pnpm check:type-check-debt OK — none above its recorded number
node scripts/check-nul-bytes.mjs OK (scanned 6640 text files)

Dependency closures were built first (--filter '@objectstack/cloud-connection^...',
--filter '@objectstack/cli^...' — the ^... suffix, i.e. upstream dependencies, which
is the direction that matters here since neither change narrows an exported type).
check:type-check-debt was run after the full build closure and raises no ledger entry;
the two new test files add no TEST_DEBT.


Generated by Claude Code

…I quotes it (#6721)
The install POST's `data` block now carries `storageDir: this.storageDir` —
the same resolved ledger directory (`LocalManifestSource.dir`) the GET
listing sibling already served. `os package install` runs on a different
machine and never touches the runtime's disk, so before this the CLI could
only describe the cache location by literal, and that literal was the
plugin's default — wrong for every host that configures `storageDir`.
The CLI now quotes the reported value, and prints NO directory sentence when
the response lacks the field (an older host). No literal fallback: a `??`
there would reinstate the defect PD #12 forbids and #5996 deleted.
Fixes#6721
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158ZQo7LiHSxGWpYKuPq1wu
@vercel

vercelBot commented Aug 10, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 10, 2026 5:02am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/cloud-connection.

19 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/metadata-service.mdx(via @objectstack/cloud-connection)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx(via @objectstack/cli)

3 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/cli, @objectstack/cloud-connection)
  • content/docs/releases/v16.mdx(via @objectstack/cli)
  • content/docs/releases/v17.mdx(via @objectstack/cli)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install-local 的 POST 响应不带 storageDir(GET 列表带),CLI 只能靠字面量描述远端账本目录

2 participants

@os-help@claude