@shopify/cli-kit 0.0.0-snapshot-20260722210655 → 0.0.0-snapshot-20260723152140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/private/node/conf-store.d.ts +7 -6
- package/dist/private/node/conf-store.js +8 -7
- package/dist/private/node/conf-store.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/hooks/prerun.js +1 -2
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/skills.d.ts +16 -12
- package/dist/public/node/skills.js +56 -32
- package/dist/public/node/skills.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@ export interface ConfSchema {
|
|
|
25
25
|
currentDevSessionId?: string;
|
|
26
26
|
cache?: Cache;
|
|
27
27
|
autoUpgradeEnabled?: boolean;
|
|
28
|
-
|
|
28
|
+
skillInstallPromptDismissed?: boolean;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Get session.
|
|
@@ -141,18 +141,19 @@ export declare function getAutoUpgradeEnabled(config?: LocalStorage<ConfSchema>)
|
|
|
141
141
|
*/
|
|
142
142
|
export declare function setAutoUpgradeEnabled(enabled: boolean, config?: LocalStorage<ConfSchema>): void;
|
|
143
143
|
/**
|
|
144
|
-
* Get whether the Shopify skill
|
|
144
|
+
* Get whether the Shopify skill install prompt has been dismissed, either because
|
|
145
|
+
* the skill was detected as installed or because the user opted out.
|
|
145
146
|
*
|
|
146
147
|
* @param config - The cli-kit local storage.
|
|
147
|
-
* @returns Whether the skill
|
|
148
|
+
* @returns Whether the skill install prompt should never be shown again.
|
|
148
149
|
*/
|
|
149
|
-
export declare function
|
|
150
|
+
export declare function getSkillInstallPromptDismissed(config?: LocalStorage<ConfSchema>): boolean;
|
|
150
151
|
/**
|
|
151
|
-
* Record that the Shopify skill
|
|
152
|
+
* Record that the Shopify skill install prompt should never be shown again.
|
|
152
153
|
*
|
|
153
154
|
* @param config - The cli-kit local storage.
|
|
154
155
|
*/
|
|
155
|
-
export declare function
|
|
156
|
+
export declare function setSkillInstallPromptDismissed(config?: LocalStorage<ConfSchema>): void;
|
|
156
157
|
export declare function getConfigStoreForPartnerStatus(): LocalStorage<Record<string, {
|
|
157
158
|
status: true;
|
|
158
159
|
checkedAt: string;
|
|
@@ -183,21 +183,22 @@ export function setAutoUpgradeEnabled(enabled, config = cliKitStore()) {
|
|
|
183
183
|
config.set('autoUpgradeEnabled', enabled);
|
|
184
184
|
}
|
|
185
185
|
/**
|
|
186
|
-
* Get whether the Shopify skill
|
|
186
|
+
* Get whether the Shopify skill install prompt has been dismissed, either because
|
|
187
|
+
* the skill was detected as installed or because the user opted out.
|
|
187
188
|
*
|
|
188
189
|
* @param config - The cli-kit local storage.
|
|
189
|
-
* @returns Whether the skill
|
|
190
|
+
* @returns Whether the skill install prompt should never be shown again.
|
|
190
191
|
*/
|
|
191
|
-
export function
|
|
192
|
-
return config.get('
|
|
192
|
+
export function getSkillInstallPromptDismissed(config = cliKitStore()) {
|
|
193
|
+
return config.get('skillInstallPromptDismissed') ?? false;
|
|
193
194
|
}
|
|
194
195
|
/**
|
|
195
|
-
* Record that the Shopify skill
|
|
196
|
+
* Record that the Shopify skill install prompt should never be shown again.
|
|
196
197
|
*
|
|
197
198
|
* @param config - The cli-kit local storage.
|
|
198
199
|
*/
|
|
199
|
-
export function
|
|
200
|
-
config.set('
|
|
200
|
+
export function setSkillInstallPromptDismissed(config = cliKitStore()) {
|
|
201
|
+
config.set('skillInstallPromptDismissed', true);
|
|
201
202
|
}
|
|
202
203
|
export function getConfigStoreForPartnerStatus() {
|
|
203
204
|
return new LocalStorage({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAC,UAAU,EAAC,MAAM,oCAAoC,CAAA;AAC7D,OAAO,EAAC,YAAY,EAAC,MAAM,oCAAoC,CAAA;AAC/D,OAAO,EAAC,aAAa,EAAE,WAAW,EAAC,MAAM,6BAA6B,CAAA;AAmCtE,IAAI,SAA+C,CAAA;AAEnD;;;;GAIG;AACH,SAAS,WAAW;IAClB,SAAS,KAAT,SAAS,GAAK,IAAI,YAAY,CAAa,EAAC,WAAW,EAAE,kBAAkB,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAC,CAAC,EAAA;IAC1G,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,cAAc,CAAA;AAClE,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,kBAAkB,CAAA;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,SAAmC,WAAW,EAAE;IAC1E,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAA;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,SAAmC,WAAW,EAAE;IAC3F,WAAW,CAAC,aAAa,CAAA,0BAA0B,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,CAAA;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAmC,WAAW,EAAE;IAC7E,WAAW,CAAC,aAAa,CAAA,2BAA2B,CAAC,CAAA;IACrD,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAA;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAmC,WAAW,EAAE;IAClF,WAAW,CAAC,aAAa,CAAA,+BAA+B,CAAC,CAAA;IACzD,OAAO,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAA;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,SAAmC,WAAW,EAAE;IACrG,WAAW,CAAC,aAAa,CAAA,+BAA+B,CAAC,CAAA;IACzD,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,EAAE,SAAS,CAAC,CAAA;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAmC,WAAW,EAAE;IACrF,WAAW,CAAC,aAAa,CAAA,gCAAgC,CAAC,CAAA;IAC1D,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAA;AACtC,CAAC;AAID;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,GAAgB,EAChB,EAA+C,EAC/C,OAAgB,EAChB,MAAM,GAAG,WAAW,EAAE;IAEtB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAEzC,IAAI,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;QACtG,OAAO,MAAM,CAAC,KAAK,CAAA;IACrB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,CAAA;IACxB,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAgB,EAAE,KAAa,EAAE,MAAM,GAAG,WAAW,EAAE;IAChF,MAAM,KAAK,GAAU,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC9C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC,CAAA;IAC3C,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAgB,EAAE,MAAM,GAAG,WAAW,EAAE;IACpE,MAAM,KAAK,GAAU,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC9C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,WAAW,EAAE;IAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC;AASD,MAAM,UAAU,0BAA0B,CAAC,EAAC,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAe;IACtG,OAAO,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,OAAO,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAA;AAChF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAW,EACX,OAAqB,EACrB,IAAyB,EACzB,MAAM,GAAG,WAAW,EAAE;IAEtB,MAAM,KAAK,GAAU,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC9C,MAAM,QAAQ,GAA4B,0BAA0B,GAAG,EAAE,CAAA;IACzE,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;IAE9B,IAAI,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,0BAA0B,CAAC,OAAO,CAAC,EAAE,CAAC;QACvG,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,IAAI,EAAE,CAAA;IACZ,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC,CAAA;IACtD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC1B,OAAO,IAAI,CAAA;AACb,CAAC;AA0BD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgC,EAAE,MAAM,GAAG,WAAW,EAAE;IAC7F,MAAM,EAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAC,GAAG,OAAO,CAAA;IAC3C,MAAM,KAAK,GAAU,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC9C,MAAM,QAAQ,GAAiB,4BAA4B,GAAG,EAAE,CAAA;IAChE,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAA;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAEtB,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;QAClB,yDAAyD;QACzD,MAAM,WAAW,GAAG,GAAG,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAA;QAC7D,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,IAAI,WAAW,CAAC,CAAA;QAElF,kFAAkF;QAClF,IAAI,WAAW,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;YAChC,kDAAkD;YAClD,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC,CAAA;YAC7D,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAE1B,OAAO,KAAK,CAAA;QACd,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;QACZ,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAC,KAAK,EAAE,CAAC,GAAG,WAAW,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAC,CAAA;IAClE,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,EAAE,CAAA;QACZ,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,EAAC,CAAA;IAClD,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAE1B,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAmC,WAAW,EAAE;IACpF,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAA;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgB,EAAE,SAAmC,WAAW,EAAE;IACtG,MAAM,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,SAAmC,WAAW,EAAE;IAC3F,OAAO,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,IAAI,KAAK,CAAA;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,SAAmC,WAAW,EAAE;IAC3F,MAAM,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,OAAO,IAAI,YAAY,CAAoD;QACzE,WAAW,EAAE,gCAAgC;KAC9C,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,aAAqB;IACjE,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAA;IAC/B,MAAM,KAAK,GAAG,8BAA8B,EAAE,CAAA;IAE9C,MAAM,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAClD,IAAI,iBAAiB,EAAE,CAAC;QACtB,6BAA6B;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,aAAqB;IACjE,MAAM,KAAK,GAAG,8BAA8B,EAAE,CAAA;IAE9C,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,EAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAC,CAAC,CAAA;AAC/E,CAAC","sourcesContent":["import {isLocalEnvironment} from './context/service.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '../../public/node/output.js'\n\ninterface CacheValue<T> {\n value: T\n timestamp: number\n}\n\nexport type PackageVersionKey = `npm-package-${string}`\nexport type NotificationsKey = `notifications-${string}`\nexport type NotificationKey = `notification-${string}`\nexport type GraphQLRequestKey = `q-${string}-${string}-${string}`\ntype MostRecentOccurrenceKey = `most-recent-occurrence-${string}`\ntype RateLimitKey = `rate-limited-occurrences-${string}`\n\ntype ExportedKey = PackageVersionKey | NotificationsKey | NotificationKey | GraphQLRequestKey\n\ninterface Cache {\n [packageVersionKey: PackageVersionKey]: CacheValue<string>\n [notifications: NotificationsKey]: CacheValue<string>\n [notification: NotificationKey]: CacheValue<string>\n [graphQLRequestKey: GraphQLRequestKey]: CacheValue<string>\n [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>\n [rateLimitKey: RateLimitKey]: CacheValue<number[]>\n}\n\nexport interface ConfSchema {\n sessionStore: string\n currentSessionId?: string\n devSessionStore?: string\n currentDevSessionId?: string\n cache?: Cache\n autoUpgradeEnabled?: boolean\n skillAutoInstallCompleted?: boolean\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n _instance ??= new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n return _instance\n}\n\nfunction sessionStoreKey(): 'devSessionStore' | 'sessionStore' {\n return isLocalEnvironment() ? 'devSessionStore' : 'sessionStore'\n}\n\nfunction currentSessionIdKey(): 'currentDevSessionId' | 'currentSessionId' {\n return isLocalEnvironment() ? 'currentDevSessionId' : 'currentSessionId'\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSessions(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get(sessionStoreKey())\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSessions(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set(sessionStoreKey(), session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSessions(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete(sessionStoreKey())\n}\n\n/**\n * Get current session ID.\n *\n * @returns Current session ID.\n */\nexport function getCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting current session ID...`)\n return config.get(currentSessionIdKey())\n}\n\n/**\n * Set current session ID.\n *\n * @param sessionId - Session ID.\n */\nexport function setCurrentSessionId(sessionId: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting current session ID...`)\n config.set(currentSessionIdKey(), sessionId)\n}\n\n/**\n * Remove current session ID.\n */\nexport function removeCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing current session ID...`)\n config.delete(currentSessionIdKey())\n}\n\ntype CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value']\n\n/**\n * Fetch from cache, or run the provided function to get the value, and cache it\n * before returning it.\n * @param key - The key to use for the cache.\n * @param fn - The function to run to get the value to cache, if a cache miss occurs.\n * @param timeout - The maximum valid age of a cached value, in milliseconds.\n * If the cached value is older than this, it will be refreshed.\n * @returns The value from the cache or the result of the function.\n */\nexport async function cacheRetrieveOrRepopulate(\n key: ExportedKey,\n fn: () => Promise<CacheValueForKey<typeof key>>,\n timeout?: number,\n config = cliKitStore(),\n): Promise<CacheValueForKey<typeof key>> {\n const cached = cacheRetrieve(key, config)\n\n if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {\n return cached.value\n }\n\n const value = await fn()\n cacheStore(key, value, config)\n return value\n}\n\nexport function cacheStore(key: ExportedKey, value: string, config = cliKitStore()): void {\n const cache: Cache = config.get('cache') ?? {}\n cache[key] = {value, timestamp: Date.now()}\n config.set('cache', cache)\n}\n\n/**\n * Fetch from cache if already populated, otherwise return undefined.\n * @param key - The key to use for the cache.\n * @returns The chache element.\n */\nexport function cacheRetrieve(key: ExportedKey, config = cliKitStore()): CacheValue<string> | undefined {\n const cache: Cache = config.get('cache') ?? {}\n return cache[key]\n}\n\nexport function cacheClear(config = cliKitStore()): void {\n config.delete('cache')\n}\n\nexport interface TimeInterval {\n days?: number\n hours?: number\n minutes?: number\n seconds?: number\n}\n\nexport function timeIntervalToMilliseconds({days = 0, hours = 0, minutes = 0, seconds = 0}: TimeInterval): number {\n return (days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds) * 1000\n}\n\n/**\n * Execute a task only if the most recent occurrence of the task is older than the specified timeout.\n * @param key - The key to use for the cache.\n * @param timeout - The maximum valid age of the most recent occurrence, expressed as an object with\n * days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n * @param task - The task to run if the most recent occurrence is older than the timeout.\n * @returns true if the task was run, or false if the task was not run.\n */\nexport async function runAtMinimumInterval(\n key: string,\n timeout: TimeInterval,\n task: () => Promise<void>,\n config = cliKitStore(),\n): Promise<boolean> {\n const cache: Cache = config.get('cache') ?? {}\n const cacheKey: MostRecentOccurrenceKey = `most-recent-occurrence-${key}`\n const cached = cache[cacheKey]\n\n if (cached?.value !== undefined && Date.now() - cached.timestamp < timeIntervalToMilliseconds(timeout)) {\n return false\n }\n\n await task()\n cache[cacheKey] = {value: true, timestamp: Date.now()}\n config.set('cache', cache)\n return true\n}\n\ninterface RunWithRateLimitOptions {\n /**\n * The key to use for the cache.\n */\n key: string\n\n /**\n * The number of times the task can be run within the limit\n */\n limit: number\n\n /**\n * The window of time after which the rate limit is refreshed,\n * expressed as an object with days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n */\n timeout: TimeInterval\n\n /**\n * The task to run if the most recent occurrence is older than the timeout.\n */\n task: () => Promise<void>\n}\n\n/**\n * Execute a task with a time-based rate limit. The rate limit is enforced by\n * checking how many times that task has been executed in a window of time ending\n * at the current time. If the task has been executed more than the allowed number\n * of times in that window, the task will not be executed.\n *\n * Note that this function has side effects, as it will also remove events prior\n * to the window of time that is being checked.\n * @param options - The options for the rate limiting.\n * @returns true, or undefined if the task was not run.\n */\nexport async function runWithRateLimit(options: RunWithRateLimitOptions, config = cliKitStore()): Promise<boolean> {\n const {key, limit, timeout, task} = options\n const cache: Cache = config.get('cache') ?? {}\n const cacheKey: RateLimitKey = `rate-limited-occurrences-${key}`\n const cached = cache[cacheKey]\n const now = Date.now()\n\n if (cached?.value) {\n // First sweep through the cache and eliminate old events\n const windowStart = now - timeIntervalToMilliseconds(timeout)\n const occurrences = cached.value.filter((occurrence) => occurrence >= windowStart)\n\n // Now check that the number of occurrences within the interval is below the limit\n if (occurrences.length >= limit) {\n // First remove the old occurrences from the cache\n cache[cacheKey] = {value: occurrences, timestamp: Date.now()}\n config.set('cache', cache)\n\n return false\n }\n\n await task()\n cache[cacheKey] = {value: [...occurrences, now], timestamp: now}\n } else {\n await task()\n cache[cacheKey] = {value: [now], timestamp: now}\n }\n config.set('cache', cache)\n\n return true\n}\n\n/**\n * Get auto-upgrade preference.\n * Defaults to true if the preference has never been explicitly set.\n *\n * @returns Whether auto-upgrade is enabled.\n */\nexport function getAutoUpgradeEnabled(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('autoUpgradeEnabled') ?? true\n}\n\n/**\n * Set auto-upgrade preference.\n *\n * @param enabled - Whether auto-upgrade should be enabled.\n */\nexport function setAutoUpgradeEnabled(enabled: boolean, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('autoUpgradeEnabled', enabled)\n}\n\n/**\n * Get whether the Shopify skill auto-install has already completed.\n *\n * @param config - The cli-kit local storage.\n * @returns Whether the skill was detected as installed at some point.\n */\nexport function getSkillAutoInstallCompleted(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('skillAutoInstallCompleted') ?? false\n}\n\n/**\n * Record that the Shopify skill auto-install has completed, so it is never attempted again.\n *\n * @param config - The cli-kit local storage.\n */\nexport function setSkillAutoInstallCompleted(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('skillAutoInstallCompleted', true)\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<Record<string, {status: true; checkedAt: string}>>({\n projectName: 'shopify-cli-kit-partner-status',\n })\n}\n\nexport function getCachedPartnerAccountStatus(partnersToken: string): true | null {\n if (!partnersToken) return null\n const store = getConfigStoreForPartnerStatus()\n\n const hasPartnerAccount = store.get(partnersToken)\n if (hasPartnerAccount) {\n // this never needs to expire\n return true\n }\n return null\n}\n\nexport function setCachedPartnerAccountStatus(partnersToken: string) {\n const store = getConfigStoreForPartnerStatus()\n\n store.set(partnersToken, {status: true, checkedAt: new Date().toISOString()})\n}\n"]}
|
|
1
|
+
{"version":3,"file":"conf-store.js","sourceRoot":"","sources":["../../../src/private/node/conf-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {isLocalEnvironment} from './context/service.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {LocalStorage} from '../../public/node/local-storage.js'\nimport {outputContent, outputDebug} from '../../public/node/output.js'\n\ninterface CacheValue<T> {\n value: T\n timestamp: number\n}\n\nexport type PackageVersionKey = `npm-package-${string}`\nexport type NotificationsKey = `notifications-${string}`\nexport type NotificationKey = `notification-${string}`\nexport type GraphQLRequestKey = `q-${string}-${string}-${string}`\ntype MostRecentOccurrenceKey = `most-recent-occurrence-${string}`\ntype RateLimitKey = `rate-limited-occurrences-${string}`\n\ntype ExportedKey = PackageVersionKey | NotificationsKey | NotificationKey | GraphQLRequestKey\n\ninterface Cache {\n [packageVersionKey: PackageVersionKey]: CacheValue<string>\n [notifications: NotificationsKey]: CacheValue<string>\n [notification: NotificationKey]: CacheValue<string>\n [graphQLRequestKey: GraphQLRequestKey]: CacheValue<string>\n [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>\n [rateLimitKey: RateLimitKey]: CacheValue<number[]>\n}\n\nexport interface ConfSchema {\n sessionStore: string\n currentSessionId?: string\n devSessionStore?: string\n currentDevSessionId?: string\n cache?: Cache\n autoUpgradeEnabled?: boolean\n skillInstallPromptDismissed?: boolean\n}\n\nlet _instance: LocalStorage<ConfSchema> | undefined\n\n/**\n * CLIKIT Store.\n *\n * @returns CLIKitStore.\n */\nfunction cliKitStore() {\n _instance ??= new LocalStorage<ConfSchema>({projectName: `shopify-cli-kit${isUnitTest() ? '-test' : ''}`})\n return _instance\n}\n\nfunction sessionStoreKey(): 'devSessionStore' | 'sessionStore' {\n return isLocalEnvironment() ? 'devSessionStore' : 'sessionStore'\n}\n\nfunction currentSessionIdKey(): 'currentDevSessionId' | 'currentSessionId' {\n return isLocalEnvironment() ? 'currentDevSessionId' : 'currentSessionId'\n}\n\n/**\n * Get session.\n *\n * @returns Session.\n */\nexport function getSessions(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting session store...`)\n return config.get(sessionStoreKey())\n}\n\n/**\n * Set session.\n *\n * @param session - Session.\n */\nexport function setSessions(session: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting session store...`)\n config.set(sessionStoreKey(), session)\n}\n\n/**\n * Remove session.\n */\nexport function removeSessions(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing session store...`)\n config.delete(sessionStoreKey())\n}\n\n/**\n * Get current session ID.\n *\n * @returns Current session ID.\n */\nexport function getCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): string | undefined {\n outputDebug(outputContent`Getting current session ID...`)\n return config.get(currentSessionIdKey())\n}\n\n/**\n * Set current session ID.\n *\n * @param sessionId - Session ID.\n */\nexport function setCurrentSessionId(sessionId: string, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Setting current session ID...`)\n config.set(currentSessionIdKey(), sessionId)\n}\n\n/**\n * Remove current session ID.\n */\nexport function removeCurrentSessionId(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n outputDebug(outputContent`Removing current session ID...`)\n config.delete(currentSessionIdKey())\n}\n\ntype CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['value']\n\n/**\n * Fetch from cache, or run the provided function to get the value, and cache it\n * before returning it.\n * @param key - The key to use for the cache.\n * @param fn - The function to run to get the value to cache, if a cache miss occurs.\n * @param timeout - The maximum valid age of a cached value, in milliseconds.\n * If the cached value is older than this, it will be refreshed.\n * @returns The value from the cache or the result of the function.\n */\nexport async function cacheRetrieveOrRepopulate(\n key: ExportedKey,\n fn: () => Promise<CacheValueForKey<typeof key>>,\n timeout?: number,\n config = cliKitStore(),\n): Promise<CacheValueForKey<typeof key>> {\n const cached = cacheRetrieve(key, config)\n\n if (cached?.value !== undefined && (timeout === undefined || Date.now() - cached.timestamp < timeout)) {\n return cached.value\n }\n\n const value = await fn()\n cacheStore(key, value, config)\n return value\n}\n\nexport function cacheStore(key: ExportedKey, value: string, config = cliKitStore()): void {\n const cache: Cache = config.get('cache') ?? {}\n cache[key] = {value, timestamp: Date.now()}\n config.set('cache', cache)\n}\n\n/**\n * Fetch from cache if already populated, otherwise return undefined.\n * @param key - The key to use for the cache.\n * @returns The chache element.\n */\nexport function cacheRetrieve(key: ExportedKey, config = cliKitStore()): CacheValue<string> | undefined {\n const cache: Cache = config.get('cache') ?? {}\n return cache[key]\n}\n\nexport function cacheClear(config = cliKitStore()): void {\n config.delete('cache')\n}\n\nexport interface TimeInterval {\n days?: number\n hours?: number\n minutes?: number\n seconds?: number\n}\n\nexport function timeIntervalToMilliseconds({days = 0, hours = 0, minutes = 0, seconds = 0}: TimeInterval): number {\n return (days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds) * 1000\n}\n\n/**\n * Execute a task only if the most recent occurrence of the task is older than the specified timeout.\n * @param key - The key to use for the cache.\n * @param timeout - The maximum valid age of the most recent occurrence, expressed as an object with\n * days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n * @param task - The task to run if the most recent occurrence is older than the timeout.\n * @returns true if the task was run, or false if the task was not run.\n */\nexport async function runAtMinimumInterval(\n key: string,\n timeout: TimeInterval,\n task: () => Promise<void>,\n config = cliKitStore(),\n): Promise<boolean> {\n const cache: Cache = config.get('cache') ?? {}\n const cacheKey: MostRecentOccurrenceKey = `most-recent-occurrence-${key}`\n const cached = cache[cacheKey]\n\n if (cached?.value !== undefined && Date.now() - cached.timestamp < timeIntervalToMilliseconds(timeout)) {\n return false\n }\n\n await task()\n cache[cacheKey] = {value: true, timestamp: Date.now()}\n config.set('cache', cache)\n return true\n}\n\ninterface RunWithRateLimitOptions {\n /**\n * The key to use for the cache.\n */\n key: string\n\n /**\n * The number of times the task can be run within the limit\n */\n limit: number\n\n /**\n * The window of time after which the rate limit is refreshed,\n * expressed as an object with days, hours, minutes, and seconds properties.\n * If the most recent occurrence is older than this, the task will be executed.\n */\n timeout: TimeInterval\n\n /**\n * The task to run if the most recent occurrence is older than the timeout.\n */\n task: () => Promise<void>\n}\n\n/**\n * Execute a task with a time-based rate limit. The rate limit is enforced by\n * checking how many times that task has been executed in a window of time ending\n * at the current time. If the task has been executed more than the allowed number\n * of times in that window, the task will not be executed.\n *\n * Note that this function has side effects, as it will also remove events prior\n * to the window of time that is being checked.\n * @param options - The options for the rate limiting.\n * @returns true, or undefined if the task was not run.\n */\nexport async function runWithRateLimit(options: RunWithRateLimitOptions, config = cliKitStore()): Promise<boolean> {\n const {key, limit, timeout, task} = options\n const cache: Cache = config.get('cache') ?? {}\n const cacheKey: RateLimitKey = `rate-limited-occurrences-${key}`\n const cached = cache[cacheKey]\n const now = Date.now()\n\n if (cached?.value) {\n // First sweep through the cache and eliminate old events\n const windowStart = now - timeIntervalToMilliseconds(timeout)\n const occurrences = cached.value.filter((occurrence) => occurrence >= windowStart)\n\n // Now check that the number of occurrences within the interval is below the limit\n if (occurrences.length >= limit) {\n // First remove the old occurrences from the cache\n cache[cacheKey] = {value: occurrences, timestamp: Date.now()}\n config.set('cache', cache)\n\n return false\n }\n\n await task()\n cache[cacheKey] = {value: [...occurrences, now], timestamp: now}\n } else {\n await task()\n cache[cacheKey] = {value: [now], timestamp: now}\n }\n config.set('cache', cache)\n\n return true\n}\n\n/**\n * Get auto-upgrade preference.\n * Defaults to true if the preference has never been explicitly set.\n *\n * @returns Whether auto-upgrade is enabled.\n */\nexport function getAutoUpgradeEnabled(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('autoUpgradeEnabled') ?? true\n}\n\n/**\n * Set auto-upgrade preference.\n *\n * @param enabled - Whether auto-upgrade should be enabled.\n */\nexport function setAutoUpgradeEnabled(enabled: boolean, config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('autoUpgradeEnabled', enabled)\n}\n\n/**\n * Get whether the Shopify skill install prompt has been dismissed, either because\n * the skill was detected as installed or because the user opted out.\n *\n * @param config - The cli-kit local storage.\n * @returns Whether the skill install prompt should never be shown again.\n */\nexport function getSkillInstallPromptDismissed(config: LocalStorage<ConfSchema> = cliKitStore()): boolean {\n return config.get('skillInstallPromptDismissed') ?? false\n}\n\n/**\n * Record that the Shopify skill install prompt should never be shown again.\n *\n * @param config - The cli-kit local storage.\n */\nexport function setSkillInstallPromptDismissed(config: LocalStorage<ConfSchema> = cliKitStore()): void {\n config.set('skillInstallPromptDismissed', true)\n}\n\nexport function getConfigStoreForPartnerStatus() {\n return new LocalStorage<Record<string, {status: true; checkedAt: string}>>({\n projectName: 'shopify-cli-kit-partner-status',\n })\n}\n\nexport function getCachedPartnerAccountStatus(partnersToken: string): true | null {\n if (!partnersToken) return null\n const store = getConfigStoreForPartnerStatus()\n\n const hasPartnerAccount = store.get(partnersToken)\n if (hasPartnerAccount) {\n // this never needs to expire\n return true\n }\n return null\n}\n\nexport function setCachedPartnerAccountStatus(partnersToken: string) {\n const store = getConfigStoreForPartnerStatus()\n\n store.set(partnersToken, {status: true, checkedAt: new Date().toISOString()})\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_KIT_VERSION = "0.0.0-snapshot-
|
|
1
|
+
export declare const CLI_KIT_VERSION = "0.0.0-snapshot-20260723152140";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const CLI_KIT_VERSION = '0.0.0-snapshot-
|
|
1
|
+
export const CLI_KIT_VERSION = '0.0.0-snapshot-20260723152140';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,+BAA+B,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '0.0.0-snapshot-
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,+BAA+B,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '0.0.0-snapshot-20260723152140'\n"]}
|
|
@@ -19,8 +19,7 @@ export const hook = async (options) => {
|
|
|
19
19
|
outputDebug(`Running command ${commandContent.command}`);
|
|
20
20
|
await analyticsMod.startAnalytics({ commandContent, args, commandClass: options.Command });
|
|
21
21
|
notificationsMod.fetchNotificationsInBackground(options.Command.id);
|
|
22
|
-
|
|
23
|
-
void skillsMod.installShopifySkillInBackground({ currentCommand: options.Command.id });
|
|
22
|
+
await skillsMod.promptShopifySkillInstallIfNeeded({ currentCommand: options.Command.id, args });
|
|
24
23
|
};
|
|
25
24
|
export function parseCommandContent(cmdInfo) {
|
|
26
25
|
let commandContent = parseCreateCommand(cmdInfo.pluginAlias);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/prerun.ts"],"names":[],"mappings":"AAQA,sFAAsF;AACtF,MAAM,CAAC,MAAM,IAAI,GAAgB,KAAK,EAAE,OAAO,EAAE,EAAE;IACjD,MAAM,cAAc,GAAG,mBAAmB,CAAC;QACzC,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO;QAChC,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK;KAC3C,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IAEzB,iCAAiC;IACjC,MAAM,CAAC,EAAC,WAAW,EAAC,EAAE,YAAY,EAAE,gBAAgB,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACnF,MAAM,CAAC,cAAc,CAAC;QACtB,MAAM,CAAC,oCAAoC,CAAC;QAC5C,MAAM,CAAC,4BAA4B,CAAC;QACpC,MAAM,CAAC,cAAc,CAAC;KACvB,CAAC,CAAA;IAEF,kDAAkD;IAClD,mCAAmC;IACnC,KAAK,8BAA8B,EAAE,CAAA;IAErC,WAAW,CAAC,mBAAmB,cAAc,CAAC,OAAO,EAAE,CAAC,CAAA;IACxD,MAAM,YAAY,CAAC,cAAc,CAAC,EAAC,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,EAAC,CAAC,CAAA;IACxF,gBAAgB,CAAC,8BAA8B,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACnE,
|
|
1
|
+
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../../../src/public/node/hooks/prerun.ts"],"names":[],"mappings":"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","sourcesContent":["import {Hook} from '@oclif/core'\n\nexport declare interface CommandContent {\n command: string\n topic?: string\n alias?: string\n}\n\n// This hook is called before each command run. More info: https://oclif.io/docs/hooks\nexport const hook: Hook.Prerun = async (options) => {\n const commandContent = parseCommandContent({\n id: options.Command.id,\n aliases: options.Command.aliases,\n pluginAlias: options.Command.plugin?.alias,\n })\n const args = options.argv\n\n // Load heavy modules in parallel\n const [{outputDebug}, analyticsMod, notificationsMod, skillsMod] = await Promise.all([\n import('../output.js'),\n import('../../../private/node/analytics.js'),\n import('../notifications-system.js'),\n import('../skills.js'),\n ])\n\n // Fire upgrade check in background (non-blocking)\n // eslint-disable-next-line no-void\n void checkForNewVersionInBackground()\n\n outputDebug(`Running command ${commandContent.command}`)\n await analyticsMod.startAnalytics({commandContent, args, commandClass: options.Command})\n notificationsMod.fetchNotificationsInBackground(options.Command.id)\n await skillsMod.promptShopifySkillInstallIfNeeded({currentCommand: options.Command.id, args})\n}\n\nexport function parseCommandContent(cmdInfo: {id: string; aliases: string[]; pluginAlias?: string}): CommandContent {\n let commandContent = parseCreateCommand(cmdInfo.pluginAlias)\n commandContent ??= parseNormalCommand(cmdInfo.id, cmdInfo.aliases)\n return commandContent\n}\n\nfunction parseNormalCommand(id: string, aliases: string[]): CommandContent {\n return {\n command: id.replace(/:/g, ' '),\n topic: parseTopic(id),\n alias: findAlias(aliases),\n }\n}\n\n/**\n * Create commands implement Init by default, so the name of the command must be extracted from\n * the plugin/module name. Neither alias or topic are supported\n *\n * @param commandClass - Oclif command configuration\n * @returns Command content with the name of the command or undefined otherwise\n */\nfunction parseCreateCommand(pluginAlias?: string): CommandContent | undefined {\n if (!pluginAlias?.startsWith('@shopify/create-')) {\n return undefined\n }\n\n return {command: pluginAlias.substring(pluginAlias.indexOf('/') + 1)}\n}\n\n/**\n * Commands use this pattern topic:subtopic1:...:subtopicN:command. This method extract the topic and subtopic\n * information replacing the ':' separator with one space\n *\n * @param cmd - Complete command string to extract the topic information\n * @returns The topic name or undefined otherwise\n */\nfunction parseTopic(cmd: string) {\n if (cmd.lastIndexOf(':') === -1) {\n return\n }\n return cmd.slice(0, cmd.lastIndexOf(':')).replace(/:/g, ' ')\n}\n\n/**\n * Identifies if the command was launched using an alias instead of the oficial command name\n *\n * @param aliases - List of possible alias a command has\n * @returns The alias used or undefined otherwise\n */\nfunction findAlias(aliases: string[]) {\n const existingAlias = aliases.find((alias) =>\n alias.split(':').every((aliasToken) => process.argv.includes(aliasToken)),\n )\n if (existingAlias) {\n return existingAlias.replace(/:/g, ' ')\n }\n}\n\n/**\n * Triggers a background check for a newer CLI version (non-blocking).\n * The result is cached and consumed by the postrun hook for auto-upgrade.\n */\nexport async function checkForNewVersionInBackground(): Promise<void> {\n const [{CLI_KIT_VERSION}, {isPreReleaseVersion}, {checkForNewVersion}] = await Promise.all([\n import('../../common/version.js'),\n import('../version.js'),\n import('../node-package-manager.js'),\n ])\n const currentVersion = CLI_KIT_VERSION\n if (isPreReleaseVersion(currentVersion)) {\n return\n }\n // eslint-disable-next-line no-void\n void checkForNewVersion('@shopify/cli', currentVersion, {cacheExpiryInHours: 24})\n}\n"]}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { LocalStorage } from './local-storage.js';
|
|
2
2
|
import { ConfSchema } from '../../private/node/conf-store.js';
|
|
3
3
|
/**
|
|
4
|
-
* Options for {@link
|
|
4
|
+
* Options for {@link promptShopifySkillInstallIfNeeded}.
|
|
5
5
|
*/
|
|
6
|
-
export interface
|
|
7
|
-
/** The command being run, used to avoid
|
|
6
|
+
export interface PromptShopifySkillInstallOptions {
|
|
7
|
+
/** The command being run, used to avoid prompting recursively from `skill` commands. */
|
|
8
8
|
currentCommand: string;
|
|
9
|
+
/** The arguments of the command being run, used to avoid corrupting `--json` output. */
|
|
10
|
+
args?: string[];
|
|
9
11
|
/** The process argv, used to re-invoke the current CLI binary. */
|
|
10
12
|
argv?: string[];
|
|
11
13
|
/** The process environment. */
|
|
@@ -27,16 +29,18 @@ export interface InstallShopifySkillInBackgroundOptions {
|
|
|
27
29
|
*/
|
|
28
30
|
export declare function shopifySkillIsInstalled(env?: NodeJS.ProcessEnv, homeDir?: string): boolean;
|
|
29
31
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
+
* Asks the user whether to install the Shopify skill for coding agents when it
|
|
33
|
+
* isn't installed yet. Selecting yes runs `shopify skill install` in a detached
|
|
34
|
+
* background process, so the current command is never delayed.
|
|
32
35
|
*
|
|
33
|
-
* The
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
+
* The prompt is shown at most once per day, and never again once the skill is
|
|
37
|
+
* detected as installed or the user opts out, so deliberately uninstalling the
|
|
38
|
+
* skill won't trigger new prompts.
|
|
36
39
|
*
|
|
37
|
-
* Skipped for `skill` commands (to avoid recursion),
|
|
38
|
-
*
|
|
40
|
+
* Skipped for `skill` commands (to avoid recursion), for `--json` output, in
|
|
41
|
+
* non-interactive terminals, in CI, in unit tests, in development mode, and
|
|
42
|
+
* when `SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT` is set.
|
|
39
43
|
*
|
|
40
|
-
* @param options - See {@link
|
|
44
|
+
* @param options - See {@link PromptShopifySkillInstallOptions}.
|
|
41
45
|
*/
|
|
42
|
-
export declare function
|
|
46
|
+
export declare function promptShopifySkillInstallIfNeeded(options: PromptShopifySkillInstallOptions): Promise<void>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { homeDirectory, isDevelopment } from './context/local.js';
|
|
2
2
|
import { isTruthy } from './context/utilities.js';
|
|
3
3
|
import { fileExistsSync } from './fs.js';
|
|
4
|
-
import { outputDebug } from './output.js';
|
|
4
|
+
import { outputDebug, outputInfo } from './output.js';
|
|
5
5
|
import { joinPath } from './path.js';
|
|
6
|
-
import { exec } from './system.js';
|
|
7
|
-
import {
|
|
6
|
+
import { exec, terminalSupportsPrompting } from './system.js';
|
|
7
|
+
import { renderSelectPrompt } from './ui.js';
|
|
8
|
+
import { getSkillInstallPromptDismissed, setSkillInstallPromptDismissed, runAtMinimumInterval, } from '../../private/node/conf-store.js';
|
|
8
9
|
/**
|
|
9
10
|
* Checks whether the Shopify skill for coding agents is installed globally.
|
|
10
11
|
*
|
|
@@ -24,53 +25,76 @@ export function shopifySkillIsInstalled(env = process.env, homeDir = homeDirecto
|
|
|
24
25
|
return skillDirectories.some(fileExistsSync);
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
28
|
+
* Asks the user whether to install the Shopify skill for coding agents when it
|
|
29
|
+
* isn't installed yet. Selecting yes runs `shopify skill install` in a detached
|
|
30
|
+
* background process, so the current command is never delayed.
|
|
29
31
|
*
|
|
30
|
-
* The
|
|
31
|
-
*
|
|
32
|
-
*
|
|
32
|
+
* The prompt is shown at most once per day, and never again once the skill is
|
|
33
|
+
* detected as installed or the user opts out, so deliberately uninstalling the
|
|
34
|
+
* skill won't trigger new prompts.
|
|
33
35
|
*
|
|
34
|
-
* Skipped for `skill` commands (to avoid recursion),
|
|
35
|
-
*
|
|
36
|
+
* Skipped for `skill` commands (to avoid recursion), for `--json` output, in
|
|
37
|
+
* non-interactive terminals, in CI, in unit tests, in development mode, and
|
|
38
|
+
* when `SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT` is set.
|
|
36
39
|
*
|
|
37
|
-
* @param options - See {@link
|
|
40
|
+
* @param options - See {@link PromptShopifySkillInstallOptions}.
|
|
38
41
|
*/
|
|
39
|
-
export async function
|
|
40
|
-
const { currentCommand, argv = process.argv, env = process.env, config, homeDir } = options;
|
|
41
|
-
if (
|
|
42
|
+
export async function promptShopifySkillInstallIfNeeded(options) {
|
|
43
|
+
const { currentCommand, args = [], argv = process.argv, env = process.env, config, homeDir } = options;
|
|
44
|
+
if (skipSkillInstallPrompt(currentCommand, args, env))
|
|
42
45
|
return;
|
|
43
|
-
if (
|
|
46
|
+
if (getSkillInstallPromptDismissed(config))
|
|
44
47
|
return;
|
|
45
48
|
if (shopifySkillIsInstalled(env, homeDir)) {
|
|
46
|
-
|
|
49
|
+
setSkillInstallPromptDismissed(config);
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
52
|
const nodeBinary = argv[0];
|
|
50
53
|
const shopifyBinary = argv[1];
|
|
51
54
|
if (!nodeBinary || !shopifyBinary)
|
|
52
55
|
return;
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
externalErrorHandler: async (error) => {
|
|
64
|
-
outputDebug(`Failed to install the Shopify skill in background: ${error.message}`);
|
|
65
|
-
},
|
|
56
|
+
// Ask at most once per day: the timestamp is recorded when the prompt is shown,
|
|
57
|
+
// so both "ask me tomorrow" and a failed install naturally re-prompt a day later.
|
|
58
|
+
await runAtMinimumInterval('skill-install-prompt', { days: 1 }, async () => {
|
|
59
|
+
const choice = await renderSelectPrompt({
|
|
60
|
+
message: 'The Shopify skill helps coding agents like Claude Code, Cursor, and Codex build with Shopify. Install it?',
|
|
61
|
+
choices: [
|
|
62
|
+
{ label: 'Yes, install it now', value: 'install' },
|
|
63
|
+
{ label: 'No, ask me tomorrow', value: 'later' },
|
|
64
|
+
{ label: 'No, never ask again', value: 'never' },
|
|
65
|
+
],
|
|
66
66
|
});
|
|
67
|
+
switch (choice) {
|
|
68
|
+
case 'install':
|
|
69
|
+
// Run the Shopify command the same way as the current execution, detached
|
|
70
|
+
// from the current process so the CLI can exit before the install finishes.
|
|
71
|
+
// eslint-disable-next-line no-void
|
|
72
|
+
void exec(nodeBinary, [shopifyBinary, 'skill', 'install'], {
|
|
73
|
+
background: true,
|
|
74
|
+
env: { ...env, SHOPIFY_CLI_NO_ANALYTICS: '1' },
|
|
75
|
+
externalErrorHandler: async (error) => {
|
|
76
|
+
outputDebug(`Failed to install the Shopify skill in background: ${error.message}`);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
outputInfo('Installing the Shopify skill in the background. Run `shopify skill install` to reinstall it at any time.');
|
|
80
|
+
break;
|
|
81
|
+
case 'later':
|
|
82
|
+
// Nothing to record: the daily interval re-prompts on the first command tomorrow.
|
|
83
|
+
break;
|
|
84
|
+
case 'never':
|
|
85
|
+
setSkillInstallPromptDismissed(config);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
67
88
|
}, config);
|
|
68
89
|
}
|
|
69
|
-
function
|
|
90
|
+
function skipSkillInstallPrompt(currentCommand, args, env) {
|
|
70
91
|
return (currentCommand.startsWith('skill') ||
|
|
92
|
+
args.includes('--json') ||
|
|
93
|
+
isTruthy(env.SHOPIFY_FLAG_JSON) ||
|
|
71
94
|
isTruthy(env.CI) ||
|
|
72
95
|
isTruthy(env.SHOPIFY_UNIT_TEST) ||
|
|
73
|
-
isTruthy(env.
|
|
74
|
-
isDevelopment(env)
|
|
96
|
+
isTruthy(env.SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT) ||
|
|
97
|
+
isDevelopment(env) ||
|
|
98
|
+
!terminalSupportsPrompting());
|
|
75
99
|
}
|
|
76
100
|
//# sourceMappingURL=skills.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/public/node/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AACtC,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/public/node/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import {homeDirectory, isDevelopment} from './context/local.js'\nimport {isTruthy} from './context/utilities.js'\nimport {fileExistsSync} from './fs.js'\nimport {outputDebug, outputInfo} from './output.js'\nimport {joinPath} from './path.js'\nimport {exec, terminalSupportsPrompting} from './system.js'\nimport {renderSelectPrompt} from './ui.js'\nimport {LocalStorage} from './local-storage.js'\nimport {\n ConfSchema,\n getSkillInstallPromptDismissed,\n setSkillInstallPromptDismissed,\n runAtMinimumInterval,\n} from '../../private/node/conf-store.js'\n\ntype SkillInstallPromptChoice = 'install' | 'later' | 'never'\n\n/**\n * Options for {@link promptShopifySkillInstallIfNeeded}.\n */\nexport interface PromptShopifySkillInstallOptions {\n /** The command being run, used to avoid prompting recursively from `skill` commands. */\n currentCommand: string\n\n /** The arguments of the command being run, used to avoid corrupting `--json` output. */\n args?: string[]\n\n /** The process argv, used to re-invoke the current CLI binary. */\n argv?: string[]\n\n /** The process environment. */\n env?: NodeJS.ProcessEnv\n\n /** The cli-kit local storage, injectable for testing. */\n config?: LocalStorage<ConfSchema>\n\n /** The user's home directory, injectable for testing. */\n homeDir?: string\n}\n\n/**\n * Checks whether the Shopify skill for coding agents is installed globally.\n *\n * The skills CLI installs universal skills under `~/.agents/skills` (older versions)\n * or `$XDG_CONFIG_HOME/agents/skills` (newer versions), so both locations are checked.\n *\n * @param env - The process environment.\n * @param homeDir - The user's home directory.\n * @returns Whether the Shopify skill is installed in any known global location.\n */\nexport function shopifySkillIsInstalled(env: NodeJS.ProcessEnv = process.env, homeDir = homeDirectory()): boolean {\n const configHome = env.XDG_CONFIG_HOME ?? joinPath(homeDir, '.config')\n const skillDirectories = [\n joinPath(homeDir, '.agents', 'skills', 'shopify'),\n joinPath(configHome, 'agents', 'skills', 'shopify'),\n ]\n return skillDirectories.some(fileExistsSync)\n}\n\n/**\n * Asks the user whether to install the Shopify skill for coding agents when it\n * isn't installed yet. Selecting yes runs `shopify skill install` in a detached\n * background process, so the current command is never delayed.\n *\n * The prompt is shown at most once per day, and never again once the skill is\n * detected as installed or the user opts out, so deliberately uninstalling the\n * skill won't trigger new prompts.\n *\n * Skipped for `skill` commands (to avoid recursion), for `--json` output, in\n * non-interactive terminals, in CI, in unit tests, in development mode, and\n * when `SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT` is set.\n *\n * @param options - See {@link PromptShopifySkillInstallOptions}.\n */\nexport async function promptShopifySkillInstallIfNeeded(options: PromptShopifySkillInstallOptions): Promise<void> {\n const {currentCommand, args = [], argv = process.argv, env = process.env, config, homeDir} = options\n\n if (skipSkillInstallPrompt(currentCommand, args, env)) return\n if (getSkillInstallPromptDismissed(config)) return\n if (shopifySkillIsInstalled(env, homeDir)) {\n setSkillInstallPromptDismissed(config)\n return\n }\n\n const nodeBinary = argv[0]\n const shopifyBinary = argv[1]\n if (!nodeBinary || !shopifyBinary) return\n\n // Ask at most once per day: the timestamp is recorded when the prompt is shown,\n // so both \"ask me tomorrow\" and a failed install naturally re-prompt a day later.\n await runAtMinimumInterval(\n 'skill-install-prompt',\n {days: 1},\n async () => {\n const choice: SkillInstallPromptChoice = await renderSelectPrompt({\n message:\n 'The Shopify skill helps coding agents like Claude Code, Cursor, and Codex build with Shopify. Install it?',\n choices: [\n {label: 'Yes, install it now', value: 'install'},\n {label: 'No, ask me tomorrow', value: 'later'},\n {label: 'No, never ask again', value: 'never'},\n ],\n })\n\n switch (choice) {\n case 'install':\n // Run the Shopify command the same way as the current execution, detached\n // from the current process so the CLI can exit before the install finishes.\n // eslint-disable-next-line no-void\n void exec(nodeBinary, [shopifyBinary, 'skill', 'install'], {\n background: true,\n env: {...env, SHOPIFY_CLI_NO_ANALYTICS: '1'},\n externalErrorHandler: async (error: unknown) => {\n outputDebug(`Failed to install the Shopify skill in background: ${(error as Error).message}`)\n },\n })\n outputInfo(\n 'Installing the Shopify skill in the background. Run `shopify skill install` to reinstall it at any time.',\n )\n break\n case 'later':\n // Nothing to record: the daily interval re-prompts on the first command tomorrow.\n break\n case 'never':\n setSkillInstallPromptDismissed(config)\n break\n }\n },\n config,\n )\n}\n\nfunction skipSkillInstallPrompt(currentCommand: string, args: string[], env: NodeJS.ProcessEnv): boolean {\n return (\n currentCommand.startsWith('skill') ||\n args.includes('--json') ||\n isTruthy(env.SHOPIFY_FLAG_JSON) ||\n isTruthy(env.CI) ||\n isTruthy(env.SHOPIFY_UNIT_TEST) ||\n isTruthy(env.SHOPIFY_CLI_NO_SKILL_INSTALL_PROMPT) ||\n isDevelopment(env) ||\n !terminalSupportsPrompting()\n )\n}\n"]}
|