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

@os-help os-help commented Aug 10, 2026

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/cli patch. 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

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants