Skip to content

refactor(cloud): move the fleet inventory and attach preflight into ts-cloud - #2380

Merged
glennmichael123 merged 1 commit into
mainfrom
refactor/cloud-logic-to-ts-cloud
Aug 31, 2026
Merged

refactor(cloud): move the fleet inventory and attach preflight into ts-cloud#2380
glennmichael123 merged 1 commit into
mainfrom
refactor/cloud-logic-to-ts-cloud

Conversation

@glennmichael123

Copy link
Copy Markdown
Member

Draft: blocked on a ts-cloud release carrying stacksjs/ts-cloud#192 (merged as b06d37a). Ready to mark ready the moment that publishes.

Why

#2378 and #2379 carried their whole implementation here: a fleet inventory, an attach preflight, and hand-rolled copies of ts-cloud's own buildHostSitePortsScript, parseHostSiteFragments and occupiedHostPorts.

Those copies were not laziness. deploy/site-ports shipped declarations with no reachable runtime, so the real functions could not be imported at all. But they were still a second reading of ts-cloud's own file format, living in another repository, with nothing to keep the two in step - and site-ports.ts cares about that enough to pin its one duplicated constant with a test.

None of that logic is buddy's. Reading a box's gateway registry, deciding whether a project may attach to somebody else's server, and writing attachTo back into a cloud config are things ts-cloud owns. stacksjs/ts-cloud#192 moves them beside site-ports and site-move where they belong, and fixes the export gap that forced the duplication (stacksjs/ts-cloud#191).

What moves

Deleted here Now in ts-cloud
src/cloud-inventory.ts operations/inventory
src/cloud-attach.ts operations/site-attach + setAttachToInCloudConfig
tests/cloud-inventory.test.ts, tests/cloud-attach.test.ts (74 tests) 47 tests, deduplicated against what site-ports already covered

The duplicated primitives are gone: the inventory now calls ts-cloud's buildHostSitePortsScript / parseHostSiteFragments, and the attach preflight calls occupiedHostPorts, so the collision check and the port allocator can no longer disagree about which ports are taken.

What stays

The part that is genuinely the CLI's:

  • resolving the provider token and listing the fleet - now through ts-cloud's HetznerClient.listServers() rather than a hand-rolled fetch with its own pagination loop;
  • reading config/cloud.ts and shaping this project's sites, via resolveSiteKind and siteInstallBase rather than re-deriving either;
  • refusal paths, exit codes and --json;
  • describing the two config edits an attach needs. That one stays deliberately: tenants is a Stacks config key, and the second edit lives in a repository this command cannot write to.

Verification

  • buddy lint clean (3198 files, 0 errors).
  • Buddy suite 554 pass / 0 fail (down from 628 because the 74 moved tests now run in ts-cloud).
  • buddy docs:buddy regenerates identically: the command surface, options and help text are unchanged.
  • bun run typecheck: every remaining error is Property '<name>' does not exist on @stacksjs/ts-cloud, for the eleven names chore(deps): update dependency pathe to ^0.3.9 #192 adds, and nothing else. Verified against the locally built ts-cloud dist that all eleven are exported from the root barrel.

Release note

No dependency bump needed. The declared range is already ^0.12.7, which the next patch satisfies; only the lockfile moves. Once ts-cloud publishes, this needs bun install --lockfile-only and nothing more.

…s-cloud

The two commands landed in #2378 and #2379 carried their whole implementation
here: a fleet inventory, an attach preflight, and hand-rolled copies of
ts-cloud's own `buildHostSitePortsScript`, `parseHostSiteFragments` and
`occupiedHostPorts`. The copies were not a shortcut - `deploy/site-ports`
shipped declarations with no reachable runtime, so the real ones could not be
imported at all - but they were still a second reading of ts-cloud's own file
format living in another repository, with nothing to keep the two in step.

