Repository navigation
Commit eaac4cb
fix(device): QA fixes, dev sync, and request-human/human commands (#258)
* chore: merge production into dev after 5.8.0 (#236)
* ReleaseAs: 5.8.0
* Release-As: 5.8.0
* Release-As: 5.8.0
* chore(production): release 5.8.0
---------
Co-authored-by: finalerock44 <ethan@devicecloud.dev>
Co-authored-by: finalerock44 <77282157+finalerock44@users.noreply.github.com>
Co-authored-by: dcd-release-please[bot] <296541543+dcd-release-please[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* chore: bump eslint-plugin-unicorn from 77.0.0 to 78.0.0 (#239)
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 77.0.0 to 78.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](sindresorhus/eslint-plugin-unicorn@v77.0.0...v78.0.0)
---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
dependency-version: 78.0.0
dependency-type: direct:development
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* deps: bump the minor-and-patch group across 1 directory with 5 updates (#238)
Bumps the minor-and-patch group with 5 updates in the / directory:
| Package | From | To |
| --- | --- | --- |
| [@supabase/supabase-js](https://github.com/supabase/supabase-js/tree/HEAD/packages/core/supabase-js) | `2.117.3` | `2.118.0` |
| [js-yaml](https://github.com/nodeca/js-yaml) | `5.4.3` | `5.5.0` |
| [zod](https://github.com/colinhacks/zod) | `4.6.5` | `4.6.7` |
| [eslint](https://github.com/eslint/eslint) | `10.12.0` | `10.13.0` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.71.1` | `8.71.2` |
Updates `@supabase/supabase-js` from 2.117.3 to 2.118.0
- [Release notes](https://github.com/supabase/supabase-js/releases)
- [Changelog](https://github.com/supabase/supabase-js/blob/master/packages/core/supabase-js/CHANGELOG.md)
- [Commits](https://github.com/supabase/supabase-js/commits/v2.118.0/packages/core/supabase-js)
Updates `js-yaml` from 5.4.3 to 5.5.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](nodeca/js-yaml@5.4.3...5.5.0)
Updates `zod` from 4.6.5 to 4.6.7
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](colinhacks/zod@v4.6.5...v4.6.7)
Updates `eslint` from 10.12.0 to 10.13.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](eslint/eslint@v10.12.0...v10.13.0)
Updates `typescript-eslint` from 8.71.1 to 8.71.2
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.2/packages/typescript-eslint)
---
updated-dependencies:
- dependency-name: "@supabase/supabase-js"
dependency-version: 2.118.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor-and-patch
- dependency-name: eslint
dependency-version: 10.13.0
dependency-type: direct:development
update-type: version-update:semver-minor
dependency-group: minor-and-patch
- dependency-name: js-yaml
dependency-version: 5.5.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: minor-and-patch
- dependency-name: typescript-eslint
dependency-version: 8.71.2
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: minor-and-patch
- dependency-name: zod
dependency-version: 4.6.7
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: minor-and-patch
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat(login): reuse the last org and add --org (#243)
* feat(login): reuse the last org and add --org
dcd login no longer hangs where nobody can answer a prompt, such as a
script, CI, or a shell an agent runs.
- The org picker starts on the org from the last login, so Enter keeps it.
- Without a TTY, the last login's org is used and one line says so. With
no last org, or one that is gone, login fails with an error that names
--org and lists the available orgs.
- --org <name|id> picks the org without the picker, and fails if the user
isn't a member.
- Without a TTY, the "already logged in" confirm takes its default and
signs in again. The old session stays until the new login succeeds.
- The last org only counts when the last login was to the same API,
because org ids differ between environments.
- A bare dcd switch-org without a TTY now fails with the org names instead
of hanging the same way.
Closes #241
* chore(deps): bump hono override to 4.13.11 to clear audit
pnpm audit flagged GHSA-5r4p-p66f-jhc7 (moderate) on hono >=4.12.4
<4.13.11, which comes in through @modelcontextprotocol/sdk. In those
versions serveStatic decodes the request path twice. The advisory was
published on 2026-10-20, after dev's last green run, so the
lint-and-test audit step now fails on every branch. Dependabot opened an
alert but no fix PR, because the exact-pin override holds hono at
4.13.7.
4.13.11 is the lowest patched version, as with the earlier pins. The
audit passes apart from the advisory that was already ignored. Lint,
typecheck, unit tests and build pass, and dcd-mcp answers initialize
and tools/list over stdio with all five tools.
* feat(auth): fetch the Supabase key from the API instead of compiling it in (#245)
Every release so far compiled the Supabase anon key in, so the key could
not be rotated without breaking pinned CLI versions (dcd#1112). The CLI
now fetches its publishable key from the API's public GET /cli-config,
once per process, so a rotation is an env change on the API.
- The key is kept in memory only. A stale on-disk copy would make a
session refresh fail with a 4xx, which drops the user's login.
- A failed key fetch during refresh is a retryable error, never a
definitive one, so the stored session survives.
- Supabase URLs stay pinned (prod uses the cloud.devicecloud.dev custom
domain); only the key comes from the API.
- Raw Storage/Auth requests send an sb_publishable_ key as `apikey`
only, and a legacy JWT key as a Bearer too.
- Realtime keeps a synchronous subscribe() and connects once the key
arrives; until then the backstop poll covers it.
- The anon keys stay in the gitleaks allowlist, relabelled: they remain
in history, which CI scans in full.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: skip promotion-pin on release-please PRs (#249)
Release-please's release PR targets production but is not a promotion,
so the Release-As pin check always failed on it (#230, #247).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(encrypt): list --encrypt in --help now encryption is on by defau… (#250)
feat(encrypt): list --encrypt in --help now encryption is on by default (dcd#1138)
The API now sends encryption.defaultOn = true for every org, not only orgs in
the client_encryption beta, so the beta-only pieces come out:
- --encrypt is listed in `dcd cloud --help` and `dcd upload --help` again,
and its description says it is on by default and that --no-encrypt or
DCD_ENCRYPT=0 turns it off. The hidden-arg filter (src/utils/help.ts),
which only ever hid this flag, is removed; flags go back to citty's ArgsDef.
- The notice drops "(beta)": "Encrypting uploads; opt out with --no-encrypt"
(and "encrypt: false" from the MCP tool). It still prints only when the
server default turned encryption on, and --json still suppresses it.
- The KEK error messages, the MCP encrypt input and comments say "the
default" or "the server default" instead of "the organization default".
- server.json lists DCD_ENCRYPT, so MCP users can find the opt-out.
- environments.ts no longer says the KEK is "left null until generated";
it describes how to rotate.
resolveEncryption is unchanged: flag, then DCD_ENCRYPT, then the server
default, then off. The default stays server-side so the API's
CLIENT_ENCRYPTION_DEFAULT=off kill switch keeps working for every CLI.
src/types/generated/schema.types.ts still carries the beta wording in one
JSDoc description; a full regeneration would pull in unrelated API surface,
so it waits for the next one.
* feat: fetch the KEK public key from the API instead of pinning it (#251)
The CLI pinned one KEK public key per environment, so every KEK rotation
needed a CLI release that customers then had to pick up. GET /cli-config
now publishes the newest KEK the API holds the private half of
(binary_kek_public_key), and the CLI wraps uploads with whatever the API it
talks to serves, fetched once per process alongside the Supabase key.
DCD_BINARY_KEK_PUBLIC still overrides for an API that publishes nothing.
An API that publishes no key keeps the old behaviour (explicit --encrypt
fails, env/org-default encryption skips with a notice); an API that cannot
be asked at all fails the run rather than silently uploading plaintext.
* chore: merge production into dev after 5.9.0 (#248)
* ReleaseAs: 5.8.0
* Release-As: 5.8.0
* Release-As: 5.8.0
* chore(production): release 5.8.0
* chore: pin the 5.9.0 promotion
Release-As: 5.9.0
* chore(production): release 5.9.0
---------
Co-authored-by: finalerock44 <ethan@devicecloud.dev>
Co-authored-by: finalerock44 <77282157+finalerock44@users.noreply.github.com>
Co-authored-by: dcd-release-please[bot] <296541543+dcd-release-please[bot]@users.noreply.github.com>
Co-authored-by: Tom Riglar <tom.riglar@moropo.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* deps: patch ip-address advisory (#256)
Bump the transitive ip-address from 10.7.3 to 10.7.4 for
GHSA-rxp7-6hxx-x8q5. express-rate-limit's ^10.2.0 range already allows
it, so only the lockfile changes.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: authenticate the Claude action by workload identity federation (#255)
Swap the CLAUDE_CODE_OAUTH_TOKEN secret for the action's built-in OIDC
exchange, so the workflows need no stored secret.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore: merge production into dev after 5.10.0 (#254)
* ReleaseAs: 5.8.0
* Release-As: 5.8.0
* Release-As: 5.8.0
* chore(production): release 5.8.0
* chore: pin the 5.9.0 promotion
Release-As: 5.9.0
* chore(production): release 5.9.0
* chore: pin the 5.10.0 promotion
Release-As: 5.10.0
* chore(production): release 5.10.0
---------
Co-authored-by: finalerock44 <ethan@devicecloud.dev>
Co-authored-by: finalerock44 <77282157+finalerock44@users.noreply.github.com>
Co-authored-by: dcd-release-please[bot] <296541543+dcd-release-please[bot]@users.noreply.github.com>
Co-authored-by: Tom Riglar <tom.riglar@moropo.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* ci: authenticate the Claude action with the org CLAUDE_CODE_OAUTH_TOKEN (#257)
Back from workload identity federation to the OAuth token, now an org-level
secret. Federation bills the Anthropic API org's purchased credit, which
promotional credit doesn't cover for Claude Code, so reviews were failing
with "Credit balance is too low".
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(auth): keep the stored session when a refresh fails
A refused refresh used to delete the session from config.json. Old
builds hit that on every refresh once Supabase turned off legacy keys
("Legacy API keys are disabled"), so the session was wiped even though
an upgrade alone would have fixed it. Now only `dcd logout` (or the
next `dcd login`) replaces the stored session. The error still tells
the user to log in again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
* fix(device): show run results as one line per flow
`dcd device run` printed the runner's raw JSON under "Output" on a pass
and under "Error" on a failed directory run, env_vars included. It now
reads that report (or `result.flows`, when the API sends it) and prints
each flow with passed or failed and the reason, plus a short summary.
The failure message names the failing flows. --json still carries the
API's full result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
* fix(device): leave session out of --json for list, models and stop --all
`dcd device list --json` printed a stray "session": null, as if the
command were about one session. Commands that are not about one session
now leave the key out. Every other command's envelope is unchanged, and
errors still carry session (null when the API sent none).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
* fix(device): infer the platform from --model
`dcd device start --model iphone-16` failed with "--platform is
required". Without --platform, start now looks the model up in
GET /device/models (by id or name) and uses its platform. It is still a
usage error when the model is unknown or exists on both platforms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
* fix(device): warn when the video and log are still uploading
Right after `dcd device stop`, `dcd device artifacts` downloaded only
the per-action screenshots; the video and device log landed about 45s
later, with no word that they were coming. It now warns "The video and
device log are still uploading. Run this again in a minute." and puts
`pending` and `warning` in --json. It reads the API's new `pending`
field. An older API gets a guess instead: an ended session missing
either file whose last activity was under three minutes ago.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
* feat(device): add request-human and human, like the MCP tools
The MCP server has request_human and get_human_status; the CLI had
nothing, though session warnings told CLI users to wait for a person.
- `dcd device request-human "<reason>" [id] [--wait]` asks a person for
help (POST .../request-human).
- `dcd device human [id] [--wait]` shows whether the session waits for a
person, who has control, when it ends, and the hand-back note.
- --wait checks every 5s until the person hands back or the session
ends (exit 4). Ctrl-C stops waiting and leaves the session open.
- `dcd device status` shows the hand-back note, and --json carries it.
- A command refused with 409 LIVE_HUMAN_IN_CONTROL now says a person has
control and to run `dcd device human <id> --wait`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xsPHeqEEpmiNy9YvGFDwB
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dcd-release-please[bot] <296541543+dcd-release-please[bot]@users.noreply.github.com>
Co-authored-by: finalerock44 <ethan@devicecloud.dev>
Co-authored-by: finalerock44 <77282157+finalerock44@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>1 parent a1348a2 commit eaac4cb
55 files changed
Lines changed: 2561 additions & 776 deletions
File tree
- .github/workflows
- .husky
- src
- commands
- config
- flags
- gateways
- mcp/tools
- services
- types/domain
- utils
- test/unit
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
79 | 84 | | |
80 | 85 | | |
81 | 86 | | |
82 | 87 | | |
83 | 88 | | |
| 89 | + | |
84 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
85 | 99 | | |
86 | 100 | | |
87 | 101 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
116 | 119 | | |
117 | | - | |
| 120 | + | |
118 | 121 | | |
119 | 122 | | |
120 | 123 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
11 | 8 | | |
12 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
13 | 15 | | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
25 | | - | |
| 27 | + | |
26 | 28 | | |
| 29 | + | |
27 | 30 | | |
28 | 31 | | |
29 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
3 | 60 | | |
4 | 61 | | |
5 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
113 | | - | |
| 113 | + | |
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| |||
0 commit comments