Keep the installed Shopify skill up to date daily#8164
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
582d2ed to
ef9d38e
Compare
747c1c1 to
e11a831
Compare
2a6aac3 to
62e16f4
Compare
|
/snapit |
|
🫰✨ Thanks @alfonso-noriega! Your snapshot has been published to npm. Test the snapshot by installing your package globally: pnpm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260723193923Caution After installing, validate the version by running |
Add a 'shopify skill update' command wrapping 'skills update shopify --global --yes', which compares the recorded install hash in the skills lock file against the remote source tree and only rewrites the skill when it has changed. The prerun hook spawns it detached in the background at most once per day whenever the skill is installed, so an outdated local skill converges to the remote source within a day. Opt out with SHOPIFY_CLI_NO_SKILL_AUTO_UPDATE. Assisted-By: devx/8a5f8cc7-d76e-49ff-a591-4193978ea1b9
Replace the skills-CLI update delegation with a direct conditional GET against the skill source URL: send If-None-Match with the ETag recorded on the last update, treat 304 as up to date, and on 200 write the body over the installed universal SKILL.md, which propagates to every agent through the install-time symlinks. This works with any HTTP host, so the source can move off GitHub without changing the mechanism. The first check after installing has no recorded ETag and compares content directly, so unchanged bodies never report as updates. Assisted-By: devx/8a5f8cc7-d76e-49ff-a591-4193978ea1b9
Drop the recorded-ETag conditional GET: ETags are opaque per RFC 9110 and not derivable from the installed file (verified: neither GitHub raw nor shopify.dev ETags match a content hash), so they forced hidden state in conf-store. Instead fetch the source unconditionally and byte-compare with the installed SKILL.md, writing it over only when it differs. The installed file is now the only state, at the cost of a small daily download. Assisted-By: devx/8a5f8cc7-d76e-49ff-a591-4193978ea1b9
Background skill updates run detached with their output discarded, so a successful update was invisible. The background spawn now passes a hidden --background flag to skill update, which records a pending announcement instead of printing; the prerun hook renders it once as an info banner on the next command and clears it. Foreground skill update runs keep printing directly. Assisted-By: devx/8a5f8cc7-d76e-49ff-a591-4193978ea1b9
Checking whether the remote skill changed requires downloading its content, and once the content is in hand applying the update is a single file write, so a detached background process no longer buys anything. Run the daily check inline in prerun with a 3-second time-boxed fetch, write the skill when it changed, and announce the update immediately in the same command. This deletes the async relay: the hidden --background flag, the pending-announcement conf key, and the announce-on-next-run hook step. Assisted-By: devx/8a5f8cc7-d76e-49ff-a591-4193978ea1b9
e11a831 to
7bdeb70
Compare
62e16f4 to
95603fc
Compare
|
/snapit |
Differences in type declarationsWe 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:
New type declarationspackages/cli-kit/dist/public/node/skills.d.tsimport { LocalStorage } from './local-storage.js';
import { ConfSchema } from '../../private/node/conf-store.js';
/**
* Options for {@link promptShopifySkillInstallIfNeeded}.
*/
export interface PromptShopifySkillInstallOptions {
/** The command being run, used to avoid prompting recursively from `skill` commands. */
currentCommand: string;
/** The arguments of the command being run, used to avoid corrupting `--json` output. */
args?: string[];
/** The process argv, used to re-invoke the current CLI binary. */
argv?: string[];
/** The process environment. */
env?: NodeJS.ProcessEnv;
/** The cli-kit local storage, injectable for testing. */
config?: LocalStorage<ConfSchema>;
/** The user's home directory, injectable for testing. */
homeDir?: string;
}
/**
* Checks whether the Shopify skill for coding agents is installed globally.
*
* The skills CLI installs universal skills under `~/.agents/skills` (older versions)
* or `$XDG_CONFIG_HOME/agents/skills` (newer versions), so both locations are checked.
*
* @param env - The process environment.
* @param homeDir - The user's home directory.
* @returns Whether the Shopify skill is installed in any known global location.
*/
export declare function shopifySkillIsInstalled(env?: NodeJS.ProcessEnv, homeDir?: string): boolean;
/**
* The outcome of a Shopify skill update check.
*/
export type ShopifySkillUpdateResult = 'updated' | 'already-up-to-date' | 'not-installed';
/**
* Options for {@link updateShopifySkill}.
*/
export interface UpdateShopifySkillOptions {
/** The process environment. */
env?: NodeJS.ProcessEnv;
/** The user's home directory, injectable for testing. */
homeDir?: string;
}
/**
* Updates the installed Shopify skill when its remote source has changed.
*
* Fetches the skill source and compares it with the installed universal skill
* file, writing it over only when the content differs. The installed file is
* the only state involved, and updating it propagates to every agent through
* the symlinks created at install time.
*
* @param options - See {@link UpdateShopifySkillOptions}.
* @returns The outcome of the update check.
*/
export declare function updateShopifySkill(options?: UpdateShopifySkillOptions): Promise<ShopifySkillUpdateResult>;
/**
* Options for {@link updateShopifySkillIfNeeded}.
*/
export interface UpdateShopifySkillIfNeededOptions {
/** The command being run, used to avoid updating recursively from `skill` commands. */
currentCommand: string;
/** The process environment. */
env?: NodeJS.ProcessEnv;
/** The cli-kit local storage, injectable for testing. */
config?: LocalStorage<ConfSchema>;
/** The user's home directory, injectable for testing. */
homeDir?: string;
}
/**
* Keeps an installed Shopify skill up to date, checking the remote source at most
* once per day. The check runs inline: a tightly time-boxed fetch compares the
* source with the installed skill, rewrites it when it changed, and announces the
* update immediately. Failures are logged and retried a day later.
*
* Skipped when the skill is not installed (the install prompt owns that case),
* for `skill` commands (to avoid recursion), in CI, in unit tests, in development
* mode, and when `SHOPIFY_CLI_NO_SKILL_AUTO_UPDATE` is set.
*
* @param options - See {@link UpdateShopifySkillIfNeededOptions}.
*/
export declare function updateShopifySkillIfNeeded(options: UpdateShopifySkillIfNeededOptions): Promise<void>;
/**
* Asks the user whether to install the Shopify skill for coding agents when it
* isn't installed yet. Selecting yes runs `shopify skill install` in a detached
* background process, so the current command is never delayed.
*
* The prompt is shown at most once per day, and never again once the skill is
* detected as installed or the user opts out, so deliberately uninstalling the
* skill won't trigger new prompts.
*
* Skipped for `skill` commands (to avoid recursion), for `--json` output, in
* non-interactive terminals, in CI, in unit tests, in development mode, and
* when `SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT` is set.
*
* @param options - See {@link PromptShopifySkillInstallOptions}.
*/
export declare function promptShopifySkillInstallIfNeeded(options: PromptShopifySkillInstallOptions): Promise<void>;
Existing type declarationspackages/cli-kit/dist/private/node/conf-store.d.ts@@ -25,6 +25,7 @@ export interface ConfSchema {
currentDevSessionId?: string;
cache?: Cache;
autoUpgradeEnabled?: boolean;
+ skillInstallPromptDismissed?: boolean;
}
/**
* Get session.
@@ -139,6 +140,20 @@ export declare function getAutoUpgradeEnabled(config?: LocalStorage<ConfSchema>)
* @param enabled - Whether auto-upgrade should be enabled.
*/
export declare function setAutoUpgradeEnabled(enabled: boolean, config?: LocalStorage<ConfSchema>): void;
+/**
+ * Get whether the Shopify skill install prompt has been dismissed, either because
+ * the skill was detected as installed or because the user opted out.
+ *
+ * @param config - The cli-kit local storage.
+ * @returns Whether the skill install prompt should never be shown again.
+ */
+export declare function getSkillInstallPromptDismissed(config?: LocalStorage<ConfSchema>): boolean;
+/**
+ * Record that the Shopify skill install prompt should never be shown again.
+ *
+ * @param config - The cli-kit local storage.
+ */
+export declare function setSkillInstallPromptDismissed(config?: LocalStorage<ConfSchema>): void;
export declare function getConfigStoreForPartnerStatus(): LocalStorage<Record<string, {
status: true;
checkedAt: string;
packages/cli-kit/dist/public/node/metadata.d.ts@@ -34,7 +34,7 @@ export type SensitiveSchema<T> = T extends RuntimeMetadataManager<infer _TPublic
* @returns A container for the metadata.
*/
export declare function createRuntimeMetadataContainer<TPublic extends AnyJson, TSensitive extends AnyJson = Record<string, never>>(defaultPublicMetadata?: Partial<TPublic>): RuntimeMetadataManager<TPublic, TSensitive>;
-type CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> & PickByPrefix<MonorailEventPublic, 'cmd_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_theme_'> & PickByPrefix<MonorailEventPublic, 'store_'> & PickByPrefix<MonorailEventPublic, 'env_auto_upgrade_'>;
+type CmdFieldsFromMonorail = PickByPrefix<MonorailEventPublic, 'cmd_all_'> & PickByPrefix<MonorailEventPublic, 'cmd_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_create_app_'> & PickByPrefix<MonorailEventPublic, 'cmd_theme_'> & PickByPrefix<MonorailEventPublic, 'cmd_validate_'> & PickByPrefix<MonorailEventPublic, 'store_'> & PickByPrefix<MonorailEventPublic, 'env_auto_upgrade_'>;
declare const coreData: RuntimeMetadataManager<CmdFieldsFromMonorail, {
commandStartOptions: {
startTime: number;
packages/cli-kit/dist/public/node/monorail.d.ts@@ -77,6 +77,11 @@ export interface Schemas {
cmd_app_validate_valid?: Optional<boolean>;
cmd_app_validate_issue_count?: Optional<number>;
cmd_app_validate_file_count?: Optional<number>;
+ cmd_validate_subcommand?: Optional<string>;
+ cmd_validate_result?: Optional<string>;
+ cmd_validate_api?: Optional<string>;
+ cmd_validate_api_version?: Optional<string>;
+ cmd_validate_json?: Optional<boolean>;
cmd_dev_tunnel_type?: Optional<string>;
cmd_dev_tunnel_custom_hash?: Optional<string>;
cmd_dev_urls_updated?: Optional<boolean>;
|
|
🫰✨ Thanks @alfonso-noriega! Your snapshot has been published to npm. Test the snapshot by installing your package globally: pnpm i -g --@shopify:registry=https://registry.npmjs.org @shopify/cli@0.0.0-snapshot-20260723204429Caution After installing, validate the version by running |

WHY are these changes introduced?
Fixes #0000
WHAT is this pull request doing?
How to test your changes?
Post-release steps
Checklist
patchfor bug fixes ·minorfor new features ·majorfor breaking changes) and added a changeset withpnpm changeset add