Skip to content

deps: upgrade ink from 6.2.0 to 6.8.0#7094

Merged
isaacroldan merged 1 commit intomainfrom
03-25-deps_upgrade_ink_from_6.2.0_to_6.8.0
Mar 26, 2026
Merged

deps: upgrade ink from 6.2.0 to 6.8.0#7094
isaacroldan merged 1 commit intomainfrom
03-25-deps_upgrade_ink_from_6.2.0_to_6.8.0

Conversation

@isaacroldan
Copy link
Contributor

@isaacroldan isaacroldan commented Mar 25, 2026

WHY are these changes introduced?

This change addresses compatibility issues with React 19 and improves the stability of UI component unmounting in the CLI toolkit.

WHAT is this pull request doing?

  • Upgrades the ink dependency from version 6.2.0 to 6.8.0 to support React 19
  • Adds concurrent: true option to the ink render function for better React 19 compatibility
  • Defers component unmounting using setImmediate() in SingleTask component and useAsyncAndUnmount hook to allow React 19 to flush batched state updates before tearing down the component tree
  • Updates the waitUntilExit promise chain in testing utilities to ensure proper cleanup

How to test your changes?

  1. Run existing CLI commands that use UI components to ensure they render and unmount properly
  2. Execute tests that use the UI testing utilities to verify they complete without hanging
  3. Test components that use async operations with UI rendering to confirm proper cleanup

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
  • Existing analytics will cater for this addition
  • PR includes analytics changes to measure impact

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@isaacroldan isaacroldan marked this pull request as ready for review March 26, 2026 10:59
@isaacroldan isaacroldan requested a review from a team as a code owner March 26, 2026 10:59
Copilot AI review requested due to automatic review settings March 26, 2026 10:59
@github-actions
Copy link
Contributor

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run pnpm changeset add to track your changes and include them in the next release CHANGELOG.

Caution

DO NOT create changesets for features which you do not wish to be included in the public changelog of the next CLI release.