None of that logic is buddy's. Reading a box's gateway registry, deciding
whether a project may attach to somebody else's server, and writing `attachTo`
back into a cloud config are all things ts-cloud owns, and they belong beside
`site-ports` and `site-move` rather than beside a CLI. stacksjs/ts-cloud#192
moves them there and fixes the export gap that forced the duplication
(stacksjs/ts-cloud#191).

So `cloud-inventory.ts` and `cloud-attach.ts` are deleted, along with their 74
tests, which moved with them. What is left here is what is genuinely the CLI's:

  - resolving the provider token and listing the fleet, now through ts-cloud's
    own `HetznerClient.listServers()` rather than a hand-rolled fetch and
    pagination loop;
  - reading `config/cloud.ts` and shaping this project's sites, using ts-cloud's
    `resolveSiteKind` and `siteInstallBase` rather than re-deriving either;
  - the refusal, exit-code and `--json` behaviour;
  - describing the two config edits an attach needs, which stays here because
    `tenants` is a Stacks config key and the second edit lives in a repository
    this command cannot write to.

The command surface is unchanged: `buddy docs:buddy` regenerates identically.

BLOCKED on a ts-cloud release carrying #192. Every remaining typecheck error is
`Property '<name>' does not exist on @stacksjs/ts-cloud`, and nothing else. No
dependency bump is needed - the declared range is already `^0.12.7`, which the
next patch satisfies; only the lockfile moves.
@glennmichael123
glennmichael123 force-pushed the refactor/cloud-logic-to-ts-cloud branch from 561d449 to cffb9b2 Compare August 31, 2026 12:50
@glennmichael123
glennmichael123 marked this pull request as ready for review August 31, 2026 12:50
@glennmichael123

Copy link
Copy Markdown
Member Author

Rebased onto main and taken out of draft. ts-cloud 0.12.10 is published and carries #192, and Chris has already bumped the nine @stacksjs/ts-cloud ranges to ^0.12.10, so the eleven Property 'X' does not exist on @stacksjs/ts-cloud errors this was waiting on are gone.

The rebase touched two things worth naming

Conflict 1 - cloud-inventory.ts. Modify/delete: 38b6c6ed12 typed its anys (ProviderServerPayload, HostRouteFragment, HostRouteProxy). Resolved as a delete, which is the point of this PR, but the improvement is not dropped:

Conflict 2 - commands/cloud.ts. 0044765f39 removed as any from the two await import('@stacksjs/ts-cloud/deploy') calls, inside the helpers blocks this PR deletes outright. Resolved to the deletion. His prompts.confirm fixes elsewhere in the file are untouched - I resolved the two hunks in place rather than checkout --theirs, which would have taken the whole file from my commit and reverted them.

A bug the port surfaced

Writing ProviderServerPayload against the real HetznerServer interface turned up a live defect in the moved code, filed as stacksjs/ts-cloud#193:

toInventoryServer resolved a location as datacenter.location.name ?? datacenter.name ?? location, treating the last as a bare string. Hetzner has retired datacenter - it sends explicit null - and nests the place under location as an object. All three reads miss, so every box reports no location and buddy cloud:sites prints that column empty for the whole fleet.

ts-cloud already knew: resize.ts:116 reads location?.name first, and role-swap.ts carries a comment plus a regression suite about the same retirement. This reader was written against the recorded fixtures, which still carry datacenter, and inherited the legacy order. It is the third reader to need the same fallback.

Not fixable here - that code no longer lives in this repo, which is rather the point.

Verification on the rebased branch

  • bun run typecheck: the eleven ts-cloud errors are gone. Four remain, all in storage/framework/cache/models/* - gitignored, locally generated, validator typings, untouched by this diff.
  • ./buddy typecheck: clean.
  • buddy suite: 569 pass / 0 fail across 64 files.
  • Lint: one error, in storage/framework/libs/entries/web-components.ts - untracked local generate output from Aug 26 that CI does not have. The diff itself is 5 files, all under core/buddy.

@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026

Copy link
Copy Markdown

Open in StackBlitz

@stacksjs/actions

npm i https://pkg.pr.new/@stacksjs/actions@2380

@stacksjs/ai

npm i https://pkg.pr.new/@stacksjs/ai@2380

@stacksjs/alias

npm i https://pkg.pr.new/@stacksjs/alias@2380

@stacksjs/analytics

npm i https://pkg.pr.new/@stacksjs/analytics@2380

@stacksjs/api

npm i https://pkg.pr.new/@stacksjs/api@2380

@stacksjs/arrays

npm i https://pkg.pr.new/@stacksjs/arrays@2380

@stacksjs/audio

npm i https://pkg.pr.new/@stacksjs/audio@2380

@stacksjs/auth

npm i https://pkg.pr.new/@stacksjs/auth@2380

@stacksjs/browser

npm i https://pkg.pr.new/@stacksjs/browser@2380

@stacksjs/browser-extension

npm i https://pkg.pr.new/@stacksjs/browser-extension@2380

@stacksjs/buddy

npm i https://pkg.pr.new/@stacksjs/buddy@2380

@stacksjs/build

npm i https://pkg.pr.new/@stacksjs/build@2380

@stacksjs/cache

npm i https://pkg.pr.new/@stacksjs/cache@2380

@stacksjs/calendar-api

npm i https://pkg.pr.new/@stacksjs/calendar-api@2380

@stacksjs/charts

npm i https://pkg.pr.new/@stacksjs/charts@2380

@stacksjs/chat

npm i https://pkg.pr.new/@stacksjs/chat@2380

@stacksjs/cli

npm i https://pkg.pr.new/@stacksjs/cli@2380

@stacksjs/cloud

npm i https://pkg.pr.new/@stacksjs/cloud@2380

@stacksjs/cms

npm i https://pkg.pr.new/@stacksjs/cms@2380

@stacksjs/collections

npm i https://pkg.pr.new/@stacksjs/collections@2380

@stacksjs/commerce

npm i https://pkg.pr.new/@stacksjs/commerce@2380

@stacksjs/composables

npm i https://pkg.pr.new/@stacksjs/composables@2380

@stacksjs/config

npm i https://pkg.pr.new/@stacksjs/config@2380

@stacksjs/cron

npm i https://pkg.pr.new/@stacksjs/cron@2380

@stacksjs/database

npm i https://pkg.pr.new/@stacksjs/database@2380

@stacksjs/datetime

npm i https://pkg.pr.new/@stacksjs/datetime@2380

@stacksjs/defaults

npm i https://pkg.pr.new/@stacksjs/defaults@2380

@stacksjs/desktop-build

npm i https://pkg.pr.new/@stacksjs/desktop-build@2380

@stacksjs/dns

npm i https://pkg.pr.new/@stacksjs/dns@2380

@stacksjs/docs

npm i https://pkg.pr.new/@stacksjs/docs@2380

@stacksjs/email

npm i https://pkg.pr.new/@stacksjs/email@2380

@stacksjs/enums

npm i https://pkg.pr.new/@stacksjs/enums@2380

@stacksjs/env

npm i https://pkg.pr.new/@stacksjs/env@2380

@stacksjs/error-handling

npm i https://pkg.pr.new/@stacksjs/error-handling@2380

@stacksjs/events

npm i https://pkg.pr.new/@stacksjs/events@2380

@stacksjs/faker

npm i https://pkg.pr.new/@stacksjs/faker@2380

@stacksjs/feature-flags

npm i https://pkg.pr.new/@stacksjs/feature-flags@2380

@stacksjs/forms

npm i https://pkg.pr.new/@stacksjs/forms@2380

@stacksjs/git

npm i https://pkg.pr.new/@stacksjs/git@2380

@stacksjs/github

npm i https://pkg.pr.new/@stacksjs/github@2380

@stacksjs/health

npm i https://pkg.pr.new/@stacksjs/health@2380

@stacksjs/http

npm i https://pkg.pr.new/@stacksjs/http@2380

@stacksjs/i18n

npm i https://pkg.pr.new/@stacksjs/i18n@2380

@stacksjs/image

npm i https://pkg.pr.new/@stacksjs/image@2380

@stacksjs/lint

npm i https://pkg.pr.new/@stacksjs/lint@2380

@stacksjs/logging

npm i https://pkg.pr.new/@stacksjs/logging@2380

@stacksjs/mobile

npm i https://pkg.pr.new/@stacksjs/mobile@2380

@stacksjs/newsletter

npm i https://pkg.pr.new/@stacksjs/newsletter@2380

@stacksjs/notifications

npm i https://pkg.pr.new/@stacksjs/notifications@2380

@stacksjs/objects

npm i https://pkg.pr.new/@stacksjs/objects@2380

@stacksjs/orm

npm i https://pkg.pr.new/@stacksjs/orm@2380

@stacksjs/path

npm i https://pkg.pr.new/@stacksjs/path@2380

@stacksjs/payments

npm i https://pkg.pr.new/@stacksjs/payments@2380

@stacksjs/push

npm i https://pkg.pr.new/@stacksjs/push@2380

@stacksjs/query-builder

npm i https://pkg.pr.new/@stacksjs/query-builder@2380

@stacksjs/queue

npm i https://pkg.pr.new/@stacksjs/queue@2380

@stacksjs/realtime

npm i https://pkg.pr.new/@stacksjs/realtime@2380

@stacksjs/registry

npm i https://pkg.pr.new/@stacksjs/registry@2380

@stacksjs/repl

npm i https://pkg.pr.new/@stacksjs/repl@2380

@stacksjs/router

npm i https://pkg.pr.new/@stacksjs/router@2380

@stacksjs/scheduler

npm i https://pkg.pr.new/@stacksjs/scheduler@2380

@stacksjs/search-engine

npm i https://pkg.pr.new/@stacksjs/search-engine@2380

@stacksjs/security

npm i https://pkg.pr.new/@stacksjs/security@2380

@stacksjs/server

npm i https://pkg.pr.new/@stacksjs/server@2380

@stacksjs/shell

npm i https://pkg.pr.new/@stacksjs/shell@2380

@stacksjs/sites

npm i https://pkg.pr.new/@stacksjs/sites@2380

@stacksjs/skills

npm i https://pkg.pr.new/@stacksjs/skills@2380

@stacksjs/slug

npm i https://pkg.pr.new/@stacksjs/slug@2380

@stacksjs/sms

npm i https://pkg.pr.new/@stacksjs/sms@2380

@stacksjs/socials

npm i https://pkg.pr.new/@stacksjs/socials@2380

@stacksjs/storage

npm i https://pkg.pr.new/@stacksjs/storage@2380

@stacksjs/strings

npm i https://pkg.pr.new/@stacksjs/strings@2380

@stacksjs/testing

npm i https://pkg.pr.new/@stacksjs/testing@2380

@stacksjs/tinker

npm i https://pkg.pr.new/@stacksjs/tinker@2380

@stacksjs/tunnel

npm i https://pkg.pr.new/@stacksjs/tunnel@2380

@stacksjs/types

npm i https://pkg.pr.new/@stacksjs/types@2380

@stacksjs/ui

npm i https://pkg.pr.new/@stacksjs/ui@2380

@stacksjs/utils

npm i https://pkg.pr.new/@stacksjs/utils@2380

@stacksjs/validation

npm i https://pkg.pr.new/@stacksjs/validation@2380

@stacksjs/video

npm i https://pkg.pr.new/@stacksjs/video@2380

@stacksjs/whois

npm i https://pkg.pr.new/@stacksjs/whois@2380

commit: cffb9b2

@glennmichael123
glennmichael123 merged commit 7c22d3b into main Aug 31, 2026
11 checks passed
@glennmichael123
glennmichael123 deleted the refactor/cloud-logic-to-ts-cloud branch August 31, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

buddy Buddy core storage @stacksjs/storage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant