Skip to content

feat: account-backed CLI with provider profiles and CLI device management - #1258

Merged
ital0 merged 33 commits into
mainfrom
ital0/cli-account-client
Sep 4, 2026
Merged

feat: account-backed CLI with provider profiles and CLI device management#1258
ital0 merged 33 commits into
mainfrom
ital0/cli-account-client

Conversation

@ital0

@ital0 ital0 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@ital0 ital0 self-assigned this Sep 2, 2026
@ital0
ital0 force-pushed the ital0/cli-account-client branch 2 times, most recently from 77685ad to 1107cb4 Compare September 2, 2026 22:03
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Semgrep Security Scan

No security issues found.

@ital0
ital0 marked this pull request as ready for review September 2, 2026 22:04
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Preview environment destroyed 🧹

Stack preview-pr-1258 and its Cloudflare subdomain have been cleaned up.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Metrics

Metric Value
Lines changed (prod code) +8729 / -1890
JS bundle size (gzipped) 🟢 639.6 KB → 639.8 KB (+183 B, +0.0%)
Test coverage 🟢 82.01% → 82.14% (+0.1%)
Performance (preview) Preview not ready — Render deploy may have timed out
Accessibility
Best Practices
SEO

Updated Fri, 04 Sep 2026 02:46:44 GMT · run #2912

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔭 thunder-deep-review (advisory)

Reviewed the diff — no issues to report. ✅ Never approves, never requests changes, never gates merge.
head: eb5e31cdc29f · mode: deep · deferred 0 item(s) already reported by other bots (best-effort dedup)

@ital0
ital0 force-pushed the ital0/cli-account-client branch from eb5e31c to 2456279 Compare September 3, 2026 21:46

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔭 thunder-deep-review (advisory)

Complements the other bots — surfaces only what they did not flag. Never approves, never requests changes, never gates merge.
head: 24562797370c · mode: deep · deferred 0 item(s) already reported by other bots (best-effort dedup)

Comment thread cli/package.json Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔭 thunder-deep-review (advisory)

Reviewed the diff — no issues to report. ✅ Never approves, never requests changes, never gates merge.
head: c3ad1ec72b47 · mode: deep · deferred 0 item(s) already reported by other bots (best-effort dedup)

ital0 added 17 commits September 4, 2026 01:51
…clave

- The proxy copied every inbound header except a short denylist, so
  X-App-Version, X-App-Language, X-Device-ID and X-Device-Name reached the
  external enclave even though they are outer-hop headers for our backend
- Keep them out of the upstream request and pin the behaviour with a route test
- Sessions minted by the device-authorization grant were accepted by the
  inference, Tinfoil and usage-receipt routes without ever binding a CLI
  device, which let a modified client escape the device cap, the device
  list and device-scoped revocation
- Mark grant sessions server-side, let only the CLI registration flow
  replace that marker, and gate the managed routes behind one shared check
  that answers 409 CLI_DEVICE_NOT_BOUND while the registration flag is on
- Web sessions, personal access tokens, anonymous sessions and flag-off
  deployments are unaffected; integration tests cover each path
…ackend

- The cli- prefix and canonical UUID check were spelled out twice, so the
  two contracts could drift independently
- Move the validator into shared/ and import it from both sides
- A login that resolved to a different account reused the stored device id,
  hit 409 DEVICE_ID_TAKEN and could never recover; rotate the installation
  once on that conflict exactly like a revoked device
- Logout now honours the compare-and-set result instead of claiming success
  over a newer credential, and handles 409 CLI_DEVICE_NOT_BOUND for legacy
  credentials that were never bound to a device
- The auth and provider-config writers only serialised mutations inside one
  process, so two concurrent CLI invocations could both match the same
  predecessor and overwrite each other's transition
- Guard both files with an exclusive lock in secure-fs that recovers from
  dead owners without letting two contenders reclaim the same stale lock
- Cross-process tests drive real child processes through a deterministic
  stdout/stdin barrier instead of polling the filesystem
