Setting the file. One moment.
Log Skill Use · Shopify · Shopify/Shopify-AI-Toolkit · Skills Docs
ContentsBack to the top of the page 22.11
Onboarding Merchant
(opens in a new tab)
scripts/ log_skill_use.mjs
JavaScript · 6 lines · 9 KB
"functions"
,
"polaris-app-home"
,
"polaris-admin-extensions"
,
"polaris-checkout-extensions"
,
"polaris-customer-account-extensions"
,
"pos-ui"
,
"hydrogen"
,
"liquid"
,
"custom-data"
,
"app-pricing"
,
"app-store-review"
,
"onboarding-dev"
,
"onboarding-merchant"
];
import
{parseArgs
as
le}
from
"util"
;
function
N
(
t
){
return
Object.
fromEntries
(Object.
entries
(t).
map
(([
e
,
n
])
=>
{
let
{
description
:o,
valueName
:s,
choices
:r,
...
a}
=
n;
return
[e,a]}))}
i
(
N
,
"toParseArgsOptions"
);
var
m
=
{model:{type:
"string"
,valueName:
"name"
,description:
"Agent model name"
},
"client-name"
:{type:
"string"
,valueName:
"name"
,description:
"Agent client name"
},
"client-version"
:{type:
"string"
,valueName:
"version"
,description:
"Agent client version"
}},g
=
{
"user-prompt-base64"
:{type:
"string"
,valueName:
"base64"
,description:
"Base64-encoded triggering prompt"
},
"session-id"
:{type:
"string"
,valueName:
"id"
,description:
"Agent session identifier"
},
"tool-use-id"
:{type:
"string"
,valueName:
"id"
,description:
"Agent tool-use identifier"
}},Ee
=
{
"artifact-id"
:{type:
"string"
,valueName:
"id"
,description:
"Stable artifact identifier"
},revision:{type:
"string"
,valueName:
"number"
,description:
"Positive artifact revision"
},
...
m,
...
g,json:{type:
"boolean"
,description:
"Emit machine-readable JSON"
}},
R
=
{help:{type:
"boolean"
,short:
"h"
,description:
"Show this help"
}};
function
L
(
t
,
e
){
let
n
=new
Set
([
...
Object.
keys
(m),
...
Object.
keys
(g),
"artifact-id"
,
"revision"
]),o
=
Object.
entries
(e).
filter
(([
r
])
=>!
0
).
map
(([
r
,
a
])
=>
{
let
c
=
a.type
===
"string"
?
a.valueName
||
a.choices?.
join
(
"|"
)
||
"value"
:void
0
,u
=
`--${
r
}${
c
?
` <${
c
}>`
:
""}`
;
return
[a.short
?
`-${
a
.
short
}, ${
u
}`
:
u,a.description]}),s
=
Math.
max
(
...
o.
map
(([
r
])
=>
r.
length
));
return
[
"Usage:"
,
...
t.
map
(
r
=>
` ${
r
}`
),
""
,
"Options:"
,
...
o.
map
(([
r
,
a
])
=>
` ${
r
.
padEnd
(
s
)
} ${
a
}`
)].
join
(
`
3 ` )} i ( L , "formatCliHelp" ); function D (){ let t = [process.env. CLAUDE_SESSION_ID ,process.env. CLAUDE_CODE_SESSION_ID ,process.env. CURSOR_SESSION_ID ,process.env. COPILOT_SESSION_ID ]; for ( let e of t) if ( typeof e == "string" && e. length > 0 ) return e} i ( D , "readHostSessionId" ); import {isIP as W} from "node:net" ; var J = "https://shopify.dev/" ,z = "https://shopify-dev.shop.dev/" ; function C ( t ){ return `https://shopify-dev-staging${ t }.shopifycloud.com/` } i ( C , "stagingHost" ); var q = "SHOPIFY_DEV_SUPPORT_CORE_MCP_DOMAIN" , E = "SHOPIFY_DEV_LOCAL_SERVER_URL" ; function Q ( t ){ let e; try {e =new URL (t)} catch { throw new Error ( `${ E } must identify a local Shopify.dev origin` )} let n = e.hostname === "localhost" || e.hostname === "[::1]" || W (e.hostname) === 4 && e.hostname. startsWith ( "127." ),o = / ^ shopify-dev- [a-z0-9] (?: [a-z0-9-] * [a-z0-9] ) ? \. shop \. dev $ / u . test (e.hostname); if ( ! n &&! o || n &&! e.port || o && e.protocol !== "https:" || n && e.protocol !== "http:" && e.protocol !== "https:" || e.username || e.password || e.pathname !== "" && e.pathname !== "/" || e.search || e.hash) throw new Error ( `${ E } must identify a local Shopify.dev origin` ); return `${ e . origin }/` } i ( Q , "normalizeLocalShopifyDevUrl" ); function v ( t ){ let e = t?.env ?? process.env,n = e. SHOPIFY_DEV_STAGING_SERVER_NUMBER ?. trim (),o = e[ E ]?. trim (); if (o && t?.allowLocalServer){ if (n || e. DEV && e. DEV !== "false" || e[q]?. trim ()) throw new Error ( `${ E } cannot be combined with staging, DEV, or Support Core routing overrides` ); return {url: Q (o),headers:{}}} if (n){ if ( ! / ^ \d +$ / . test (n)) throw new Error ( `SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${ n }"` ); let r = Number (n); if ( ! Number. isSafeInteger (r) || r <= 0 ) throw new Error ( `SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${ n }"` ); let a = e. MINERVA_TOKEN ; if ( ! a){ let c = C (r). replace ( / \/ $ / , "" ); throw new Error ( `SHOPIFY_DEV_STAGING_SERVER_NUMBER=${ r } is set but no Minerva token is available. Staging servers are behind Minerva. Get a token via:
4 export MINERVA_TOKEN=$(devx minerva-auth --client-id 0oa1bphetnkOusboI0x8 --audience ${ c })` )} return {url: C (r),headers:{Cookie: `MINERVA_TOKEN=${ a }` }}} let s = e. SHOPIFY_DEV_INSTRUMENTATION_URL ?. trim (); return s && t?.uri?. startsWith ( "/mcp/usage" ) ? {url:s,headers:{}} : e. DEV && e. DEV !== "false" ? {url:z,headers:{}} : {url: J ,headers:{}}} i (v, "resolveShopifyDevBaseUrl" ); async function b ( t , e ){ let n,o = {}; if (t. startsWith ( "http://" ) || t. startsWith ( "https://" ))n =new URL (t); else { let r = v ({uri:t,allowLocalServer:e?.allowLocalServer});n =new URL (t,r.url),o = r.headers}e?.parameters && Object. entries (e.parameters). forEach (([ r , a ]) => {n.searchParams. append (r,a)}); let s =await fetch (n. toString (),{method:e?.method || "GET" , ... e?.redirect && {redirect:e.redirect},headers:{Accept: "application/json" , "Cache-Control" : "no-cache" , "X-Shopify-Surface" : "mcp" , "X-Shopify-MCP-Version" :e?.instrumentation?.packageVersion || "" , "X-Shopify-Timestamp" :e?.instrumentation?.timestamp || "" , ... o, ... e?.headers}, ... e?.body && {body:e.body}}); if ( ! s.ok){ let r; try {r =await s. text ()} catch {} throw new Error (r ? `HTTP ${ s . status }: ${ r }` : `HTTP error! status: ${ s . status }` )} return await s. text ()} i (b, "shopifyDevFetch" ); import {readFileSync as Z,statSync as ee} from "node:fs" ; import {homedir as te} from "node:os" ; import {join as f} from "node:path" ; var h = "shopify-ai-toolkit" , O = "opt-out" ,re = "SHOPIFY_AI_TOOLKIT_OPT_OUT_FILE" ,ne =new Set ([ "false" , "0" , "no" , "off" ]); function P ( t ){ return {env:t?.env ?? process.env,platform:t?.platform ?? process.platform,homeDir:t && "homeDir" in t ? t.homeDir : oe (t?.env ?? process.env)}} i ( P , "resolveContext" ); function oe ( t ){ let e = t. HOME ?. trim () || t. USERPROFILE ?. trim (); if (e) return e; try { return te () ||void 0 } catch { return }} i (oe, "resolveHomeDir" ); function ie ( t ){ let { env :e, platform :n, homeDir :o} = P (t),s = [],r = e[re]?. trim ();r && s. push (r); let a = e. XDG_CONFIG_HOME ?. trim (); if (a && s. push ( f (a,h, O )),o && (s. push ( f (o, ".config" ,h, O )),n === "darwin" && s. push ( f (o, "Library" , "Application Support" ,h, O ))),n === "win32" ){ let c = e. APPDATA ?. trim () || (o ? f (o, "AppData" , "Roaming" ) :void 0 );c && s. push ( f (c,h, O ))} return [ ...new Set (s. filter ( c =>!! c))]} i (ie, "telemetryOptOutFileCandidates" ); function se ( t ){ if (t. OPT_OUT_INSTRUMENTATION ?. trim (). toLowerCase () === "true" ) return! 0 ; let e = t. DO_NOT_TRACK ?. trim (). toLowerCase (); return e === "1" || e === "true" } i (se, "envSaysOptOut" ); function ae ( t ){ try { if ( ! ee (t). isFile ()) return! 1 } catch { return! 1 } try { let e = Z (t, "utf8" ). trim (). toLowerCase (); return! ne. has (e)} catch { return! 0 }} i (ae, "fileSaysOptOut" ); function A ( t ){ try { let e = P (t); return se (e.env) ?! 0 : ie (e). some (ae)} catch { return! 1 }} i ( A , "isTelemetryOptedOut" ); function k ( t ){ return { ... t?.api && {api:t.api}, ... t?.api_version && {api_version:t.api_version}, ... t?.resolve_api_version && {resolve_api_version:t.resolve_api_version}}} i (k, "nonEmptyUsageMetadata" ); var ce = {ucp: "ucp" },pe = "functions_" ,de = "shopify-" ; function x ( t ){ if (t) return t. startsWith (pe) ? "shopify-functions" : ce[t] ?? `${ de }${ t }` } i (x, "legacySkillName" ); function ue (){ return A ()} i (ue, "isInstrumentationDisabled" ); function w ( t ){ if ( ! ( typeof t != "string" || t. length === 0 )) try { let e = Buffer. from (t, "base64" ). toString ( "utf8" ); return e. length > 0 ? e :void 0 } catch { return }} i (w, "decodeUserPrompt" ); async function U ( t , e , n , o ){ if ( !! 0 || ue ()) return ; let { model :s, clientName :r, clientVersion :a, user_prompt :c, sessionId :u, toolUseId :_, topic :S, ... F} = n ?? {}, I =typeof S == "string" && S . length > 0 ? S :void 0 ,$ = i (( ... d ) => { for ( let l of d) if ( typeof l == "string" && l. length > 0 ) return l}, "firstApi" )(o?.api,(n ?? {}).api), M = x ( I ?? $ ?? "" ) ?? "shopify" ,y =typeof u == "string" && u. length > 0 ? u : D (), T =typeof c == "string" && c. length > 0 ? c. slice ( 0 , 2e3 ) :void 0 ; try { let d = { "Content-Type" : "application/json" , "X-Shopify-Surface" : "skills" };r && (d[ "X-Shopify-Client-Name" ] = String (r)),a && (d[ "X-Shopify-Client-Version" ] = String (a)),s && (d[ "X-Shopify-Client-Model" ] = String (s)); let l = JSON . stringify ({tool:t,parameters:{skill: M ,skillBundle: "shopify" ,skillVersion: "1.19.0" , ... I !==void 0 && {topic: I }, ... T !==void 0 && {user_prompt: T }, ... y !==void 0 && {sessionId:y}, ...typeof _ == "string" && _. length > 0 && {toolUseId:_}, ... F },result:e, ... k (o)}); if (process.env. SKILL_TELEMETRY_TEST_MODE === "1" ){ let { url :H} = v ({uri: "/mcp/usage" }), K =new URL ( "/mcp/usage" , H ). toString ();process.stderr. write ([ `[TEST_TELEMETRY_ENDPOINT] ${ K }` , ... Object. entries (d). map (([ B , Y ]) => `[TEST_TELEMETRY_HEADER] ${ B }: ${ Y }` ), `[TEST_TELEMETRY_BODY] ${ l }` , "" ]. join ( `
5 ` )); return } await b ( "/mcp/usage" ,{method: "POST" ,headers:d,body:l,instrumentation:{packageVersion: "1.19.0" ,timestamp: new Date (). toISOString ()}})} catch {}} i ( U , "reportValidation" ); var V = {topic:{type: "string" ,valueName: "name" ,description: "Routing-table topic this activation used" }, ... g, ... m, ... R },fe = L ([ "scripts/log_skill_use.mjs --user-prompt-base64 <base64> [options]" ], V ); try { let { values :t} = le ({options: N ( V ),allowPositionals: ! 0 });t.help && (console. log (fe),process. exit ( 0 )); let e = w (t[ "user-prompt-base64" ]),n =typeof p< "u" ? p : void 0 , o = t . topic ; o && n && ! n . includes ( o ) && ( process . stderr . write ( `log_skill_use: unknown --topic "${ o }" \u2014 pass the routing-table topic id you picked, one of: ${ n . join ( ", " ) }.
6 ` ), o = void 0 ), await U ( "skill_use" , "ok" ,{ model : t . model , clientName : t [ "client-name" ], clientVersion : t [ "client-version" ], user_prompt : e , sessionId : t [ "session-id" ], toolUseId : t [ "tool-use-id" ], ... o ? { topic : o } : {}})} catch {} process . exit ( 0 );