@github-actions
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/private/node/constants.d.ts
@@ -8,7 +8,7 @@ export declare const environmentVariables: {
     env: string;
     firstPartyDev: string;
     noAnalytics: string;
-    appAutomationToken: string;
+    cliToken: string;
     partnersToken: string;
     runAsUser: string;
     serviceEnv: string;
packages/cli-kit/dist/public/node/environment.d.ts
@@ -10,12 +10,12 @@
  */
 export declare function getEnvironmentVariables(): NodeJS.ProcessEnv;
 /**
- * Returns the value of the SHOPIFY_APP_AUTOMATION_TOKEN environment variable,
+ * Returns the value of the SHOPIFY_CLI_TOKEN environment variable,
  * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN.
  *
- * @returns The app automation token value, or undefined if neither env var is set.
+ * @returns The CLI token value, or undefined if neither env var is set.
  */
-export declare function getAppAutomationToken(): string | undefined;
+export declare function getCliToken(): string | undefined;
 /**
  * Returns the value of the organization id from the environment variables.
  *
packages/cli-kit/dist/public/node/path.d.ts
 import type { URL } from 'url';
 /**
  * Joins a list of paths together.
  *
  * @param paths - Paths to join.
  * @returns Joined path.
  */
 export declare function joinPath(...paths: string[]): string;
 /**
  * Normalizes a path.
  *
  * @param path - Path to normalize.
  * @returns Normalized path.
  */
 export declare function normalizePath(path: string): string;
 /**
  * Resolves a list of paths together.
  *
  * @param paths - Paths to resolve.
  * @returns Resolved path.
  */
 export declare function resolvePath(...paths: string[]): string;
 /**
  * Returns the relative path from one path to another.
  *
  * @param from - Path to resolve from.
  * @param to - Path to resolve to.
  * @returns Relative path.
  */
 export declare function relativePath(from: string, to: string): string;
 /**
  * Returns whether the path is absolute.
  *
  * @param path - Path to check.
  * @returns Whether the path is absolute.
  */
 export declare function isAbsolutePath(path: string): boolean;
 /**
  * Returns the directory name of a path.
  *
  * @param path - Path to get the directory name of.
  * @returns Directory name.
  */
 export declare function dirname(path: string): string;
 /**
  * Returns the base name of a path.
  *
  * @param path - Path to get the base name of.
  * @param ext - Optional extension to remove from the result.
  * @returns Base name.
  */
 export declare function basename(path: string, ext?: string): string;
 /**
  * Returns the extension of the path.
  *
  * @param path - Path to get the extension of.
  * @returns Extension.
  */
 export declare function extname(path: string): string;
 /**
  * Parses a path into its components (root, dir, base, ext, name).
  *
  * @param path - Path to parse.
  * @returns Parsed path object.
  */
 export declare function parsePath(path: string): {
     root: string;
     dir: string;
     base: string;
     ext: string;
     name: string;
 };
 /**
  * Given an absolute filesystem path, it makes it relative to
  * the current working directory. This is useful when logging paths
  * to allow the users to click on the file and let the OS open it
  * in the editor of choice.
  *
  * @param path - Path to relativize.
  * @param dir - Current working directory.
  * @returns Relativized path.
  */
 export declare function relativizePath(path: string, dir?: string): string;
 /**
  * Given 2 paths, it returns whether the second path is a subpath of the first path.
  *
  * @param mainPath - The main path.
  * @param subpath - The subpath.
  * @returns Whether the subpath is a subpath of the main path.
  */
 export declare function isSubpath(mainPath: string, subpath: string): boolean;
 /**
  * Given a module's import.meta.url it returns the directory containing the module.
  *
  * @param moduleURL - The value of import.meta.url in the context of the caller module.
  * @returns The path to the directory containing the caller module.
  */
 export declare function moduleDirectory(moduleURL: string | URL): string;
 /**
  * When running a script using `npm run`, something interesting happens. If the current
  * folder does not have a `package.json` or a `node_modules` folder, npm will traverse
  * the directory tree upwards until it finds one. Then it will run the script and set
  * `process.cwd()` to that folder, while the actual path is stored in the INIT_CWD
  * environment variable (see here: https://docs.npmjs.com/cli/v9/commands/npm-run-script#description).
  *
  * @returns The path to the current working directory.
  */
 export declare function cwd(): string;
 /**
  * Tries to get the value of the `--path` argument, if provided.
  *
  * @param argv - The arguments to search for the `--path` argument.
  * @returns The value of the `--path` argument, if provided.
  */
 export declare function sniffForPath(argv?: string[]): string | undefined;
 /**
  * Returns whether the `--json` or `-j` flags are present in the arguments.
  *
  * @param argv - The arguments to search for the `--json` and `-j` flags.
  * @returns Whether the `--json` or `-j` flag is present in the arguments.
  */
 export declare function sniffForJson(argv?: string[]): boolean;
-/**
- * Removes any `..` traversal segments from a relative path and calls `warn`
- * if any were stripped. Normal `..` that cancel out within the path (e.g.
- * `foo/../bar` → `bar`) are collapsed but never allowed to escape the root.
- * Both `/` and `\` are treated as separators for cross-platform safety.
- *
- * @param input - The relative path to sanitize.
- * @param warn - Called with a human-readable warning when traversal segments are removed.
- * @returns The sanitized path (may be an empty string if all segments were traversal).
- */
-export declare function sanitizeRelativePath(input: string, warn: (msg: string) => void): string;
packages/cli-kit/dist/private/node/session/exchange.d.ts
@@ -25,9 +25,9 @@ export declare function exchangeAccessForApplicationTokens(identityToken: Identi
  */
 export declare function refreshAccessToken(currentToken: IdentityToken): Promise<IdentityToken>;
 /**
- * Given a custom app automation token passed as ENV variable, request a valid Partners API token.
+ * Given a custom CLI token passed as ENV variable, request a valid Partners API token.
  * This token does not accept extra scopes, just the cli one.
- * @param token - The app automation token passed as ENV variable 
+ * @param token - The CLI token passed as ENV variable 
  * @returns An instance with the application access tokens.
  */
 export declare function exchangeCustomPartnerToken(token: string): Promise<{
@@ -35,20 +35,20 @@ export declare function exchangeCustomPartnerToken(token: string): Promise<{
     userId: string;
 }>;
 /**
- * Given a custom app automation token passed as ENV variable, request a valid App Management API token.
- * @param token - The app automation token passed as ENV variable 
+ * Given a custom CLI token passed as ENV variable, request a valid App Management API token.
+ * @param token - The CLI token passed as ENV variable 
  * @returns An instance with the application access tokens.
  */
-export declare function exchangeAppAutomationTokenForAppManagementAccessToken(token: string): Promise<{
+export declare function exchangeCliTokenForAppManagementAccessToken(token: string): Promise<{
     accessToken: string;
     userId: string;
 }>;
 /**
- * Given a custom app automation token passed as ENV variable, request a valid Business Platform API token.
- * @param token - The app automation token passed as ENV variable 
+ * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token.
+ * @param token - The CLI token passed as ENV variable 
  * @returns An instance with the application access tokens.
  */
-export declare function exchangeAppAutomationTokenForBusinessPlatformAccessToken(token: string): Promise<{
+export declare function exchangeCliTokenForBusinessPlatformAccessToken(token: string): Promise<{
     accessToken: string;
     userId: string;
 }>;
packages/cli-kit/dist/public/node/toml/toml-file.d.ts
 import { JsonMapType } from './codec.js';
 /**
- * Thrown when a TOML file does not exist at the expected path.
- */
-export declare class TomlFileNotFoundError extends Error {
-    readonly path: string;
-    constructor(path: string);
-}
-/**
  * Thrown when a TOML file cannot be parsed. Includes the file path for context.
  */
 export declare class TomlParseError extends Error {
     readonly path: string;
     constructor(path: string, cause: Error);
 }
 /**
  * General-purpose TOML file abstraction.
  *
  * Provides a unified interface for reading, patching, removing keys from, and replacing
  * the content of TOML files on disk.
  *
  * - `read` populates content from disk
  * - `patch` does surgical WASM-based edits (preserves comments and formatting)
  * - `remove` deletes a key by dotted path (preserves comments and formatting)
  * - `replace` does a full re-serialization (comments and formatting are NOT preserved).
  * - `transformRaw` applies a function to the raw TOML string on disk.
  */
 export declare class TomlFile {
     /**
      * Read and parse a TOML file from disk. Throws if the file doesn't exist or contains invalid TOML.
      * Parse errors are wrapped in {@link TomlParseError} with the file path for context.
      *
      * @param path - Absolute path to the TOML file.
      * @returns A TomlFile instance with parsed content.
      */
     static read(path: string): Promise<TomlFile>;
     readonly path: string;
     content: JsonMapType;
     constructor(path: string, content: JsonMapType);
     /**
      * Surgically patch values in the TOML file, preserving comments and formatting.
      *
      * Accepts a nested object whose leaf values are set in the TOML. Intermediate tables are
      * created automatically. Setting a leaf to `undefined` removes it (use `remove()` for a
      * clearer API when deleting keys).
      *
      * @example
      * ```ts
      * await file.patch({build: {dev_store_url: 'my-store.myshopify.com'}})
      * await file.patch({application_url: 'https://example.com', auth: {redirect_urls: ['...']}})
      * ```
      */
     patch(changes: {
         [key: string]: unknown;
     }): Promise<void>;
     /**
      * Remove a key from the TOML file by dotted path, preserving comments and formatting.
      *
      * @param keyPath - Dotted key path to remove (e.g. 'build.include_config_on_deploy').
      * @example
      * ```ts
      * await file.remove('build.include_config_on_deploy')
      * ```
      */
     remove(keyPath: string): Promise<void>;
     /**
      * Replace the entire file content. The file is fully re-serialized — comments and formatting
      * are NOT preserved.
      *
      * @param content - The new content to write.
      * @example
      * ```ts
      * await file.replace({client_id: 'abc', name: 'My App'})
      * ```
      */
     replace(content: JsonMapType): Promise<void>;
     /**
      * Transform the raw TOML string on disk. Reads the file, applies the transform function
      * to the raw text, writes back, and re-parses to keep `content` in sync.
      *
      * Use this for text-level operations that can't be expressed as structured edits —
      * e.g. Injecting comments or positional insertion of keys in arrays-of-tables.
      * Subsequent `patch()` calls will preserve any comments added this way.
      *
      * @param transform - A function that receives the raw TOML string and returns the modified string.
      * @example
      * ```ts
      * await file.transformRaw((raw) => `# Header comment\n${raw}`)
      * ```
      */
     transformRaw(transform: (raw: string) => string): Promise<void>;
     private decode;
 }

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the CLI Kit’s Ink-based UI runtime to better align with React 19 behavior, focusing on improved unmount stability and more predictable test cleanup.

Changes:

  • Upgraded ink from 6.2.0 to 6.8.0 (and updated the lockfile accordingly).
  • Enabled Ink concurrent rendering by default in the CLI Kit render() wrapper (concurrent: true).
  • Deferred Ink unmounting via setImmediate() in async-completion paths and adjusted test waitUntilExit chaining to improve cleanup behavior.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pnpm-lock.yaml Locks the Ink upgrade and pulls updated transitive deps required by Ink 6.8.0.
packages/cli-kit/package.json Bumps direct dependency ink to 6.8.0.
packages/cli-kit/src/private/node/ui.tsx Forces concurrent: true for Ink rendering in the main async render() wrapper.
packages/cli-kit/src/private/node/ui/hooks/use-async-and-unmount.ts Defers exit() (Ink unmount) to next setImmediate() after async completion/failure.
packages/cli-kit/src/private/node/ui/components/SingleTask.tsx Defers Ink unmount to next setImmediate() after task resolution/rejection.
packages/cli-kit/src/private/node/testing/ui.ts Adjusts the waitUntilExit wrapper to normalize the returned promise chain for tracking/cleanup.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@isaacroldan isaacroldan force-pushed the 03-25-deps_upgrade_ink_from_6.2.0_to_6.8.0 branch from a2ac678 to 0522c84 Compare March 26, 2026 16:35
Upgrade the Ink terminal UI framework to the latest version.

Code changes required for compatibility:
- Pass concurrent: true to inkRender() (new default behavior in 6.8.0)
- Defer unmountInk() calls with setImmediate() so React 19 can flush
  batched state updates before the component tree is torn down
- Adapt waitUntilExit() return type change (.then(() => {}))

Co-authored-by: Claude Code <claude-code@anthropic.com>
@isaacroldan isaacroldan force-pushed the 03-25-deps_upgrade_ink_from_6.2.0_to_6.8.0 branch from 0522c84 to d741e24 Compare March 26, 2026 16:36
@github-actions
Copy link
Contributor

Coverage report

St.
Category Percentage Covered / Total
🟢 Statements 82.28% 15106/18360
🟡 Branches 74.83% 7451/9957
🟢 Functions 81.31% 3794/4666
🟢 Lines 82.67% 14283/17278

Test suite run success

3990 tests passing in 1527 suites.

Report generated by 🧪jest coverage report action from d741e24

@isaacroldan isaacroldan added this pull request to the merge queue Mar 26, 2026
Merged via the queue into main with commit 3a064a9 Mar 26, 2026
29 checks passed
@isaacroldan isaacroldan deleted the 03-25-deps_upgrade_ink_from_6.2.0_to_6.8.0 branch March 26, 2026 17:51
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.

3 participants