- Only 127.0.0.1 counted as loopback, so valid local self-host endpoints
  such as 127.0.0.2 were rejected as insecure plain HTTP
- Document backendHeaders while touching the module
…ntry

- The confidential binding borrowed compatibility and thinking metadata from
  a hard-coded GLM 5.2 Pi model, so any other confidential catalog entry
  would silently be sent the wrong payload
- Resolve the Pi model from the entry's own vendor and model identity instead
- A transient failure while submitting a confidential usage receipt dropped
  it for good, leaving the quota ledger under-counted
- Queue completed receipts under THUNDERBOLT_HOME per installation, retry
  with bounded backoff, flush on the next run, and report persistence
  failures instead of swallowing them
- Only 401 consults the authentication observer once and keeps the receipt;
  403 means the receipt belongs to another user and is discarded without
  touching the current session
- The observer that persists credential status ran inside an empty catch, so
  a failed durable write left stale auth state with no trace
- Log the failure while still returning the provider response; tests
  suppress and assert the expected error
- The one-line activity header rendered a model-controlled command through a
  sanitizer that preserves newlines and tabs, so a multiline command could
  draw fake status or prompt lines
- Reuse the newline-safe sanitizer the permission renderer already uses
…r login

- A one-shot prompt given in argv printed nothing and exited 0 when stdin was
  already closed, because readline EOF aborted the shared terminal signal;
  EOF now only settles pending reads, and a real interruption exits 130
- A clean-state `thunderbolt login` left no active provider, so the default
  managed prompt refused to run; login now activates Thunderbolt unless a
  provider was already chosen explicitly
- Replace promise-chain catches with try/catch in the catalog client and the
  rejection-capturing tests, await the steering-mode setup instead of
  floating it, and give the command switch a throwing never default so a
  new parser variant cannot silently do nothing
- Wait on the disposal completion signal instead of a scheduler yield in the
  provider-stage test
- Assigning undefined to import.meta.env made Bun expose the string
  "undefined", so the client identity prompt rendered "App version:
  undefined" and the suite failed depending on file order
- Restore the env in a Bun-safe way and normalise a missing version at the
  identity boundary for both the prompt and the X-App-Version header
- The one-call-site helper claimed to identify pairable device types but
  excluded bridges, so the caller patched it back; state the condition
  directly and drop the helper
- The CLI now imports shared/agent-core and shared/cli-device-id, so a change
  there must trigger the CLI typecheck, tests and build
@ital0
ital0 force-pushed the ital0/cli-account-client branch from 4c09432 to 6bb631c Compare September 4, 2026 02:00
…rver

- Bun 1.3.14 releases an AbortSignal.timeout timer once its only listener is
  removed, so the receipt submission hung when the 401 observer stalled and
  the CLI test suite timed out in CI
- Hold a listener for the whole fetch-plus-observer operation, as the
  account client already does, and cover the two-phase deadline with a test
@ital0
ital0 merged commit dbdc545 into main Sep 4, 2026
31 of 32 checks passed
@ital0
ital0 deleted the ital0/cli-account-client branch September 4, 2026 12:38
darkbanjo added a commit that referenced this pull request Sep 4, 2026
main landed the account-backed CLI (#1258), which conflicted in
src/hooks/use-app-initialization.ts. One hunk, both sides wanted: main wrapped
`cloudUrl` in `normalizeBackendUrl`, this branch added
`experimental_feature_mini_apps` to the settings read. Kept both.

Note that a conflicting PR runs no CI at all — GitHub computes a merge ref for
`pull_request` workflows and can't produce one while the branch is dirty, so CI,
E2E, Security, PR Metrics and thunder-deep-review are simply absent rather than
failing. That is the second time this has stalled the branch silently, so it is
worth checking mergeability whenever the checks look thinner than expected
rather than assuming a partial green.

Verification: tsc clean at root and backend, lint 0 errors, 5077 frontend tests
pass with only the known pre-existing query-plan failure, 1353 backend tests
pass, catalogs re-extracted.
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