Skip to content

feat: layer the CLI as cli → sdk/adapty → sdk/core - #29

Open
gshteynardt wants to merge 1 commit into
mainfrom
feat/sdk-cli-layers
Open

feat: layer the CLI as cli → sdk/adapty → sdk/core#29
gshteynardt wants to merge 1 commit into
mainfrom
feat/sdk-cli-layers

Conversation

@gshteynardt

Copy link
Copy Markdown
Contributor

Introduce the architecture new commands are written against, without rewriting the existing ones. Three layers, one dependency arrow:

src/sdk/core framework-free mechanics: http transport with retries,
errors, session store, device flow, clock, validation
src/sdk/adapty the product: resources, models, rules
src/cli the oclif adapter: base commands, exit codes, flags, views

auth (login, logout, revoke, status, whoami) and apps (list, get, create, update) move over as the first users. oclif discovers commands only under src/commands, so each keeps a one-line re-export there; package.json switches to the pattern discovery strategy with '!/lib/', otherwise a command's private lib/ ships as a command id of its own.

The boundaries are enforced, not just described: no-restricted-imports zones in eslint.config.mjs (sdk must not see oclif or cli, core must not see products, core/http has one door, src/lib is frozen to three named bridges), test/architecture/frozen-legacy.test.ts fails on a new file in src/lib, and test/cli/command-layout.test.ts keeps a command's lib/ private to it.

Behaviour changes, all deliberate:

  • the migrated commands get their own exit-code dialect: 2 usage, 3 auth, 4 api, 5 network, 130 cancelled, where the old stack answers 1 or 2
  • --json gains source on auth status and env_token_set on auth revoke
  • auth revoke now revokes ADAPTY_TOKEN when it is set instead of ignoring it, and preserves a stored session holding a different token (README)
  • ADAPTY_TOKEN alone counts as authenticated for auth status

The manifest is otherwise unchanged against main: the same 75 command ids with the same flags and the same --json contract, compared entry by entry against a build of main. Human and --json output on the happy paths, and the requests behind them (path, query, body, headers), are byte-identical. POST and PUT are never retried, only GET and anything marked idempotent.

359 tests pass, lint clean. Layer contracts and migration state: docs/architecture.md.

@gshteynardt
gshteynardt requested a review from mlnchk September 11, 2026 08:13
Introduce the architecture new commands are written against, without
rewriting the existing ones. Three layers, one dependency arrow:

  src/sdk/core    framework-free mechanics: http transport with retries,
                  errors, session store, device flow, clock, validation
  src/sdk/adapty  the product: resources, models, rules
  src/cli         the oclif adapter: base commands, exit codes, flags, views

auth (login, logout, revoke, status, whoami) and apps (list, get, create,
update) move over as the first users. oclif discovers commands only under
src/commands, so each keeps a one-line re-export there; package.json switches
to the pattern discovery strategy with '!**/lib/**', otherwise a command's
private lib/ ships as a command id of its own.

The boundaries are enforced, not just described: no-restricted-imports zones
in eslint.config.mjs (sdk must not see oclif or cli, core must not see
products, core/http has one door, src/lib is frozen to three named bridges),
test/architecture/frozen-legacy.test.ts fails on a new file in src/lib, and
test/cli/command-layout.test.ts keeps a command's lib/ private to it.

Behaviour changes, all deliberate:

- the migrated commands get their own exit-code dialect: 2 usage, 3 auth,
  4 api, 5 network, 130 cancelled, where the old stack answers 1 or 2
- --json gains `source` on auth status and `env_token_set` on auth revoke
- auth revoke now revokes ADAPTY_TOKEN when it is set instead of ignoring
  it, and preserves a stored session holding a different token (README)
- ADAPTY_TOKEN alone counts as authenticated for auth status

The manifest is otherwise unchanged against main: the same 75 command ids
with the same flags and the same --json contract, compared entry by entry
against a build of main. Human and --json output on the happy paths, and the
requests behind them (path, query, body, headers), are byte-identical. POST
and PUT are never retried, only GET and anything marked idempotent.

359 tests pass, lint clean. Layer contracts and migration state:
docs/architecture.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant