feat(apps): show UI extensions and install URL in apps view#377
Merged
Conversation
Expand `td apps view <ref>` so that when an integration ships UI extensions, the view lists each extension (name + type and variant sub-type, e.g. `context-menu: project`, `composer: task`, `settings`) and prints the installable URL (`https://app.todoist.com/app/install/<distribution_token>`) — the link shared so others can install the integration. The distribution token is reclassified as non-secret (it is the basis of a shareable install link by design): it is now always fetched and the install URL is shown by default, no longer gated behind `--include-secrets`. The genuinely sensitive credentials (client secret, verification token, test token) stay hidden by default. `--json` / `--ndjson` now always carry `uiExtensions`, `distributionToken`, and `installUrl` (null when the app has no UI extensions).
doistbot
reviewed
Jun 2, 2026
doistbot
left a comment
Member
There was a problem hiding this comment.
Thanks Scott for surfacing UI extensions and shareable install links in the apps view 😎 👊.
Few things worth tightening:
- Register
getUiExtensionsForAppinAPI_SPINNER_MESSAGESandMETHOD_REQUIRED_FLAGwithinsrc/lib/api/core.tsto ensure API errors are formatted correctly and missing permissions prompt for theapp-managementscope. - Defer fetching the distribution token in the default plain-text flow until after confirming the app has UI extensions to avoid an unnecessary API call.
I also included a few optional follow-up notes in the details below.
Optional follow-up notes (3)
- [P3] src/commands/apps/view.ts:28: The
defaultbranch drops exhaustiveness on the SDK’sUiExtensiondiscriminated union. If a new extension type is added upstream, this helper will keep compiling and silently render a partial label instead of forcing us to handle the new shape. Prefer explicit branches for the current variants plus aneverfallback so SDK additions fail at compile time. - [P3] src/lib/skills/content.ts:354: This description now overstates the plain-output behavior.
view.tsonly renders the install link when the app has UI extensions, but this says the distribution token is "always shown." SinceSKILL_CONTENTis the source of truth for agents, tighten the wording to distinguish plain output (install URL only when UI extensions exist) from JSON, wheredistributionTokenis always present. - [P3] src/commands/apps/apps.test.ts:551: This fixture hand-builds the full SDK
UiExtensionshape even though these tests only assertname,extensionType, and the subtype field. That makes the suite noisy and brittle to unrelated SDK field changes. A small localmakeUiExtension(...)helper (or shared fixture if you want to reuse it) would keep each case focused on just the fields under test.
- Register getUiExtensionsForApp in API_SPINNER_MESSAGES and METHOD_REQUIRED_FLAG (core.ts) so its errors get CliError formatting and a 403 prompts for the app-management scope. - Defer the distribution-token fetch: only call it when the app has UI extensions (plain output) or for --json/--ndjson, avoiding an unnecessary round-trip in the common no-extensions path. - Make formatExtensionType exhaustive over the UiExtension union with a never fallback so new SDK variants fail at compile time. - Tighten SKILL_CONTENT wording: install URL appears in plain output only when UI extensions exist; distributionToken is always present in JSON. - Refactor test fixtures behind a makeUiExtension helper.
doist-release-bot Bot
added a commit
that referenced
this pull request
Jun 2, 2026
## [1.72.0](v1.71.0...v1.72.0) (2026-06-02) ### Features * **apps:** show UI extensions and install URL in `apps view` ([#377](#377)) ([53d9fe6](53d9fe6))
Contributor
|
🎉 This PR is included in version 1.72.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Expand
td apps view <ref>so that when an integration ships UI extensions, the view:<name> (<type>[: <sub-type>]), where type iscontext-menu/composer/settingsand sub-type is thecontext-menucontext (project/task) orcomposerlocation (task/comment). Settings extensions have no sub-type.https://app.todoist.com/app/install/<distribution_token>) — the link an integration owner shares so others can install it. This is required for any integration with UI extensions.When an app has no UI extensions, neither the section nor the install URL is shown.
Why
The view previously omitted the install URL entirely, which is required to distribute an integration that has UI extensions. The SDK already exposes
getUiExtensionsForApp(previously unused) to detect them; the install URL mirrors howtodoist-webbuilds it (<origin>/app/install/<distribution_token>).Distribution token reclassified as non-secret
The distribution token is the basis of a shareable install link by design, so it is now:
--include-secrets)Install URLline /installUrlJSON field by defaultThe genuinely sensitive credentials — client secret, verification token, test token — remain hidden by default.
Output
--json/--ndjsonnow always carryuiExtensions,distributionToken, andinstallUrl(nullwhen the app has no UI extensions).Testing
npm run type-check✅npm run check(lint + format) ✅npm run sync:skill