Skip to content

feat: adopt cli-core DCR provider + account command attachers#5

Merged
scottlovegrove merged 4 commits into
mainfrom
scottl/account-attachers
May 25, 2026
Merged

feat: adopt cli-core DCR provider + account command attachers#5
scottlovegrove merged 4 commits into
mainfrom
scottl/account-attachers

Conversation

@scottlovegrove
Copy link
Copy Markdown
Collaborator

@scottlovegrove scottlovegrove commented May 25, 2026

Summary

Ports two cli-core adoption changes from twist-cli (weekend of 2026-05-22) into comms-cli, bundled into one PR. Bumps @doist/cli-core 0.16.1 → 0.24.0 and adds oauth4webapi as a direct dependency.

Upstream PRs ported here:

comms-cli is a hard fork of twist-cli; this is part of porting the weekend's twist-cli work over. (twist-cli#248 / #251 — the test-scaffolding dedupe — follow in a separate PR.)

feat(auth): adopt cli-core createDcrProvider (twist-cli#243)

  • Replace the bespoke DCR AuthProvider (hand-rolled registration, PKCE authorize, HTTP Basic token exchange) with cli-core's createDcrProvider, driven by oauth4webapi. The only comms-specific piece left is validate, which probes getSessionUser and derives authMode/authScope from the folded handshake.readOnly via a shared getScopes().
  • Use client_secret_post (not the default client_secret_basic): client_ids can contain _, which the basic form url-encodes (_%5F) and the token endpoint doesn't decode.
  • Thread the 0.24.0 TokenStore contract through the store override + test mocks (clear() → ClearedAccount | null, required activeAccount/setBundle/activeBundle).

refactor(account): adopt cli-core account attachers (twist-cli#250)

  • Replace hand-rolled list/use/remove/current with attachAccount*Command; delete those four files. Adopt cli-core's JSON envelopes ({accounts,default}, {ok,default}, {ok,removed}).
  • No legacy-auth machinery here (comms shipped multi-account from day one), so the upstream withLegacyGuard/assertV2Available is dropped. comms' manual-token model is adapted into the attacher hooks: current reports source: token-only, list hides identity-less rows.
  • Add an activeAccount() store override (env → null) mirroring active()/activeBundle(); forward clear()'s ClearedAccount through withUserRefAware.

docs: add CODEBASE.md (part of twist-cli#250)

  • Descriptive ~2000-token repo map (matching the cli-core / todoist-cli style), written from the actual comms-cli codebase.

Test plan

  • npm run type-check
  • npm run lint:check (oxlint + oxfmt) — 0 warnings/errors
  • npm test — 630 tests pass (37 files)

🤖 Generated with Claude Code

scottlovegrove and others added 3 commits May 25, 2026 09:42
Replace the bespoke DCR AuthProvider (hand-rolled registration, PKCE
authorize, HTTP Basic token exchange) with cli-core's createDcrProvider,
driven by oauth4webapi. The only comms-specific piece left is validate,
which probes getSessionUser and derives authMode/authScope from the
folded handshake.readOnly via a shared getScopes() helper.

Use client_secret_post (not the default client_secret_basic): client_ids
can contain underscores, which the basic form url-encodes (_ -> %5F) and
the token endpoint doesn't decode, breaking the lookup.

Bump @doist/cli-core 0.16.1 -> 0.24.0 and add oauth4webapi as a direct
dependency. The 0.24.0 TokenStore contract change (clear() ->
ClearedAccount | null, required activeAccount/setBundle/activeBundle) is
threaded through the store override and test mocks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the hand-rolled account list/use/remove/current commands with
cli-core's attachAccount*Command, deleting list.ts/use.ts/remove.ts/
current.ts. The attachers own the command action and JSON envelopes
({accounts,default} for list, {ok,default} for use, {ok,removed} for
remove), so comms-specific behaviour moves into their hooks:

- current: env-token resolves as null from activeAccount() and renders
  the env notice via onNotAuthenticated; an identity-less manual-token
  account (empty id/label, persisted by `tdc auth token`) stays a
  resolved account and is special-cased in renderText/renderJson as
  source: token-only.
- list: wrapped so manual-token snapshots stay out of the roster.
- remove: onRemoved surfaces the keyring-fallback warning on stderr.

Add an activeAccount() override to the store (env -> null) mirroring
active()/activeBundle(), and forward clear()'s ClearedAccount return
through withUserRefAware.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Descriptive ~2000-token orientation file (matching the cli-core /
todoist-cli style) so agents and humans can navigate the repo without
exploring. Covers the lazy command registry, command/lib catalogs, ref
resolution, the env-token + manual-token auth path, testing, and the
skill-content flow. Complements AGENTS.md (prescriptive rules).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove self-assigned this May 25, 2026
@doistbot doistbot requested a review from craigcarlyle May 25, 2026 08:58
@scottlovegrove scottlovegrove requested a review from amix May 25, 2026 09:00
Copy link
Copy Markdown
Member

@doistbot doistbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR successfully ports the cli-core DCR provider and account command attachers, standardizing the multi-account workflows while removing bespoke boilerplate. Adopting upstream JSON envelopes and shared attachers significantly improves maintainability and aligns the project with other Doist CLI tools. A few areas could use minor refinement, including addressing edge cases with --ndjson output and hidden manual-token targeting, extracting duplicated logout result logic, utilizing public Commander APIs for default commands, and expanding test coverage for the new account store logic.

Share FeedbackReview Logs

Comment thread src/commands/account/index.ts
Comment thread src/commands/account/index.ts
Comment thread src/commands/account/index.ts Outdated
Comment thread src/commands/account/index.ts
Comment thread src/commands/account/index.ts
Comment thread src/lib/auth-provider.test.ts
Address review feedback on the account-attacher refactor:

- matchCommsAccount() now never matches an identity-less manual-token
  account, so an empty-ish ref (`""`, `id:`) passed to `account use` /
  `remove` can't target a row that `list` deliberately hides.
- Extract the shared `logStoredTokenRemoval` helper (auth/helpers.ts) so
  `auth logout`'s onCleared and `account remove`'s onRemoved can't drift.
- Add tests: manual-token rows hidden from `account list` (human + json),
  the matchCommsAccount manual-token guard, and the store's activeAccount()
  env-token short-circuit + delegation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove merged commit 4749a07 into main May 25, 2026
5 checks passed
@scottlovegrove scottlovegrove deleted the scottl/account-attachers branch May 25, 2026 09:35
doist-release-bot Bot added a commit that referenced this pull request May 25, 2026
## 1.0.0 (2026-05-25)

### Features

* add channel create and update commands ([#4](#4)) ([f097378](f097378))
* adopt cli-core DCR provider + account command attachers ([#5](#5)) ([4749a07](4749a07))
* bootstrap Comms CLI from twist-cli ([ea28735](ea28735))
* upgrade to @doist/comms-sdk@0.2.0 ([#2](#2)) ([ae4d6e1](ae4d6e1))
@doist-release-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Copy link
Copy Markdown
Member

@amix amix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would have been great to seperate these in two distinct PRs.

I also think we should remove CODEBASE.md; this can quickly become stale 👍

@scottlovegrove
Copy link
Copy Markdown
Collaborator Author

I also think we should remove CODEBASE.md; this can quickly become stale

It hasn't on any of the repos I've added it into because when new things get added, or stuff gets removed, the codebase.md gets updated by the agent, and the agent is actually who the file is for in the first place.

@craigcarlyle
Copy link
Copy Markdown

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants