@playtagon/cli 0.4.4 → 0.4.6

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/index.js CHANGED
@@ -1942,7 +1942,7 @@ import { Command as Command8 } from "commander";
1942
1942
  import * as fs5 from "fs";
1943
1943
  import * as path6 from "path";
1944
1944
  import ora6 from "ora";
1945
- var watchCommand = new Command8("watch").description("Watch directory for new Spine exports and auto-upload").argument("<directory>", "Directory to watch for Spine files").option("-s, --studio <studio>", "Studio ID or slug (uses default if set)").option("-g, --game <game>", "Game ID or slug (uses default if set)").option("--batch", "Enable batch mode for multiple skeletons sharing atlas").option("--interval <seconds>", "Check interval in seconds", "2").option("--debug", "Enable debug output").action(async (directory, options) => {
1945
+ var watchCommand = new Command8("watch").description("Watch directory for new Spine exports and auto-upload").argument("<directory>", "Directory to watch for Spine files").option("-s, --studio <studio>", "Studio ID or slug (uses default if set)").option("-g, --game <game>", "Game ID or slug (uses default if set)").option("--batch", "Enable batch mode for multiple skeletons sharing atlas").option("--interval <seconds>", "Check interval in seconds", "2").option("--debug", "Enable debug output").option("--upload-existing", "Upload files that are already in the directory when watcher starts").action(async (directory, options) => {
1946
1946
  if (!credentials.isLoggedIn()) {
1947
1947
  logger.error("Not logged in.");
1948
1948
  logger.info(`Run ${logger.command("playtagon login")} first.`);
@@ -2012,6 +2012,22 @@ var watchCommand = new Command8("watch").description("Watch directory for new Sp
2012
2012
  console.log(` ${path6.relative(absolutePath, file)}`);
2013
2013
  }
2014
2014
  }
2015
+ if (options.uploadExisting && initialFiles.length > 0) {
2016
+ const hasAtlas = initialAtlas.length > 0;
2017
+ const hasTextures = initialTextures.length > 0;
2018
+ const hasSkeletons = initialSkeletons.length > 0;
2019
+ if (hasAtlas && hasTextures && hasSkeletons) {
2020
+ console.log();
2021
+ logger.info("--upload-existing flag detected, uploading current files...");
2022
+ await uploadDirectory(absolutePath, state, options.batch);
2023
+ console.log();
2024
+ } else {
2025
+ console.log();
2026
+ logger.warn("--upload-existing: Incomplete file set, skipping upload");
2027
+ logger.warn(` Missing: ${!hasAtlas ? "atlas " : ""}${!hasTextures ? "textures " : ""}${!hasSkeletons ? "skeletons" : ""}`);
2028
+ console.log();
2029
+ }
2030
+ }
2015
2031
  console.log();
2016
2032
  logger.info("Watching for changes... (Press Ctrl+C to stop)");
2017
2033
  console.log();
@@ -2105,6 +2121,10 @@ async function checkForChanges(directory, state, batchMode, debug = false) {
2105
2121
  const skeletonFiles = files.filter((f) => f.endsWith(".json") || f.endsWith(".skel"));
2106
2122
  const textureFiles = files.filter((f) => /\.(png|jpg|jpeg|webp)$/i.test(f));
2107
2123
  console.log(` Found: ${skeletonFiles.length} skeleton(s), ${atlasFiles.length} atlas, ${textureFiles.length} texture(s)`);
2124
+ state.pendingUpload = false;
2125
+ state.isUploading = true;
2126
+ await uploadDirectory(directory, state, batchMode);
2127
+ state.isUploading = false;
2108
2128
  for (const file of files) {
2109
2129
  try {
2110
2130
  const stats = fs5.statSync(file);
@@ -2112,10 +2132,6 @@ async function checkForChanges(directory, state, batchMode, debug = false) {
2112
2132
  } catch (error) {
2113
2133
  }
2114
2134
  }
2115
- state.pendingUpload = false;
2116
- state.isUploading = true;
2117
- await uploadDirectory(directory, state, batchMode);
2118
- state.isUploading = false;
2119
2135
  }
2120
2136
  async function uploadDirectory(directory, state, batchMode) {
2121
2137
  const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
@@ -2579,7 +2595,7 @@ var configCommand = new Command11("config").description("View or set CLI configu
2579
2595
 
2580
2596
  // src/index.ts
2581
2597
  var program = new Command12();
2582
- program.name("playtagon").description("Playtagon CLI - Upload and manage game assets").version("0.4.4");
2598
+ program.name("playtagon").description("Playtagon CLI - Upload and manage game assets").version("0.4.6");
2583
2599
  program.addCommand(loginCommand);
2584
2600
  program.addCommand(logoutCommand);
2585
2601
  program.addCommand(whoamiCommand);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/utils/logger.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/spine/index.ts","../src/commands/spine/validate.ts","../src/lib/spine-validator.ts","../src/utils/files.ts","../src/commands/spine/upload.ts","../src/lib/api.ts","../src/commands/spine/preset.ts","../src/commands/spine/sync.ts","../src/lib/codegen.ts","../src/commands/spine/watch.ts","../src/commands/setup.ts","../src/commands/config.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { whoamiCommand } from './commands/whoami.js';\nimport { spineCommand } from './commands/spine/index.js';\nimport { setupCommand } from './commands/setup.js';\nimport { configCommand } from './commands/config.js';\n\nconst program = new Command();\n\nprogram\n .name('playtagon')\n .description('Playtagon CLI - Upload and manage game assets')\n .version('0.4.4');\n\n// Add commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(spineCommand);\nprogram.addCommand(setupCommand);\nprogram.addCommand(configCommand);\n\n// Parse arguments\nprogram.parse();\n","import { Command } from 'commander';\nimport * as readline from 'node:readline';\nimport open from 'open';\nimport ora from 'ora';\nimport { loginWithEmail, loginWithBrowser, getAuthUrl, getCurrentUser } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with Playtagon')\n .option('-e, --email <email>', 'Login with email/password instead of browser')\n .option('--no-browser', 'Use email/password login instead of browser')\n .action(async (options) => {\n // Check if already logged in\n if (credentials.isLoggedIn()) {\n const user = await getCurrentUser();\n if (user) {\n logger.info(`Already logged in as ${logger.value(user.email)}`);\n logger.info(`Run ${logger.command('playtagon logout')} to sign out.`);\n return;\n }\n }\n\n if (options.email) {\n await emailLogin(options.email);\n } else if (options.browser === false) {\n await promptEmailLogin();\n } else {\n // Default: browser-based login (like npm, gh, vercel)\n await browserLogin();\n }\n });\n\nasync function promptEmailLogin(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const question = (prompt: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(prompt, resolve);\n });\n\n try {\n const email = await question('Email: ');\n const password = await questionHidden('Password: ', rl);\n\n const spinner = ora('Logging in...').start();\n\n try {\n await loginWithEmail(email, password);\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n logger.header('Account');\n logger.item('Email', user.email);\n if (user.studios.length > 0) {\n logger.item(\n 'Studios',\n user.studios.map((s) => s.name).join(', ')\n );\n }\n }\n } catch (error) {\n spinner.fail('Login failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n } finally {\n rl.close();\n }\n}\n\nasync function emailLogin(email: string): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const password = await questionHidden('Password: ', rl);\n\n const spinner = ora('Logging in...').start();\n\n try {\n await loginWithEmail(email, password);\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n logger.header('Account');\n logger.item('Email', user.email);\n }\n } catch (error) {\n spinner.fail('Login failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n } finally {\n rl.close();\n }\n}\n\nasync function browserLogin(): Promise<void> {\n const authUrl = getAuthUrl();\n\n console.log();\n logger.info('Opening browser to log in...');\n logger.info('');\n logger.info(`If browser doesn't open, visit:`);\n logger.info(` ${logger.link(authUrl)}`);\n console.log();\n\n // Open browser\n try {\n await open(authUrl);\n } catch {\n // Browser failed to open, user can use the URL manually\n }\n\n const spinner = ora('Waiting for authentication...').start();\n\n // Start local server and wait for callback\n const result = await loginWithBrowser();\n\n if (result.success) {\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n console.log();\n logger.header('Account');\n logger.item('Email', user.email);\n if (user.studios.length > 0) {\n logger.item(\n 'Studios',\n user.studios.map((s) => s.name).join(', ')\n );\n }\n }\n } else {\n spinner.fail('Login failed');\n logger.error(result.error || 'Unknown error');\n console.log();\n logger.info('You can also try email/password login:');\n logger.info(` ${logger.command('playtagon login --no-browser')}`);\n process.exit(1);\n }\n}\n\n// Hidden password input\nfunction questionHidden(\n prompt: string,\n rl: readline.Interface\n): Promise<string> {\n return new Promise((resolve) => {\n const stdin = process.stdin;\n const stdout = process.stdout;\n\n stdout.write(prompt);\n\n const wasRaw = stdin.isRaw;\n\n if (stdin.isTTY) {\n stdin.setRawMode(true);\n }\n\n let password = '';\n\n const onData = (char: Buffer) => {\n const c = char.toString('utf8');\n\n switch (c) {\n case '\\n':\n case '\\r':\n case '\\u0004':\n // Enter or Ctrl+D\n if (stdin.isTTY) {\n stdin.setRawMode(wasRaw ?? false);\n }\n stdin.removeListener('data', onData);\n stdout.write('\\n');\n resolve(password);\n break;\n case '\\u0003':\n // Ctrl+C\n process.exit(1);\n break;\n case '\\u007F':\n // Backspace\n password = password.slice(0, -1);\n break;\n default:\n password += c;\n break;\n }\n };\n\n stdin.on('data', onData);\n });\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\nimport * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport { config, credentials } from './config.js';\nimport { logger } from '../utils/logger.js';\n\nlet supabaseClient: SupabaseClient | null = null;\n\n// PKCE helpers\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nfunction sha256(buffer: string): Buffer {\n return crypto.createHash('sha256').update(buffer).digest();\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32));\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return base64URLEncode(sha256(verifier));\n}\n\nexport function getSupabaseClient(): SupabaseClient {\n if (!supabaseClient) {\n supabaseClient = createClient(config.supabaseUrl, config.supabaseAnonKey, {\n auth: {\n persistSession: false,\n autoRefreshToken: false,\n },\n });\n }\n return supabaseClient;\n}\n\nexport async function getAuthenticatedClient(): Promise<SupabaseClient> {\n const client = getSupabaseClient();\n\n if (!credentials.isLoggedIn()) {\n throw new Error('Not logged in. Run `playtagon login` first.');\n }\n\n // Check if token is expired and needs refresh\n if (credentials.isExpired() && credentials.refreshToken) {\n logger.debug('Token expired, refreshing...');\n await refreshSession();\n }\n\n // Set the session\n const accessToken = credentials.accessToken;\n if (!accessToken) {\n throw new Error('No access token found. Run `playtagon login` first.');\n }\n\n await client.auth.setSession({\n access_token: accessToken,\n refresh_token: credentials.refreshToken || '',\n });\n\n return client;\n}\n\nexport async function refreshSession(): Promise<void> {\n const client = getSupabaseClient();\n const refreshToken = credentials.refreshToken;\n\n if (!refreshToken) {\n throw new Error('No refresh token found. Run `playtagon login` first.');\n }\n\n const { data, error } = await client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n credentials.clear();\n throw new Error(`Failed to refresh session: ${error.message}`);\n }\n\n if (data.session) {\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n });\n }\n}\n\nexport async function loginWithEmail(\n email: string,\n password: string\n): Promise<void> {\n const client = getSupabaseClient();\n\n const { data, error } = await client.auth.signInWithPassword({\n email,\n password,\n });\n\n if (error) {\n throw new Error(`Login failed: ${error.message}`);\n }\n\n if (!data.session) {\n throw new Error('Login failed: No session returned');\n }\n\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n userId: data.user?.id,\n email: data.user?.email,\n });\n}\n\nexport interface OAuthLoginResult {\n success: boolean;\n error?: string;\n}\n\nexport async function loginWithBrowser(): Promise<OAuthLoginResult> {\n return new Promise((resolve) => {\n const port = 19419;\n const redirectUri = `http://localhost:${port}/callback`;\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n\n // Build the Supabase auth URL with PKCE\n const authUrl = new URL(`${config.supabaseUrl}/auth/v1/authorize`);\n authUrl.searchParams.set('provider', 'google'); // or use generic PKCE\n authUrl.searchParams.set('redirect_to', redirectUri);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n\n // For email login via browser, we use the Supabase hosted UI\n const loginUrl = new URL(`${config.supabaseUrl}/auth/v1/authorize`);\n // Use the platform's auth page instead\n const platformAuthUrl = `https://playtagon.com/cli-auth?redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${codeChallenge}`;\n\n let server: http.Server | null = null;\n let timeoutId: NodeJS.Timeout | null = null;\n\n const cleanup = () => {\n if (timeoutId) clearTimeout(timeoutId);\n if (server) {\n server.close();\n server = null;\n }\n };\n\n // Create local server to receive the callback\n server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`);\n\n if (url.pathname === '/callback') {\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n if (error) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(errorDescription || error));\n cleanup();\n resolve({ success: false, error: errorDescription || error });\n return;\n }\n\n // Handle tokens directly (from platform CLI auth page)\n const accessToken = url.searchParams.get('access_token');\n const refreshToken = url.searchParams.get('refresh_token');\n\n if (accessToken) {\n credentials.save({\n accessToken,\n refreshToken: refreshToken || undefined,\n expiresAt: Date.now() + 3600 * 1000,\n });\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml(''));\n cleanup();\n resolve({ success: true });\n return;\n }\n\n // Handle OAuth code exchange flow (fallback)\n const code = url.searchParams.get('code');\n if (code) {\n try {\n // Exchange code for session\n const client = getSupabaseClient();\n const { data, error: exchangeError } = await client.auth.exchangeCodeForSession(code);\n\n if (exchangeError || !data.session) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(exchangeError?.message || 'Failed to exchange code'));\n cleanup();\n resolve({ success: false, error: exchangeError?.message || 'Failed to exchange code' });\n return;\n }\n\n // Save credentials\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n userId: data.user?.id,\n email: data.user?.email,\n });\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml(data.user?.email || ''));\n cleanup();\n resolve({ success: true });\n } catch (err) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(err instanceof Error ? err.message : 'Unknown error'));\n cleanup();\n resolve({ success: false, error: err instanceof Error ? err.message : 'Unknown error' });\n }\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('No authorization token received'));\n cleanup();\n resolve({ success: false, error: 'No authorization token received' });\n } else {\n res.writeHead(404);\n res.end('Not found');\n }\n });\n\n server.listen(port, () => {\n logger.info(`Waiting for authentication on port ${port}...`);\n });\n\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n cleanup();\n resolve({ success: false, error: `Port ${port} is already in use. Please close any applications using it.` });\n } else {\n cleanup();\n resolve({ success: false, error: err.message });\n }\n });\n\n // Timeout after 5 minutes\n timeoutId = setTimeout(() => {\n cleanup();\n resolve({ success: false, error: 'Authentication timed out. Please try again.' });\n }, 5 * 60 * 1000);\n });\n}\n\nexport function getAuthUrl(): string {\n const port = 19419;\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Use platform's auth page which handles the Supabase flow\n return `https://playtagon.com/cli-auth?redirect_uri=${encodeURIComponent(redirectUri)}`;\n}\n\nfunction getSuccessHtml(email: string): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Login Successful - Playtagon CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n color: #fff;\n }\n .container {\n text-align: center;\n padding: 40px;\n background: rgba(255,255,255,0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n }\n .checkmark {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 { margin: 0 0 10px; font-size: 24px; }\n p { margin: 0; opacity: 0.8; }\n .email { font-weight: bold; color: #4ade80; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"checkmark\">✓</div>\n <h1>Login Successful!</h1>\n <p>You're now logged in${email ? ` as <span class=\"email\">${email}</span>` : ''}.</p>\n <p style=\"margin-top: 20px; opacity: 0.6;\">You can close this window and return to your terminal.</p>\n </div>\n</body>\n</html>`;\n}\n\nfunction getErrorHtml(error: string): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Login Failed - Playtagon CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n color: #fff;\n }\n .container {\n text-align: center;\n padding: 40px;\n background: rgba(255,255,255,0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n }\n .icon {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 { margin: 0 0 10px; font-size: 24px; color: #f87171; }\n p { margin: 0; opacity: 0.8; }\n .error { color: #fca5a5; font-family: monospace; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✗</div>\n <h1>Login Failed</h1>\n <p class=\"error\">${error}</p>\n <p style=\"margin-top: 20px; opacity: 0.6;\">Please return to your terminal and try again.</p>\n </div>\n</body>\n</html>`;\n}\n\nexport function logout(): void {\n credentials.clear();\n}\n\nexport async function getCurrentUser(): Promise<{\n id: string;\n email: string;\n studios: Array<{ id: string; name: string; slug: string }>;\n} | null> {\n try {\n const client = await getAuthenticatedClient();\n\n const {\n data: { user },\n error,\n } = await client.auth.getUser();\n\n if (error || !user) {\n return null;\n }\n\n // Fetch user's studios\n const { data: memberships } = await client.from('studio_members').select(`\n studio:studios (\n id,\n name,\n slug\n )\n `)\n .eq('user_id', user.id);\n\n const studios =\n memberships\n ?.map((m) => m.studio as unknown as { id: string; name: string; slug: string })\n .filter(Boolean) || [];\n\n return {\n id: user.id,\n email: user.email || '',\n studios,\n };\n } catch {\n return null;\n }\n}\n\nexport function getAccessToken(): string | undefined {\n return credentials.accessToken;\n}\n","import Conf from 'conf';\n\nexport interface PlaytagonConfig {\n supabaseUrl?: string;\n supabaseAnonKey?: string;\n defaultStudio?: string;\n defaultGame?: string;\n}\n\nexport interface PlaytagonCredentials {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n userId?: string;\n email?: string;\n}\n\n// Default Supabase config - can be overridden via environment variables\nconst DEFAULT_SUPABASE_URL = process.env.PLAYTAGON_SUPABASE_URL || 'https://pthbeazcwnhjljwksuae.supabase.co';\nconst DEFAULT_SUPABASE_ANON_KEY = process.env.PLAYTAGON_SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB0aGJlYXpjd25oamxqd2tzdWFlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjcxMjIzNDEsImV4cCI6MjA4MjY5ODM0MX0.ls0hO-UigKnl9cj2NEkxjQL4TnijkIG50iImqZIThVc';\n\n// Config store for settings\nconst configStore = new Conf<PlaytagonConfig>({\n projectName: 'playtagon',\n configFileMode: 0o600,\n defaults: {\n supabaseUrl: DEFAULT_SUPABASE_URL,\n supabaseAnonKey: DEFAULT_SUPABASE_ANON_KEY,\n },\n});\n\n// Separate store for credentials (more sensitive)\nconst credentialsStore = new Conf<PlaytagonCredentials>({\n projectName: 'playtagon',\n configName: 'credentials',\n configFileMode: 0o600,\n});\n\nexport const config = {\n get supabaseUrl(): string {\n return configStore.get('supabaseUrl') || DEFAULT_SUPABASE_URL;\n },\n\n get supabaseAnonKey(): string {\n return configStore.get('supabaseAnonKey') || DEFAULT_SUPABASE_ANON_KEY;\n },\n\n get defaultStudio(): string | undefined {\n return configStore.get('defaultStudio');\n },\n\n set defaultStudio(value: string | undefined) {\n if (value) {\n configStore.set('defaultStudio', value);\n } else {\n configStore.delete('defaultStudio');\n }\n },\n\n get defaultGame(): string | undefined {\n return configStore.get('defaultGame');\n },\n\n set defaultGame(value: string | undefined) {\n if (value) {\n configStore.set('defaultGame', value);\n } else {\n configStore.delete('defaultGame');\n }\n },\n\n // Get full config\n getAll(): PlaytagonConfig {\n return configStore.store;\n },\n\n // Get config file path\n get path(): string {\n return configStore.path;\n },\n};\n\nexport const credentials = {\n get accessToken(): string | undefined {\n return credentialsStore.get('accessToken');\n },\n\n get refreshToken(): string | undefined {\n return credentialsStore.get('refreshToken');\n },\n\n get expiresAt(): number | undefined {\n return credentialsStore.get('expiresAt');\n },\n\n get userId(): string | undefined {\n return credentialsStore.get('userId');\n },\n\n get email(): string | undefined {\n return credentialsStore.get('email');\n },\n\n isLoggedIn(): boolean {\n return !!credentialsStore.get('accessToken');\n },\n\n isExpired(): boolean {\n const expiresAt = credentialsStore.get('expiresAt');\n if (!expiresAt) return true;\n // Consider expired if less than 5 minutes remaining\n return Date.now() > expiresAt - 5 * 60 * 1000;\n },\n\n save(creds: PlaytagonCredentials): void {\n if (creds.accessToken) credentialsStore.set('accessToken', creds.accessToken);\n if (creds.refreshToken) credentialsStore.set('refreshToken', creds.refreshToken);\n if (creds.expiresAt) credentialsStore.set('expiresAt', creds.expiresAt);\n if (creds.userId) credentialsStore.set('userId', creds.userId);\n if (creds.email) credentialsStore.set('email', creds.email);\n },\n\n clear(): void {\n credentialsStore.clear();\n },\n\n // Get credentials file path\n get path(): string {\n return credentialsStore.path;\n },\n};\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('info'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('success'), message);\n },\n\n warn: (message: string) => {\n console.log(chalk.yellow('warn'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('error'), message);\n },\n\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(chalk.gray('debug'), message);\n }\n },\n\n // Styled output for specific contexts\n file: (filename: string) => chalk.cyan(filename),\n value: (val: string | number) => chalk.yellow(val),\n command: (cmd: string) => chalk.bold.white(cmd),\n url: (url: string) => chalk.underline.blue(url),\n link: (url: string) => chalk.underline.cyan(url),\n\n // Section headers\n header: (title: string) => {\n console.log();\n console.log(chalk.bold.white(title));\n console.log(chalk.gray('─'.repeat(title.length)));\n },\n\n // List item\n item: (label: string, value: string) => {\n console.log(` ${chalk.gray(label + ':')} ${value}`);\n },\n\n // Validation result formatting\n validationError: (message: string, detail?: string) => {\n console.log(` ${chalk.red('✗')} ${message}`);\n if (detail) {\n console.log(` ${chalk.gray(detail)}`);\n }\n },\n\n validationSuccess: (message: string) => {\n console.log(` ${chalk.green('✓')} ${message}`);\n },\n\n validationWarn: (message: string) => {\n console.log(` ${chalk.yellow('!')} ${message}`);\n },\n};\n","import { Command } from 'commander';\nimport { logout } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Sign out of Playtagon')\n .action(() => {\n if (!credentials.isLoggedIn()) {\n logger.info('Not currently logged in.');\n return;\n }\n\n const email = credentials.email;\n logout();\n\n if (email) {\n logger.success(`Logged out from ${logger.value(email)}`);\n } else {\n logger.success('Logged out successfully');\n }\n });\n","import { Command } from 'commander';\nimport ora from 'ora';\nimport { getCurrentUser } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const whoamiCommand = new Command('whoami')\n .description('Show current logged in user')\n .action(async () => {\n if (!credentials.isLoggedIn()) {\n logger.info('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} to authenticate.`);\n return;\n }\n\n const spinner = ora('Fetching user info...').start();\n\n try {\n const user = await getCurrentUser();\n\n if (!user) {\n spinner.fail('Session expired');\n logger.info(`Run ${logger.command('playtagon login')} to re-authenticate.`);\n return;\n }\n\n spinner.stop();\n\n logger.header('Current User');\n logger.item('ID', user.id);\n logger.item('Email', user.email);\n\n if (user.studios.length > 0) {\n console.log();\n logger.header('Studios');\n for (const studio of user.studios) {\n console.log(` ${studio.name} (${logger.value(studio.slug)})`);\n }\n } else {\n console.log();\n logger.warn('No studios found. Join or create a studio in the platform.');\n }\n } catch (error) {\n spinner.fail('Failed to fetch user info');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { validateCommand } from './validate.js';\nimport { uploadCommand } from './upload.js';\nimport { presetCommand } from './preset.js';\nimport { syncCommand } from './sync.js';\nimport { watchCommand } from './watch.js';\n\nexport const spineCommand = new Command('spine')\n .description('Manage Spine animation assets')\n .addCommand(validateCommand)\n .addCommand(uploadCommand)\n .addCommand(watchCommand)\n .addCommand(presetCommand)\n .addCommand(syncCommand);\n","import { Command } from 'commander';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { validateDirectory, type BatchValidation } from '../../lib/spine-validator.js';\nimport { formatFileSize } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const validateCommand = new Command('validate')\n .description('Validate Spine files before uploading')\n .argument('<directory>', 'Directory containing Spine files')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .action(async (directory: string, options: { batch?: boolean }) => {\n const absolutePath = path.resolve(directory);\n\n const spinner = ora(`Validating ${logger.file(directory)}...`).start();\n\n try {\n const result = validateDirectory(absolutePath, options.batch);\n spinner.stop();\n\n printValidationResult(result, directory);\n\n if (!result.isValid) {\n process.exit(1);\n }\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n\nfunction printValidationResult(result: BatchValidation, directory: string): void {\n console.log();\n logger.header(`Validation: ${directory}`);\n\n // Summary info\n if (result.isBatchMode) {\n console.log(` Mode: ${logger.value('Batch')} (${result.assets.length} skeletons)`);\n if (result.sharedAtlas) {\n console.log(` Shared Atlas: ${logger.file(path.basename(result.sharedAtlas))}`);\n console.log(` Shared Textures: ${result.sharedTextures.length}`);\n }\n } else if (result.assets.length > 0) {\n console.log(` Mode: ${logger.value('Single')}`);\n }\n\n console.log(` Total Size: ${logger.value(formatFileSize(result.totalSize))}`);\n console.log();\n\n // Print each asset\n for (const asset of result.assets) {\n const statusIcon = asset.isValid ? '✓' : '✗';\n const statusColor = asset.isValid ? 'green' : 'red';\n\n console.log(\n ` ${statusIcon} ${logger.file(asset.skeleton.name)}`\n );\n console.log(` Spine: ${asset.skeleton.spineVersion}`);\n console.log(` Animations: ${asset.skeleton.animations.length}`);\n console.log(` Skins: ${asset.skeleton.skins.length}`);\n\n if (asset.atlasPath) {\n console.log(` Atlas: ${path.basename(asset.atlasPath)}`);\n console.log(` Textures: ${asset.texturePaths.length}`);\n }\n }\n\n console.log();\n\n // Print all issues\n const errors = result.issues.filter((i) => i.type === 'error');\n const warnings = result.issues.filter((i) => i.type === 'warning');\n const infos = result.issues.filter((i) => i.type === 'info');\n\n // Info messages\n for (const info of infos) {\n logger.info(info.message);\n }\n\n // Warnings\n if (warnings.length > 0) {\n console.log();\n for (const warning of warnings) {\n logger.validationWarn(\n warning.file ? `${warning.file}: ${warning.message}` : warning.message\n );\n if ((warning as { detail?: string }).detail) {\n console.log(` ${(warning as { detail: string }).detail}`);\n }\n }\n }\n\n // Errors\n if (errors.length > 0) {\n console.log();\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message,\n (error as { detail?: string }).detail\n );\n }\n }\n\n // Final status\n console.log();\n if (result.isValid) {\n logger.success('Validation passed! Ready for upload.');\n } else {\n logger.error(`Validation failed with ${errors.length} error(s).`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport {\n discoverSpineFiles,\n matchSkeletonToAtlas,\n parseAtlasTextures,\n getFileSize,\n getTotalSize,\n formatFileSize,\n type DiscoveredFiles,\n} from '../utils/files.js';\n\n// Validation rules - keep in sync with server and platform\nexport const SPINE_VALIDATION_RULES = {\n supportedVersions: ['4.0', '4.1', '4.2', '4.3'] as const,\n maxTextureSize: 4096, // pixels per dimension\n maxTotalSize: 50 * 1024 * 1024, // 50MB\n maxTextureCount: 8,\n slugPattern: /^[a-z0-9-]+$/,\n animationNamePattern: /^[a-zA-Z0-9_-]+$/,\n} as const;\n\nexport interface ValidationError {\n type: 'error';\n message: string;\n file?: string;\n detail?: string;\n}\n\nexport interface ValidationWarning {\n type: 'warning';\n message: string;\n file?: string;\n detail?: string;\n}\n\nexport interface ValidationInfo {\n type: 'info';\n message: string;\n}\n\nexport type ValidationIssue = ValidationError | ValidationWarning | ValidationInfo;\n\nexport interface SkeletonInfo {\n path: string;\n name: string;\n spineVersion: string;\n animations: string[];\n skins: string[];\n hasEvents: boolean;\n boneCount: number;\n slotCount: number;\n}\n\nexport interface AssetValidation {\n skeleton: SkeletonInfo;\n atlasPath: string | null;\n texturePaths: string[];\n totalSize: number;\n issues: ValidationIssue[];\n isValid: boolean;\n}\n\nexport interface BatchValidation {\n assets: AssetValidation[];\n sharedAtlas: string | null;\n sharedTextures: string[];\n totalSize: number;\n issues: ValidationIssue[];\n isValid: boolean;\n isBatchMode: boolean;\n}\n\nexport function validateDirectory(\n directory: string,\n batchMode = false\n): BatchValidation {\n const discovered = discoverSpineFiles(directory);\n const issues: ValidationIssue[] = [];\n\n // Check if we found any skeleton files\n if (discovered.skeletons.length === 0) {\n issues.push({\n type: 'error',\n message: 'No Spine skeleton files found in this directory',\n detail: 'Expected exported files: skeleton.json + skeleton.atlas + texture.png. Export from Spine Editor first (File → Export → JSON).',\n });\n return {\n assets: [],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize: 0,\n issues,\n isValid: false,\n isBatchMode: false,\n };\n }\n\n // Determine if this is batch mode (multiple skeletons sharing atlas)\n const isBatchMode = batchMode || discovered.skeletons.length > 1;\n\n if (isBatchMode && discovered.skeletons.length > 1) {\n return validateBatch(discovered, issues);\n } else {\n return validateSingle(discovered, issues);\n }\n}\n\nfunction validateSingle(\n discovered: DiscoveredFiles,\n issues: ValidationIssue[]\n): BatchValidation {\n const skeletonPath = discovered.skeletons[0];\n const skeleton = parseSkeletonFile(skeletonPath);\n\n if (!skeleton) {\n issues.push({\n type: 'error',\n message: 'Failed to parse skeleton file',\n file: path.basename(skeletonPath),\n });\n return {\n assets: [],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize: 0,\n issues,\n isValid: false,\n isBatchMode: false,\n };\n }\n\n // Validate spine version\n const versionIssues = validateSpineVersion(skeleton);\n issues.push(...versionIssues);\n\n // Match atlas\n const atlasPath = matchSkeletonToAtlas(skeletonPath, discovered.atlases);\n if (!atlasPath) {\n if (discovered.atlases.length === 0) {\n issues.push({\n type: 'error',\n message: 'No atlas file found',\n detail: 'Expected .atlas file',\n });\n } else {\n issues.push({\n type: 'warning',\n message: 'Could not match skeleton to atlas',\n detail: `Found atlases: ${discovered.atlases.map((a) => path.basename(a)).join(', ')}`,\n });\n }\n }\n\n // Get textures from atlas\n let texturePaths: string[] = [];\n if (atlasPath) {\n texturePaths = parseAtlasTextures(atlasPath);\n const textureIssues = validateTextures(texturePaths);\n issues.push(...textureIssues);\n }\n\n // Check for orphan textures\n const orphanTextures = discovered.textures.filter(\n (t) => !texturePaths.includes(t)\n );\n if (orphanTextures.length > 0) {\n issues.push({\n type: 'warning',\n message: `${orphanTextures.length} texture(s) not referenced in atlas`,\n detail: orphanTextures.map((t) => path.basename(t)).join(', '),\n });\n }\n\n // Calculate total size\n const allFiles = [skeletonPath, atlasPath, ...texturePaths].filter(\n Boolean\n ) as string[];\n const totalSize = getTotalSize(allFiles);\n\n // Validate total size\n if (totalSize > SPINE_VALIDATION_RULES.maxTotalSize) {\n issues.push({\n type: 'error',\n message: `Total size ${formatFileSize(totalSize)} exceeds ${formatFileSize(SPINE_VALIDATION_RULES.maxTotalSize)} limit`,\n });\n }\n\n // Validate animation names\n const animationIssues = validateAnimationNames(skeleton.animations);\n issues.push(...animationIssues);\n\n const hasErrors = issues.some((i) => i.type === 'error');\n\n const asset: AssetValidation = {\n skeleton,\n atlasPath,\n texturePaths,\n totalSize,\n issues: issues.filter(\n (i) =>\n (i as ValidationError | ValidationWarning).file === undefined ||\n (i as ValidationError | ValidationWarning).file === path.basename(skeletonPath)\n ),\n isValid: !hasErrors,\n };\n\n return {\n assets: [asset],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize,\n issues,\n isValid: !hasErrors,\n isBatchMode: false,\n };\n}\n\nfunction validateBatch(\n discovered: DiscoveredFiles,\n issues: ValidationIssue[]\n): BatchValidation {\n const assets: AssetValidation[] = [];\n\n // In batch mode, we expect a shared atlas\n let sharedAtlas: string | null = null;\n let sharedTextures: string[] = [];\n\n if (discovered.atlases.length === 1) {\n sharedAtlas = discovered.atlases[0];\n sharedTextures = parseAtlasTextures(sharedAtlas);\n\n issues.push({\n type: 'info',\n message: `Batch mode: ${discovered.skeletons.length} skeletons sharing 1 atlas`,\n });\n } else if (discovered.atlases.length === 0) {\n issues.push({\n type: 'error',\n message: 'No atlas file found for batch upload',\n });\n } else {\n issues.push({\n type: 'warning',\n message: `Multiple atlases found (${discovered.atlases.length}). Batch mode works best with shared atlas.`,\n });\n }\n\n // Validate each skeleton\n for (const skeletonPath of discovered.skeletons) {\n const skeleton = parseSkeletonFile(skeletonPath);\n\n if (!skeleton) {\n issues.push({\n type: 'error',\n message: 'Failed to parse skeleton file',\n file: path.basename(skeletonPath),\n });\n continue;\n }\n\n // Validate spine version\n const versionIssues = validateSpineVersion(skeleton);\n issues.push(...versionIssues);\n\n // Validate animation names\n const animationIssues = validateAnimationNames(skeleton.animations);\n issues.push(...animationIssues);\n\n // Each skeleton uses the shared atlas\n const atlasPath = sharedAtlas || matchSkeletonToAtlas(skeletonPath, discovered.atlases);\n const texturePaths = atlasPath ? parseAtlasTextures(atlasPath) : [];\n\n // Calculate size for this asset (skeleton only, atlas counted once at the end)\n const skeletonSize = getFileSize(skeletonPath);\n\n assets.push({\n skeleton,\n atlasPath,\n texturePaths,\n totalSize: skeletonSize,\n issues: [],\n isValid: true,\n });\n }\n\n // Validate shared textures\n if (sharedTextures.length > 0) {\n const textureIssues = validateTextures(sharedTextures);\n issues.push(...textureIssues);\n }\n\n // Calculate total size (atlas + textures counted once)\n const skeletonSizes = assets.reduce((sum, a) => sum + a.totalSize, 0);\n const atlasSize = sharedAtlas ? getFileSize(sharedAtlas) : 0;\n const textureSize = getTotalSize(sharedTextures);\n const totalSize = skeletonSizes + atlasSize + textureSize;\n\n // Validate total size\n if (totalSize > SPINE_VALIDATION_RULES.maxTotalSize) {\n issues.push({\n type: 'error',\n message: `Total batch size ${formatFileSize(totalSize)} exceeds ${formatFileSize(SPINE_VALIDATION_RULES.maxTotalSize)} limit`,\n });\n }\n\n const hasErrors = issues.some((i) => i.type === 'error');\n\n return {\n assets,\n sharedAtlas,\n sharedTextures,\n totalSize,\n issues,\n isValid: !hasErrors,\n isBatchMode: true,\n };\n}\n\nfunction parseSkeletonFile(filePath: string): SkeletonInfo | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const json = JSON.parse(content);\n\n if (!json.skeleton?.spine) {\n return null;\n }\n\n const name = path.basename(filePath, path.extname(filePath));\n const spineVersion = json.skeleton.spine;\n const animations = json.animations ? Object.keys(json.animations) : [];\n const skins = json.skins\n ? Array.isArray(json.skins)\n ? json.skins.map((s: { name?: string }) => s.name || 'default')\n : Object.keys(json.skins)\n : ['default'];\n const hasEvents = !!json.events && Object.keys(json.events).length > 0;\n const boneCount = json.bones ? json.bones.length : 0;\n const slotCount = json.slots ? json.slots.length : 0;\n\n return {\n path: filePath,\n name,\n spineVersion,\n animations,\n skins,\n hasEvents,\n boneCount,\n slotCount,\n };\n } catch {\n return null;\n }\n}\n\nfunction validateSpineVersion(skeleton: SkeletonInfo): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Extract major.minor version\n const version = skeleton.spineVersion;\n const majorMinor = version.match(/^(\\d+\\.\\d+)/)?.[1];\n\n if (\n !majorMinor ||\n !SPINE_VALIDATION_RULES.supportedVersions.includes(\n majorMinor as (typeof SPINE_VALIDATION_RULES.supportedVersions)[number]\n )\n ) {\n issues.push({\n type: 'error',\n message: `Unsupported Spine version: ${version}`,\n file: path.basename(skeleton.path),\n detail: `Supported versions: ${SPINE_VALIDATION_RULES.supportedVersions.join(', ')}`,\n });\n }\n\n return issues;\n}\n\nfunction validateAnimationNames(animations: string[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const name of animations) {\n if (!SPINE_VALIDATION_RULES.animationNamePattern.test(name)) {\n issues.push({\n type: 'warning',\n message: `Animation name \"${name}\" contains invalid characters`,\n detail: 'Recommended: a-z, A-Z, 0-9, _, -',\n });\n }\n }\n\n return issues;\n}\n\nfunction validateTextures(texturePaths: string[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check texture count\n if (texturePaths.length > SPINE_VALIDATION_RULES.maxTextureCount) {\n issues.push({\n type: 'error',\n message: `Too many textures: ${texturePaths.length}`,\n detail: `Maximum allowed: ${SPINE_VALIDATION_RULES.maxTextureCount}`,\n });\n }\n\n // Check each texture\n for (const texturePath of texturePaths) {\n if (!fs.existsSync(texturePath)) {\n issues.push({\n type: 'error',\n message: `Texture file not found: ${path.basename(texturePath)}`,\n });\n continue;\n }\n\n // Check file size (basic check - full dimension check would require image parsing)\n const size = getFileSize(texturePath);\n if (size > 20 * 1024 * 1024) {\n // 20MB per texture is suspicious\n issues.push({\n type: 'warning',\n message: `Large texture file: ${path.basename(texturePath)} (${formatFileSize(size)})`,\n detail: 'Consider optimizing texture size',\n });\n }\n }\n\n return issues;\n}\n\nexport function generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function validateSlug(slug: string): boolean {\n return SPINE_VALIDATION_RULES.slugPattern.test(slug);\n}\n\n// Export preset for Spine Editor\n// Full preset with texture packing settings\n// Note: 'output' field should be set by user in Spine UI\nexport const SPINE_EXPORT_PRESET = {\n class: 'export-json',\n name: 'Playtagon Platform',\n extension: '.json',\n format: 'JSON',\n nonessential: false,\n cleanUp: true,\n pack: true,\n prettyPrint: false,\n packAtlas: {\n stripWhitespaceX: true,\n stripWhitespaceY: true,\n rotation: true,\n alias: true,\n ignoreBlankImages: false,\n alphaThreshold: 3,\n minWidth: 16,\n minHeight: 16,\n maxWidth: 2048,\n maxHeight: 2048,\n pot: true,\n square: false,\n multipleOfFour: false,\n outputFormat: 'png',\n jpegQuality: 0.9,\n premultiplyAlpha: false,\n paddingX: 2,\n paddingY: 2,\n edgePadding: true,\n duplicatePadding: false,\n filterMin: 'Linear',\n filterMag: 'Linear',\n wrapX: 'ClampToEdge',\n wrapY: 'ClampToEdge',\n format: 'RGBA8888',\n atlasExtension: '.atlas',\n combineSubdirectories: false,\n flattenPaths: false,\n useIndexes: false,\n packing: 'polygons',\n fast: false,\n limitMemory: true,\n scale: [0.5],\n scaleSuffix: [''],\n scaleResampling: ['bilinear'],\n legacyOutput: false,\n debug: false,\n silent: false,\n },\n packSource: 'attachments',\n packTarget: 'single',\n warnings: true,\n version: null,\n all: false,\n open: false,\n};\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface SpineFileSet {\n skeletonFile: string; // .json or .skel\n atlasFile: string | null; // .atlas\n textureFiles: string[]; // .png or .jpg\n}\n\nexport interface DiscoveredFiles {\n skeletons: string[];\n atlases: string[];\n textures: string[];\n}\n\n// File extensions\nconst SKELETON_EXTENSIONS = ['.json', '.skel'];\nconst ATLAS_EXTENSIONS = ['.atlas'];\nconst TEXTURE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'];\n\nexport function discoverSpineFiles(directory: string): DiscoveredFiles {\n const absolutePath = path.resolve(directory);\n\n if (!fs.existsSync(absolutePath)) {\n throw new Error(`Directory not found: ${absolutePath}\\n\\nMake sure you're pointing to a folder containing exported Spine files (.json, .atlas, .png), not a .spine project file.`);\n }\n\n if (!fs.statSync(absolutePath).isDirectory()) {\n const ext = path.extname(absolutePath).toLowerCase();\n if (ext === '.spine') {\n throw new Error(`Cannot upload .spine project files directly.\\n\\nYou need to export from Spine Editor first:\\n 1. Open ${path.basename(absolutePath)} in Spine Editor\\n 2. Go to File → Export\\n 3. Export as JSON with atlas\\n 4. Upload the exported folder`);\n }\n throw new Error(`Not a directory: ${absolutePath}\\n\\nThe upload command expects a folder containing exported Spine files (.json, .atlas, .png).`);\n }\n\n const files = fs.readdirSync(absolutePath);\n\n const skeletons: string[] = [];\n const atlases: string[] = [];\n const textures: string[] = [];\n\n for (const file of files) {\n const ext = path.extname(file).toLowerCase();\n const fullPath = path.join(absolutePath, file);\n\n // Skip directories\n if (fs.statSync(fullPath).isDirectory()) continue;\n\n if (SKELETON_EXTENSIONS.includes(ext)) {\n // For .json files, we need to verify it's actually a Spine skeleton\n if (ext === '.json') {\n if (isSpineSkeletonJson(fullPath)) {\n skeletons.push(fullPath);\n }\n } else {\n skeletons.push(fullPath);\n }\n } else if (ATLAS_EXTENSIONS.includes(ext)) {\n atlases.push(fullPath);\n } else if (TEXTURE_EXTENSIONS.includes(ext)) {\n textures.push(fullPath);\n }\n }\n\n return { skeletons, atlases, textures };\n}\n\nexport function isSpineSkeletonJson(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const json = JSON.parse(content);\n // Spine skeleton files have a \"skeleton\" property with version info\n return json.skeleton && typeof json.skeleton.spine === 'string';\n } catch {\n return false;\n }\n}\n\nexport function matchSkeletonToAtlas(\n skeletonPath: string,\n atlases: string[]\n): string | null {\n const skeletonName = path.basename(skeletonPath, path.extname(skeletonPath));\n const skeletonDir = path.dirname(skeletonPath);\n\n // Try exact name match first\n for (const atlas of atlases) {\n const atlasName = path.basename(atlas, '.atlas');\n if (atlasName === skeletonName) {\n return atlas;\n }\n }\n\n // If only one atlas in same directory, use it\n const sameDirectoryAtlases = atlases.filter(\n (a) => path.dirname(a) === skeletonDir\n );\n if (sameDirectoryAtlases.length === 1) {\n return sameDirectoryAtlases[0];\n }\n\n return null;\n}\n\nexport function parseAtlasTextures(atlasPath: string): string[] {\n const content = fs.readFileSync(atlasPath, 'utf-8');\n const lines = content.split('\\n');\n const textures: string[] = [];\n const atlasDir = path.dirname(atlasPath);\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Texture file names are on their own lines, can be .png, .jpg, or .webp\n // They can also include relative paths like \"subdir/texture.png\"\n if (trimmed.endsWith('.png') || trimmed.endsWith('.jpg') || trimmed.endsWith('.jpeg') || trimmed.endsWith('.webp')) {\n // Handle both absolute and relative paths\n const texturePath = path.isAbsolute(trimmed)\n ? trimmed\n : path.join(atlasDir, trimmed);\n\n if (fs.existsSync(texturePath)) {\n textures.push(texturePath);\n }\n }\n }\n\n return textures;\n}\n\nexport function getFileSize(filePath: string): number {\n return fs.statSync(filePath).size;\n}\n\nexport function getTotalSize(files: string[]): number {\n return files.reduce((total, file) => total + getFileSize(file), 0);\n}\n\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function readFileAsBuffer(filePath: string): Buffer {\n return fs.readFileSync(filePath);\n}\n\nexport function getBaseName(filePath: string): string {\n return path.basename(filePath);\n}\n\nexport function getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { getAccessToken } from '../../lib/auth.js';\nimport { uploadSpineAsset, resolveStudio, resolveGame } from '../../lib/api.js';\nimport {\n validateDirectory,\n generateSlug,\n validateSlug,\n type BatchValidation,\n} from '../../lib/spine-validator.js';\nimport { formatFileSize, getBaseName } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const uploadCommand = new Command('upload')\n .description('Upload Spine files to Playtagon')\n .argument('<directory>', 'Directory containing Spine files')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('-n, --name <name>', 'Asset name (defaults to directory name)')\n .option('--slug <slug>', 'Custom slug for the asset')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .option('--dry-run', 'Validate only, do not upload')\n .option('--description <text>', 'Asset description')\n .option('--tags <tags>', 'Comma-separated tags')\n .action(async (directory: string, options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n logger.info(` ${logger.command('playtagon setup spine-integration --studio <slug>')}`);\n process.exit(1);\n }\n\n const absolutePath = path.resolve(directory);\n\n // Validate directory first\n const spinner = ora('Validating files...').start();\n\n let validation: BatchValidation;\n try {\n validation = validateDirectory(absolutePath, options.batch);\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n\n if (!validation.isValid) {\n spinner.fail('Validation failed');\n printValidationErrors(validation);\n process.exit(1);\n }\n\n spinner.succeed(`Validated ${validation.assets.length} asset(s)`);\n\n // Resolve studio\n spinner.start('Resolving studio...');\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Determine asset name\n const assetName = options.name || path.basename(absolutePath);\n\n // Generate or validate slug\n let slug = options.slug || generateSlug(assetName);\n if (!validateSlug(slug)) {\n logger.error(`Invalid slug: \"${slug}\". Use lowercase letters, numbers, and hyphens only.`);\n process.exit(1);\n }\n\n // Print upload summary\n console.log();\n logger.header('Upload Summary');\n logger.item('Directory', directory);\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Name', assetName);\n logger.item('Slug', slug);\n logger.item('Size', formatFileSize(validation.totalSize));\n\n if (validation.isBatchMode) {\n logger.item('Mode', 'Batch');\n logger.item('Skeletons', String(validation.assets.length));\n }\n\n if (options.dryRun) {\n console.log();\n logger.success('Dry run complete. No files were uploaded.');\n return;\n }\n\n // Build FormData for upload\n console.log();\n spinner.start('Uploading...');\n\n try {\n const formData = await buildFormData(validation, {\n studioId: studio.id,\n gameId: game?.id,\n name: assetName,\n slug,\n description: options.description,\n tags: options.tags?.split(',').map((t: string) => t.trim()),\n batchMode: validation.isBatchMode,\n });\n\n const result = await uploadSpineAsset(formData);\n\n if (result.success) {\n spinner.succeed('Upload complete!');\n\n console.log();\n if (result.assets && result.assets.length > 1) {\n logger.header('Uploaded Assets');\n for (const asset of result.assets) {\n console.log(` ${logger.value(asset.name)} (${asset.slug})`);\n console.log(` ID: ${asset.id}`);\n console.log(` Status: ${asset.status}`);\n }\n } else if (result.asset) {\n logger.header('Uploaded Asset');\n logger.item('ID', result.asset.id);\n logger.item('Name', result.asset.name);\n logger.item('Slug', result.asset.slug);\n logger.item('Status', result.asset.status);\n }\n } else {\n spinner.fail('Upload failed');\n logger.error(result.error || 'Unknown error');\n process.exit(1);\n }\n } catch (error) {\n spinner.fail('Upload failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n\nasync function buildFormData(\n validation: BatchValidation,\n options: {\n studioId: string;\n gameId?: string;\n name: string;\n slug: string;\n description?: string;\n tags?: string[];\n batchMode: boolean;\n }\n): Promise<FormData> {\n const formData = new FormData();\n\n // Add metadata\n formData.append('studioId', options.studioId);\n if (options.gameId) formData.append('gameId', options.gameId);\n formData.append('name', options.name);\n formData.append('slug', options.slug);\n if (options.description) formData.append('description', options.description);\n if (options.tags) formData.append('tags', JSON.stringify(options.tags));\n if (options.batchMode) formData.append('batchMode', 'true');\n\n // Collect all unique files\n const filesAdded = new Set<string>();\n\n // Add skeleton files\n for (const asset of validation.assets) {\n const filePath = asset.skeleton.path;\n if (!filesAdded.has(filePath)) {\n const buffer = fs.readFileSync(filePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(filePath));\n filesAdded.add(filePath);\n }\n }\n\n // Add shared atlas if exists\n if (validation.sharedAtlas && !filesAdded.has(validation.sharedAtlas)) {\n const buffer = fs.readFileSync(validation.sharedAtlas);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(validation.sharedAtlas));\n filesAdded.add(validation.sharedAtlas);\n }\n\n // Add shared textures\n for (const texturePath of validation.sharedTextures) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n\n // Add individual asset files (atlas and textures for non-batch mode)\n for (const asset of validation.assets) {\n if (asset.atlasPath && !filesAdded.has(asset.atlasPath)) {\n const buffer = fs.readFileSync(asset.atlasPath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(asset.atlasPath));\n filesAdded.add(asset.atlasPath);\n }\n\n for (const texturePath of asset.texturePaths) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n }\n\n return formData;\n}\n\nfunction printValidationErrors(validation: BatchValidation): void {\n const errors = validation.issues.filter((i) => i.type === 'error');\n console.log();\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message,\n (error as { detail?: string }).detail\n );\n }\n console.log();\n logger.info(`Run ${logger.command('playtagon spine validate <dir>')} for full report.`);\n}\n","import { config } from './config.js';\nimport { getAccessToken } from './auth.js';\n\nconst API_BASE = config.supabaseUrl;\n\nexport interface UploadResponse {\n success: boolean;\n asset?: {\n id: string;\n name: string;\n slug: string;\n version: number;\n status: string;\n };\n assets?: Array<{\n id: string;\n name: string;\n slug: string;\n version: number;\n status: string;\n }>;\n error?: string;\n}\n\nexport interface StudioInfo {\n id: string;\n name: string;\n slug: string;\n}\n\nexport interface GameInfo {\n id: string;\n name: string;\n slug: string;\n}\n\nexport interface SyncAsset {\n id: string;\n slug: string;\n name: string;\n version: number;\n skeleton_url: string;\n skeleton_format: 'json' | 'binary';\n atlas_url: string;\n texture_urls: string[];\n animations: { name: string; duration: number }[];\n skins: { name: string }[];\n events: { name: string }[];\n total_size_bytes: number;\n updated_at: string;\n}\n\nexport interface SyncManifestResponse {\n assets: SyncAsset[];\n syncedAt: string;\n}\n\nexport async function uploadSpineAsset(formData: FormData): Promise<UploadResponse> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(`${API_BASE}/functions/v1/spine-upload`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorText;\n } catch {\n errorMessage = errorText;\n }\n throw new Error(`Upload failed: ${errorMessage}`);\n }\n\n return response.json();\n}\n\nexport async function getStudios(): Promise<StudioInfo[]> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(\n `${API_BASE}/rest/v1/studio_members?select=studio:studios(id,name,slug)`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch studios');\n }\n\n const data = await response.json();\n return data.map((m: { studio: StudioInfo }) => m.studio).filter(Boolean);\n}\n\nexport async function getGames(studioId: string): Promise<GameInfo[]> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(\n `${API_BASE}/rest/v1/games?studio_id=eq.${studioId}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch games');\n }\n\n return response.json();\n}\n\nexport async function resolveStudio(studioIdOrSlug: string): Promise<StudioInfo | null> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n // Try by ID first, then by slug (case-insensitive)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n studioIdOrSlug\n );\n\n const query = isUuid\n ? `id=eq.${studioIdOrSlug}`\n : `slug=ilike.${studioIdOrSlug}`; // ilike = case-insensitive LIKE\n\n const response = await fetch(\n `${API_BASE}/rest/v1/studios?${query}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data[0] || null;\n}\n\nexport async function resolveGame(\n studioId: string,\n gameIdOrSlug: string\n): Promise<GameInfo | null> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n gameIdOrSlug\n );\n\n const idQuery = isUuid\n ? `id=eq.${gameIdOrSlug}`\n : `slug=ilike.${gameIdOrSlug}`; // ilike = case-insensitive LIKE\n\n const response = await fetch(\n `${API_BASE}/rest/v1/games?studio_id=eq.${studioId}&${idQuery}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data[0] || null;\n}\n\nexport async function getSyncManifest(\n studioId: string,\n gameId?: string,\n since?: string\n): Promise<SyncManifestResponse> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const params = new URLSearchParams();\n params.set('studioId', studioId);\n if (gameId) params.set('gameId', gameId);\n if (since) params.set('since', since);\n\n const response = await fetch(\n `${API_BASE}/functions/v1/spine-assets/sync?${params}`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorText;\n } catch {\n errorMessage = errorText;\n }\n throw new Error(`Failed to fetch sync manifest: ${errorMessage}`);\n }\n\n return response.json();\n}\n","import { Command } from 'commander';\nimport { SPINE_EXPORT_PRESET } from '../../lib/spine-validator.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const presetCommand = new Command('preset')\n .description('Output Spine export preset JSON for consistent exports')\n .option('--pretty', 'Pretty print JSON (default: true)', true)\n .option('--compact', 'Output compact JSON')\n .action((options) => {\n const pretty = !options.compact;\n\n if (pretty) {\n // Print usage info to stderr so it doesn't interfere with piping\n console.error(logger.info('Spine Export Preset for Playtagon Platform'));\n console.error();\n console.error('Usage:');\n console.error(' playtagon spine preset > playtagon-export.json');\n console.error(' Import this file into Spine Editor as an export preset.');\n console.error();\n }\n\n // Output JSON to stdout for easy piping\n const json = pretty\n ? JSON.stringify(SPINE_EXPORT_PRESET, null, 2)\n : JSON.stringify(SPINE_EXPORT_PRESET);\n\n console.log(json);\n });\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { getSyncManifest, resolveStudio, resolveGame, type SyncAsset } from '../../lib/api.js';\nimport { generateAssetTypes, generateAssetStory, generateManifest } from '../../lib/codegen.js';\nimport { formatFileSize } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\ninterface SyncManifest {\n studioId: string;\n gameId?: string;\n syncedAt: string;\n assets: Record<string, {\n id: string;\n version: number;\n checksum: string;\n updatedAt: string;\n }>;\n}\n\nexport const syncCommand = new Command('sync')\n .description('Sync approved Spine assets to local project')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('-o, --output <dir>', 'Output directory', './src/assets/spine')\n .option('--types', 'Generate TypeScript types (default: true)', true)\n .option('--no-types', 'Skip TypeScript type generation')\n .option('--stories', 'Generate Storybook stories (default: true)', true)\n .option('--no-stories', 'Skip Storybook story generation')\n .option('--assets <slugs>', 'Comma-separated asset slugs to sync (default: all)')\n .option('--force', 'Overwrite local changes')\n .option('--dry-run', 'Show what would be synced without making changes')\n .action(async (options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n process.exit(1);\n }\n\n const outputDir = path.resolve(options.output);\n const manifestPath = path.join(outputDir, '.sync-manifest.json');\n\n // Resolve studio\n const spinner = ora('Resolving studio...').start();\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Load existing manifest for incremental sync\n let existingManifest: SyncManifest | null = null;\n let since: string | undefined;\n\n if (fs.existsSync(manifestPath) && !options.force) {\n try {\n existingManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n if (existingManifest && existingManifest.studioId === studio.id) {\n since = existingManifest.syncedAt;\n logger.info(`Incremental sync from ${new Date(since).toLocaleString()}`);\n }\n } catch {\n // Ignore invalid manifest\n }\n }\n\n // Fetch sync manifest from API\n spinner.start('Fetching asset manifest...');\n let manifest;\n try {\n manifest = await getSyncManifest(studio.id, game?.id, options.force ? undefined : since);\n } catch (error) {\n spinner.fail('Failed to fetch manifest');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n\n const assets = manifest.assets;\n\n // Filter by specific slugs if provided\n let assetsToSync = assets;\n if (options.assets) {\n const requestedSlugs = options.assets.split(',').map((s: string) => s.trim());\n assetsToSync = assets.filter((a: SyncAsset) => requestedSlugs.includes(a.slug));\n\n const found = assetsToSync.map((a: SyncAsset) => a.slug);\n const notFound = requestedSlugs.filter((s: string) => !found.includes(s));\n\n if (notFound.length > 0) {\n logger.warn(`Assets not found (or not approved): ${notFound.join(', ')}`);\n }\n }\n\n if (assetsToSync.length === 0) {\n spinner.succeed('No assets to sync');\n logger.info('All assets are up to date or no approved assets found.');\n return;\n }\n\n spinner.succeed(`Found ${assetsToSync.length} asset(s) to sync`);\n\n // Calculate total size\n const totalSize = assetsToSync.reduce((sum: number, a: SyncAsset) => sum + a.total_size_bytes, 0);\n\n // Print sync summary\n console.log();\n logger.header('Sync Summary');\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Output', outputDir);\n logger.item('Assets', String(assetsToSync.length));\n logger.item('Total Size', formatFileSize(totalSize));\n logger.item('TypeScript Types', options.types ? 'Yes' : 'No');\n logger.item('Storybook Stories', options.stories ? 'Yes' : 'No');\n\n console.log();\n logger.header('Assets');\n for (const asset of assetsToSync) {\n console.log(` ${logger.value(asset.name)} (${asset.slug}) v${asset.version}`);\n }\n\n if (options.dryRun) {\n console.log();\n logger.success('Dry run complete. No files were written.');\n return;\n }\n\n // Create output directory\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Download and generate files for each asset\n console.log();\n const syncedAssets: Record<string, { id: string; version: number; checksum: string; updatedAt: string }> = {};\n\n for (const asset of assetsToSync) {\n spinner.start(`Syncing ${asset.name}...`);\n\n try {\n const assetDir = path.join(outputDir, asset.slug);\n\n // Create asset directory\n if (!fs.existsSync(assetDir)) {\n fs.mkdirSync(assetDir, { recursive: true });\n }\n\n // Download skeleton file\n const skeletonExt = asset.skeleton_format === 'binary' ? '.skel' : '.json';\n const skeletonPath = path.join(assetDir, `${asset.slug}${skeletonExt}`);\n await downloadFile(asset.skeleton_url, skeletonPath);\n\n // Download atlas file\n const atlasPath = path.join(assetDir, `${asset.slug}.atlas`);\n await downloadFile(asset.atlas_url, atlasPath);\n\n // Download texture files\n for (const textureUrl of asset.texture_urls) {\n const textureName = path.basename(new URL(textureUrl).pathname);\n const texturePath = path.join(assetDir, textureName);\n await downloadFile(textureUrl, texturePath);\n }\n\n // Generate TypeScript types\n if (options.types) {\n const typesContent = generateAssetTypes(asset);\n const typesPath = path.join(assetDir, 'index.ts');\n fs.writeFileSync(typesPath, typesContent);\n }\n\n // Generate Storybook story (Svelte CSF format)\n if (options.stories) {\n const storyContent = generateAssetStory(asset);\n const storyPath = path.join(assetDir, `${pascalCase(asset.slug)}.stories.svelte`);\n fs.writeFileSync(storyPath, storyContent);\n }\n\n // Track synced asset\n syncedAssets[asset.slug] = {\n id: asset.id,\n version: asset.version,\n checksum: generateChecksum(asset),\n updatedAt: asset.updated_at,\n };\n\n spinner.succeed(`Synced ${asset.name}`);\n } catch (error) {\n spinner.fail(`Failed to sync ${asset.name}`);\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n }\n }\n\n // Merge with existing manifest\n const finalAssets = {\n ...(existingManifest?.assets || {}),\n ...syncedAssets,\n };\n\n // Generate manifest.ts with all asset exports\n if (options.types) {\n spinner.start('Generating manifest...');\n const manifestContent = generateManifest(Object.keys(finalAssets));\n fs.writeFileSync(path.join(outputDir, 'manifest.ts'), manifestContent);\n spinner.succeed('Generated manifest.ts');\n }\n\n // Save sync manifest\n const newManifest: SyncManifest = {\n studioId: studio.id,\n gameId: game?.id,\n syncedAt: manifest.syncedAt,\n assets: finalAssets,\n };\n fs.writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));\n\n console.log();\n logger.success(`Synced ${Object.keys(syncedAssets).length} asset(s) to ${outputDir}`);\n });\n\nasync function downloadFile(url: string, destPath: string): Promise<void> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download: ${response.status} ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n fs.writeFileSync(destPath, Buffer.from(buffer));\n}\n\nfunction generateChecksum(asset: SyncAsset): string {\n // Simple checksum based on version and updated_at\n const data = `${asset.id}:${asset.version}:${asset.updated_at}`;\n let hash = 0;\n for (let i = 0; i < data.length; i++) {\n const char = data.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(16);\n}\n\nfunction pascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n","import type { SyncAsset } from './api.js';\n\n/**\n * Convert a slug to PascalCase for type/const names\n */\nfunction pascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Convert a slug to camelCase for variable names\n */\nfunction camelCase(str: string): string {\n const pascal = pascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Escape a string for use in JavaScript string literals\n */\nfunction escapeString(str: string): string {\n return str.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate TypeScript types and config for a Spine asset\n */\nexport function generateAssetTypes(asset: SyncAsset): string {\n const name = pascalCase(asset.slug);\n const ext = asset.skeleton_format === 'binary' ? '.skel' : '.json';\n\n const animationNames = asset.animations.map(a => a.name);\n const skinNames = asset.skins.map(s => s.name);\n const eventNames = asset.events.map(e => e.name);\n\n return `// Auto-generated by @playtagon/cli\n// Do not edit manually - changes will be overwritten on next sync\n\n/**\n * ${asset.name}\n * @version ${asset.version}\n */\n\nexport const ${name}Animations = {\n${animationNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Animation = typeof ${name}Animations[keyof typeof ${name}Animations];\n\nexport const ${name}Skins = {\n${skinNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Skin = typeof ${name}Skins[keyof typeof ${name}Skins];\n\n${eventNames.length > 0 ? `export const ${name}Events = {\n${eventNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Event = typeof ${name}Events[keyof typeof ${name}Events];\n` : `export const ${name}Events = {} as const;\n\nexport type ${name}Event = never;\n`}\nexport interface ${name}AnimationInfo {\n name: ${name}Animation;\n duration: number;\n}\n\nexport const ${name}AnimationDurations: Record<${name}Animation, number> = {\n${asset.animations.map(a => ` '${escapeString(a.name)}': ${a.duration},`).join('\\n')}\n};\n\nexport const ${name} = {\n id: '${asset.slug}',\n name: '${escapeString(asset.name)}',\n version: ${asset.version},\n skeleton: './${asset.slug}${ext}',\n atlas: './${asset.slug}.atlas',\n animations: ${name}Animations,\n skins: ${name}Skins,\n events: ${name}Events,\n animationDurations: ${name}AnimationDurations,\n defaultAnimation: '${escapeString(animationNames[0] || 'idle')}' as ${name}Animation,\n defaultSkin: '${escapeString(skinNames[0] || 'default')}' as ${name}Skin,\n} as const;\n\nexport type ${name}Config = typeof ${name};\n\nexport default ${name};\n`;\n}\n\n/**\n * Generate a Storybook story for a Spine asset (Svelte CSF format)\n * Compatible with pixi-svelte's SpineAnimation component\n */\nexport function generateAssetStory(asset: SyncAsset): string {\n const name = pascalCase(asset.slug);\n\n // Generate individual animation stories\n const animationStories = asset.animations.map(anim => {\n return `<Story name=\"${escapeString(anim.name)}\">\n {#snippet template(args)}\n <StoryPixiApp {assets}>\n <SpineAnimation {...args} asset={${name}} animation=\"${escapeString(anim.name)}\" />\n </StoryPixiApp>\n {/snippet}\n</Story>`;\n }).join('\\n\\n');\n\n return `<!-- Auto-generated by @playtagon/cli -->\n<!-- Do not edit manually - changes will be overwritten on next sync -->\n\n<script lang=\"ts\" module>\n import { defineMeta } from '@storybook/addon-svelte-csf';\n import { SpineAnimation, createSpineAssets } from 'pixi-svelte';\n import { StoryPixiApp } from 'components-storybook';\n import ${name}, { ${name}Animations, ${name}Skins } from './index';\n\n const { Story } = defineMeta({\n title: 'Spine/${escapeString(asset.name)}',\n args: {\n width: 400,\n height: 400,\n x: 200,\n y: 200,\n loop: true,\n speed: 1,\n },\n argTypes: {\n animation: {\n control: 'select',\n options: Object.values(${name}Animations),\n description: 'Animation to play',\n },\n skin: {\n control: 'select',\n options: Object.values(${name}Skins),\n description: 'Skin to apply',\n },\n loop: {\n control: 'boolean',\n description: 'Whether to loop the animation',\n },\n speed: {\n control: { type: 'range', min: 0.1, max: 3, step: 0.1 },\n description: 'Playback speed multiplier',\n },\n },\n });\n\n // Create assets for Storybook - adjust baseUrl to match your asset serving path\n const assets = createSpineAssets([${name}], '.');\n</script>\n\n<!-- Default story with all controls -->\n<Story name=\"Default\">\n {#snippet template(args)}\n <StoryPixiApp {assets}>\n <SpineAnimation\n {...args}\n asset={${name}}\n animation={args.animation ?? ${name}.defaultAnimation}\n skin={args.skin ?? ${name}.defaultSkin}\n />\n </StoryPixiApp>\n {/snippet}\n</Story>\n\n<!-- Individual animation stories -->\n${animationStories}\n`;\n}\n\n/**\n * Generate the main manifest.ts file that exports all assets\n */\nexport function generateManifest(slugs: string[]): string {\n const imports = slugs.map(slug => {\n const name = pascalCase(slug);\n return `import ${name} from './${slug}';`;\n }).join('\\n');\n\n const exports = slugs.map(slug => {\n const name = pascalCase(slug);\n return ` ${name},`;\n }).join('\\n');\n\n const reexports = slugs.map(slug => {\n const name = pascalCase(slug);\n return `export * from './${slug}';`;\n }).join('\\n');\n\n return `// Auto-generated by @playtagon/cli\n// Do not edit manually - changes will be overwritten on next sync\n\n${imports}\n\nexport const SpineAssets = {\n${exports}\n} as const;\n\nexport type SpineAssetName = keyof typeof SpineAssets;\n\n// Re-export all individual assets\n${reexports}\n\nexport default SpineAssets;\n`;\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { uploadSpineAsset, resolveStudio, resolveGame } from '../../lib/api.js';\nimport {\n validateDirectory,\n generateSlug,\n validateSlug,\n type BatchValidation,\n} from '../../lib/spine-validator.js';\nimport { formatFileSize, getBaseName } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\ninterface WatchState {\n lastModified: Map<string, number>;\n isUploading: boolean;\n studioId: string;\n gameId?: string;\n lastChangeDetected: number;\n pendingUpload: boolean;\n}\n\nexport const watchCommand = new Command('watch')\n .description('Watch directory for new Spine exports and auto-upload')\n .argument('<directory>', 'Directory to watch for Spine files')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .option('--interval <seconds>', 'Check interval in seconds', '2')\n .option('--debug', 'Enable debug output')\n .action(async (directory: string, options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n process.exit(1);\n }\n\n const absolutePath = path.resolve(directory);\n\n // Verify directory exists\n if (!fs.existsSync(absolutePath)) {\n logger.error(`Directory not found: ${absolutePath}`);\n process.exit(1);\n }\n\n // Resolve studio\n const spinner = ora('Resolving studio...').start();\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Initialize watch state\n const state: WatchState = {\n lastModified: new Map(),\n isUploading: false,\n studioId: studio.id,\n gameId: game?.id,\n lastChangeDetected: 0,\n pendingUpload: false,\n };\n\n // Initial scan\n await scanDirectory(absolutePath, state);\n\n // Print watch info\n console.log();\n logger.header('Watching for Spine Exports');\n logger.item('Directory', absolutePath);\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Batch Mode', options.batch ? 'Yes' : 'No');\n logger.item('Check Interval', `${options.interval}s`);\n\n // Show initial file count\n const initialFiles = getAllFiles(absolutePath);\n const initialSkeletons = initialFiles.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const initialAtlas = initialFiles.filter(f => f.endsWith('.atlas'));\n const initialTextures = initialFiles.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n console.log();\n logger.info(`Found ${initialFiles.length} file(s) in directory:`);\n logger.info(` - ${initialSkeletons.length} skeleton(s) (.json/.skel)`);\n logger.info(` - ${initialAtlas.length} atlas (.atlas)`);\n logger.info(` - ${initialTextures.length} texture(s) (.png/.jpg/.webp)`);\n\n if (options.debug && initialFiles.length > 0) {\n console.log();\n logger.info('Files found:');\n for (const file of initialFiles) {\n console.log(` ${path.relative(absolutePath, file)}`);\n }\n }\n\n console.log();\n logger.info('Watching for changes... (Press Ctrl+C to stop)');\n console.log();\n\n // Start watching\n const intervalMs = parseInt(options.interval) * 1000;\n setInterval(async () => {\n await checkForChanges(absolutePath, state, options.batch, options.debug);\n }, intervalMs);\n\n // Keep process alive\n process.on('SIGINT', () => {\n console.log();\n logger.success('Stopped watching.');\n process.exit(0);\n });\n });\n\nasync function scanDirectory(directory: string, state: WatchState): Promise<void> {\n const files = getAllFiles(directory);\n\n for (const file of files) {\n const stats = fs.statSync(file);\n state.lastModified.set(file, stats.mtimeMs);\n }\n}\n\nfunction getAllFiles(directory: string): string[] {\n const files: string[] = [];\n\n try {\n const entries = fs.readdirSync(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(directory, entry.name);\n\n if (entry.isFile()) {\n // Only track Spine-related files\n const ext = path.extname(entry.name).toLowerCase();\n if (['.json', '.skel', '.atlas', '.png', '.jpg', '.jpeg', '.webp'].includes(ext)) {\n files.push(fullPath);\n }\n } else if (entry.isDirectory()) {\n files.push(...getAllFiles(fullPath));\n }\n }\n } catch (error) {\n // Ignore errors\n }\n\n return files;\n}\n\nasync function checkForChanges(\n directory: string,\n state: WatchState,\n batchMode: boolean,\n debug: boolean = false\n): Promise<void> {\n if (state.isUploading) {\n return; // Skip if already uploading\n }\n\n const files = getAllFiles(directory);\n let hasChanges = false;\n const currentChangeTime = Date.now();\n\n if (debug && files.length > 0) {\n const skeletons = files.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const atlas = files.filter(f => f.endsWith('.atlas'));\n const textures = files.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n console.log(`[DEBUG] Checking ${files.length} files: ${skeletons.length} skeleton(s), ${atlas.length} atlas, ${textures.length} texture(s)`);\n }\n\n // Check for new or modified files\n for (const file of files) {\n try {\n const stats = fs.statSync(file);\n const lastModified = state.lastModified.get(file) || 0;\n\n if (stats.mtimeMs > lastModified) {\n hasChanges = true;\n // Update last change time\n state.lastChangeDetected = currentChangeTime;\n state.pendingUpload = true;\n }\n } catch (error) {\n // File might have been deleted\n }\n }\n\n // If files are still changing, reset the timer\n if (hasChanges) {\n return; // Wait for files to settle\n }\n\n // No new changes - check if we have a pending upload\n if (!state.pendingUpload) {\n return; // Nothing to upload\n }\n\n // Wait for files to stabilize (no changes for at least 5 seconds)\n const timeSinceLastChange = currentChangeTime - state.lastChangeDetected;\n if (timeSinceLastChange < 5000) {\n return; // Files still settling\n }\n\n // Verify we have a complete set of files before uploading\n const hasAtlas = files.some(f => f.endsWith('.atlas'));\n const hasTextures = files.some(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n const hasSkeletons = files.some(f => f.endsWith('.json') || f.endsWith('.skel'));\n\n if (!hasAtlas) {\n console.log(' Waiting for .atlas file...');\n return;\n }\n\n if (!hasTextures) {\n console.log(' Waiting for texture files (.png/.jpg/.webp)...');\n return;\n }\n\n if (!hasSkeletons) {\n console.log(' Waiting for skeleton files (.json/.skel)...');\n return;\n }\n\n // Additional check: count files to ensure we have the expected set\n // In batch mode with multiple skeletons, we should have:\n // - Multiple .json files (one per skeleton)\n // - One .atlas file (shared)\n // - One or more texture files (shared)\n const atlasFiles = files.filter(f => f.endsWith('.atlas'));\n const skeletonFiles = files.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const textureFiles = files.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n\n console.log(` Found: ${skeletonFiles.length} skeleton(s), ${atlasFiles.length} atlas, ${textureFiles.length} texture(s)`);\n\n // Update state\n for (const file of files) {\n try {\n const stats = fs.statSync(file);\n state.lastModified.set(file, stats.mtimeMs);\n } catch (error) {\n // Ignore\n }\n }\n\n // Reset pending upload flag\n state.pendingUpload = false;\n\n // Trigger upload\n state.isUploading = true;\n await uploadDirectory(directory, state, batchMode);\n state.isUploading = false;\n}\n\nasync function uploadDirectory(\n directory: string,\n state: WatchState,\n batchMode: boolean\n): Promise<void> {\n const timestamp = new Date().toLocaleTimeString();\n console.log(`[${timestamp}] Changes detected, uploading...`);\n\n const spinner = ora('Validating files...').start();\n\n let validation: BatchValidation;\n try {\n validation = validateDirectory(directory, batchMode);\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n console.log();\n return;\n }\n\n if (!validation.isValid) {\n spinner.fail('Validation failed');\n const errors = validation.issues.filter((i) => i.type === 'error');\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message\n );\n }\n console.log();\n return;\n }\n\n spinner.text = `Validated ${validation.assets.length} asset(s)`;\n spinner.succeed();\n\n // Determine asset name from directory\n const assetName = path.basename(directory);\n const slug = generateSlug(assetName);\n\n if (!validateSlug(slug)) {\n logger.error(`Invalid slug generated: \"${slug}\". Skipping upload.`);\n console.log();\n return;\n }\n\n spinner.start('Uploading...');\n\n try {\n const formData = await buildFormData(validation, {\n studioId: state.studioId,\n gameId: state.gameId,\n name: assetName,\n slug,\n batchMode: validation.isBatchMode,\n });\n\n const result = await uploadSpineAsset(formData);\n\n if (result.success) {\n spinner.succeed('Upload complete!');\n\n if (result.assets && result.assets.length > 1) {\n console.log(` Uploaded ${result.assets.length} assets (batch mode)`);\n for (const asset of result.assets) {\n console.log(` ${asset.name} (${asset.slug}) - ${asset.status}`);\n }\n } else if (result.asset) {\n console.log(` ${result.asset.name} (${result.asset.slug}) - ${result.asset.status}`);\n }\n console.log();\n } else {\n spinner.fail('Upload failed');\n logger.error(result.error || 'Unknown error');\n console.log();\n }\n } catch (error) {\n spinner.fail('Upload failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n console.log();\n }\n}\n\nasync function buildFormData(\n validation: BatchValidation,\n options: {\n studioId: string;\n gameId?: string;\n name: string;\n slug: string;\n batchMode: boolean;\n }\n): Promise<FormData> {\n const formData = new FormData();\n\n // Add metadata\n formData.append('studioId', options.studioId);\n if (options.gameId) formData.append('gameId', options.gameId);\n formData.append('name', options.name);\n formData.append('slug', options.slug);\n if (options.batchMode) formData.append('batchMode', 'true');\n\n // Collect all unique files\n const filesAdded = new Set<string>();\n\n // Add skeleton files\n for (const asset of validation.assets) {\n const filePath = asset.skeleton.path;\n if (!filesAdded.has(filePath)) {\n const buffer = fs.readFileSync(filePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(filePath));\n filesAdded.add(filePath);\n }\n }\n\n // Add shared atlas if exists\n if (validation.sharedAtlas && !filesAdded.has(validation.sharedAtlas)) {\n const buffer = fs.readFileSync(validation.sharedAtlas);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(validation.sharedAtlas));\n filesAdded.add(validation.sharedAtlas);\n }\n\n // Add shared textures\n for (const texturePath of validation.sharedTextures) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n\n // Add individual asset files (atlas and textures for non-batch mode)\n for (const asset of validation.assets) {\n if (asset.atlasPath && !filesAdded.has(asset.atlasPath)) {\n const buffer = fs.readFileSync(asset.atlasPath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(asset.atlasPath));\n filesAdded.add(asset.atlasPath);\n }\n\n for (const texturePath of asset.texturePaths) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n }\n\n return formData;\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execFile } from 'node:child_process';\nimport ora from 'ora';\nimport { credentials, config } from '../lib/config.js';\nimport { getCurrentUser } from '../lib/auth.js';\nimport { getStudios, getGames } from '../lib/api.js';\nimport { SPINE_EXPORT_PRESET } from '../lib/spine-validator.js';\nimport { logger } from '../utils/logger.js';\n\nconst PLAYTAGON_DIR = path.join(os.homedir(), '.playtagon');\n\nexport const setupCommand = new Command('setup')\n .description('Set up integrations')\n .addCommand(spineIntegrationCommand());\n\nfunction spineIntegrationCommand(): Command {\n return new Command('spine-integration')\n .description('Set up automatic Spine Editor to Platform upload')\n .option('-s, --studio <studio>', 'Default studio for uploads')\n .option('-g, --game <game>', 'Default game for uploads')\n .option('--force', 'Overwrite existing setup files')\n .action(async (options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const spinner = ora('Checking authentication...').start();\n\n // Verify auth and get user info\n const user = await getCurrentUser();\n if (!user) {\n spinner.fail('Session expired');\n logger.info(`Run ${logger.command('playtagon login')} to re-authenticate.`);\n process.exit(1);\n }\n\n spinner.succeed(`Logged in as ${user.email}`);\n\n // Get studios\n let studioSlug = options.studio;\n if (!studioSlug) {\n spinner.start('Fetching studios...');\n const studios = await getStudios();\n spinner.stop();\n\n if (studios.length === 0) {\n logger.error('No studios found. Join or create a studio first.');\n process.exit(1);\n }\n\n if (studios.length === 1) {\n studioSlug = studios[0].slug;\n logger.info(`Using studio: ${logger.value(studios[0].name)}`);\n } else {\n logger.header('Available Studios');\n studios.forEach((s, i) => {\n console.log(` ${i + 1}. ${s.name} (${logger.value(s.slug)})`);\n });\n console.log();\n logger.info(`Specify studio with ${logger.command('--studio <slug>')}`);\n logger.info(`Example: ${logger.command(`playtagon setup spine-integration --studio ${studios[0].slug}`)}`);\n process.exit(1);\n }\n }\n\n // Create .playtagon directory\n spinner.start('Creating setup files...');\n\n if (!fs.existsSync(PLAYTAGON_DIR)) {\n fs.mkdirSync(PLAYTAGON_DIR, { recursive: true, mode: 0o700 });\n }\n\n // Generate post-export scripts\n const scriptPaths = generatePostExportScripts(studioSlug, options.game, options.force);\n\n // Generate Spine export preset with postScript\n const presetPath = generateExportPreset(scriptPaths.sh, options.force);\n\n spinner.succeed('Setup complete!');\n\n // Print instructions\n console.log();\n logger.header('Setup Complete');\n console.log();\n logger.info('Files created:');\n console.log(` ${logger.file(scriptPaths.sh)}`);\n if (process.platform === 'win32') {\n console.log(` ${logger.file(scriptPaths.bat)}`);\n }\n console.log(` ${logger.file(presetPath)}`);\n\n console.log();\n logger.header('Next Steps');\n console.log();\n console.log(' 1. Open Spine Editor');\n console.log(' 2. Go to File → Export...');\n console.log(' 3. Click the gear icon (⚙) next to the preset dropdown');\n console.log(' 4. Click \"Import\" and select the preset file from the folder that just opened');\n console.log(' 5. The preset \"Upload to Playtagon\" will be available');\n console.log();\n console.log(' Now when you export with this preset, files automatically');\n console.log(' upload to Playtagon Platform!');\n console.log();\n\n // Open the folder in Finder/Explorer so user can find the preset file\n openFolder(PLAYTAGON_DIR);\n\n // Verify game if provided\n let gameSlug = options.game;\n if (gameSlug) {\n spinner.start('Verifying game...');\n const studios = await getStudios();\n const studio = studios.find((s) => s.slug.toLowerCase() === studioSlug.toLowerCase());\n if (studio) {\n const games = await getGames(studio.id);\n const game = games.find(\n (g) => g.slug.toLowerCase() === gameSlug.toLowerCase() ||\n g.id === gameSlug ||\n g.name.toLowerCase() === gameSlug.toLowerCase()\n );\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameSlug}\" not found in studio \"${studioSlug}\".`);\n if (games.length > 0) {\n console.log();\n logger.info('Available games:');\n games.forEach((g) => {\n console.log(` ${logger.value(g.slug)} - ${g.name}`);\n });\n }\n process.exit(1);\n }\n gameSlug = game.slug; // Normalize to slug\n spinner.succeed(`Game: ${game.name}`);\n }\n }\n\n // Save defaults to config\n config.defaultStudio = studioSlug;\n if (gameSlug) {\n config.defaultGame = gameSlug;\n }\n\n if (gameSlug) {\n logger.info(`Uploads will go to: ${logger.value(studioSlug)} / ${logger.value(gameSlug)}`);\n } else {\n logger.info(`Uploads will go to studio: ${logger.value(studioSlug)}`);\n logger.info(`Add ${logger.command('--game <slug>')} to also set default game.`);\n }\n\n console.log();\n logger.info('Defaults saved. You can change them later with:');\n logger.info(` ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n });\n}\n\nfunction generatePostExportScripts(\n studioSlug: string,\n gameSlug?: string,\n force = false\n): { sh: string; bat: string } {\n const shPath = path.join(PLAYTAGON_DIR, 'upload.sh');\n const batPath = path.join(PLAYTAGON_DIR, 'upload.bat');\n\n // Build upload command\n let uploadCmd = `playtagon spine upload \"$1\" --studio ${studioSlug}`;\n if (gameSlug) {\n uploadCmd += ` --game ${gameSlug}`;\n }\n\n // Shell script (Mac/Linux)\n const shScript = `#!/bin/bash\n# Playtagon Spine Upload Script\n# Auto-generated by: playtagon setup spine-integration\n#\n# This script is called by Spine Editor after export.\n# It uploads the exported files to Playtagon Platform.\n\nset -e\n\nEXPORT_DIR=\"$1\"\n\nif [ -z \"$EXPORT_DIR\" ]; then\n echo \"Error: No export directory provided\"\n exit 1\nfi\n\necho \"Uploading to Playtagon...\"\n${uploadCmd}\n\n# macOS notification (optional)\nif command -v osascript &> /dev/null; then\n osascript -e 'display notification \"Spine export uploaded successfully\" with title \"Playtagon\"' 2>/dev/null || true\nfi\n\n# Linux notification (optional)\nif command -v notify-send &> /dev/null; then\n notify-send \"Playtagon\" \"Spine export uploaded successfully\" 2>/dev/null || true\nfi\n\necho \"Upload complete!\"\n`;\n\n // Batch script (Windows)\n let uploadCmdWin = `playtagon spine upload \"%~1\" --studio ${studioSlug}`;\n if (gameSlug) {\n uploadCmdWin += ` --game ${gameSlug}`;\n }\n\n const batScript = `@echo off\nREM Playtagon Spine Upload Script\nREM Auto-generated by: playtagon setup spine-integration\nREM\nREM This script is called by Spine Editor after export.\nREM It uploads the exported files to Playtagon Platform.\n\nset EXPORT_DIR=%~1\nset LOG_FILE=%USERPROFILE%\\\\.playtagon\\\\upload.log\n\nREM Log script execution\necho [%date% %time%] Script started with directory: %EXPORT_DIR% >> \"%LOG_FILE%\"\n\nif \"%EXPORT_DIR%\"==\"\" (\n echo Error: No export directory provided\n echo [%date% %time%] ERROR: No export directory provided >> \"%LOG_FILE%\"\n exit /b 1\n)\n\necho Uploading to Playtagon...\necho [%date% %time%] Running upload command... >> \"%LOG_FILE%\"\n${uploadCmdWin} >> \"%LOG_FILE%\" 2>&1\n\nif %ERRORLEVEL% EQU 0 (\n echo [%date% %time%] Upload successful >> \"%LOG_FILE%\"\n REM Windows notification (PowerShell)\n powershell -Command \"& {Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('Spine export uploaded successfully', 'Playtagon', 'OK', 'Information')}\" 2>nul\n echo Upload complete!\n) else (\n echo [%date% %time%] Upload failed with error code %ERRORLEVEL% >> \"%LOG_FILE%\"\n powershell -Command \"& {Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('Upload failed! Check log file', 'Playtagon Error', 'OK', 'Error')}\" 2>nul\n)\n`;\n\n // Write scripts\n if (!fs.existsSync(shPath) || force) {\n fs.writeFileSync(shPath, shScript, { mode: 0o755 });\n } else {\n logger.warn(`${shPath} already exists. Use --force to overwrite.`);\n }\n\n if (!fs.existsSync(batPath) || force) {\n fs.writeFileSync(batPath, batScript);\n }\n\n return { sh: shPath, bat: batPath };\n}\n\nfunction generateExportPreset(scriptPath: string, force = false): string {\n const presetPath = path.join(PLAYTAGON_DIR, 'playtagon-spine-preset.export.json');\n\n // Extend the base preset with postScript\n const preset = {\n ...SPINE_EXPORT_PRESET,\n name: 'Upload to Playtagon',\n postScript: process.platform === 'win32'\n ? `\"${scriptPath.replace('.sh', '.bat')}\" \"{output}\"`\n : `\"${scriptPath}\" \"{output}\"`,\n };\n\n if (!fs.existsSync(presetPath) || force) {\n fs.writeFileSync(presetPath, JSON.stringify(preset, null, 2));\n } else {\n logger.warn(`${presetPath} already exists. Use --force to overwrite.`);\n }\n\n return presetPath;\n}\n\nfunction openFolder(folderPath: string): void {\n // Open folder in system file manager using execFile (safe from injection)\n const platform = process.platform;\n let cmd: string;\n let args: string[];\n\n if (platform === 'darwin') {\n cmd = 'open';\n args = [folderPath];\n } else if (platform === 'win32') {\n cmd = 'explorer';\n args = [folderPath];\n } else {\n // Linux - try xdg-open\n cmd = 'xdg-open';\n args = [folderPath];\n }\n\n execFile(cmd, args, (error) => {\n if (error) {\n // Silently fail - user can still navigate manually\n logger.debug(`Could not open folder: ${error.message}`);\n }\n });\n}\n","import { Command } from 'commander';\nimport { config, credentials } from '../lib/config.js';\nimport { getStudios, getGames } from '../lib/api.js';\nimport { logger } from '../utils/logger.js';\nimport ora from 'ora';\n\nexport const configCommand = new Command('config')\n .description('View or set CLI configuration')\n .option('-s, --studio <studio>', 'Set default studio')\n .option('-g, --game <game>', 'Set default game')\n .option('--clear', 'Clear all default settings')\n .action(async (options) => {\n // If --clear flag is set, clear all defaults\n if (options.clear) {\n config.defaultStudio = undefined;\n config.defaultGame = undefined;\n logger.success('Default settings cleared.');\n return;\n }\n\n // If setting studio\n if (options.studio) {\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const spinner = ora('Verifying studio...').start();\n const studios = await getStudios();\n const studio = studios.find(\n (s) => s.slug === options.studio || s.id === options.studio || s.name === options.studio\n );\n\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${options.studio}\" not found or you don't have access.`);\n console.log();\n logger.info('Available studios:');\n studios.forEach((s) => {\n console.log(` ${logger.value(s.slug)} - ${s.name}`);\n });\n process.exit(1);\n }\n\n spinner.succeed(`Default studio set: ${studio.name} (${studio.slug})`);\n config.defaultStudio = studio.slug;\n }\n\n // If setting game\n if (options.game) {\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const studioSlug = options.studio || config.defaultStudio;\n if (!studioSlug) {\n logger.error('Studio is required to set default game.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default studio first.`);\n process.exit(1);\n }\n\n const spinner = ora('Verifying game...').start();\n const studios = await getStudios();\n const studio = studios.find(\n (s) => s.slug === studioSlug || s.id === studioSlug || s.name === studioSlug\n );\n\n if (!studio) {\n spinner.fail('Studio not found');\n process.exit(1);\n }\n\n const games = await getGames(studio.id);\n const game = games.find(\n (g) => g.slug === options.game || g.id === options.game || g.name === options.game\n );\n\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${options.game}\" not found in studio \"${studio.name}\".`);\n console.log();\n if (games.length > 0) {\n logger.info('Available games:');\n games.forEach((g) => {\n console.log(` ${logger.value(g.slug)} - ${g.name}`);\n });\n } else {\n logger.info('No games in this studio yet.');\n }\n process.exit(1);\n }\n\n spinner.succeed(`Default game set: ${game.name} (${game.slug})`);\n config.defaultGame = game.slug;\n }\n\n // If no options, show current config\n if (!options.studio && !options.game && !options.clear) {\n logger.header('Current Configuration');\n console.log();\n logger.item('Config file', config.path);\n console.log();\n\n const currentStudio = config.defaultStudio;\n const currentGame = config.defaultGame;\n\n if (currentStudio || currentGame) {\n logger.header('Default Upload Target');\n if (currentStudio) {\n logger.item('Studio', currentStudio);\n }\n if (currentGame) {\n logger.item('Game', currentGame);\n }\n console.log();\n logger.info('These defaults are used when --studio/--game are not provided.');\n console.log();\n logger.info(`To change: ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n logger.info(`To clear: ${logger.command('playtagon config --clear')}`);\n } else {\n logger.info('No default studio or game set.');\n console.log();\n logger.info(`Set defaults: ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n logger.info(`Or run setup: ${logger.command('playtagon setup spine-integration')}`);\n }\n }\n });\n"],"mappings":"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","names":["Command","resolve","resolve","Command","Command","Command","ora","Command","ora","Command","Command","path","ora","fs","path","Command","ora","Command","fs","path","ora","Command","ora","Command","Command","Command","fs","path","ora","Command","ora","pascalCase","Command","fs","path","ora","Command","ora","buildFormData","Command","Command","fs","path","ora","Command","ora","Command","ora","Command","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/utils/logger.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/commands/spine/index.ts","../src/commands/spine/validate.ts","../src/lib/spine-validator.ts","../src/utils/files.ts","../src/commands/spine/upload.ts","../src/lib/api.ts","../src/commands/spine/preset.ts","../src/commands/spine/sync.ts","../src/lib/codegen.ts","../src/commands/spine/watch.ts","../src/commands/setup.ts","../src/commands/config.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { whoamiCommand } from './commands/whoami.js';\nimport { spineCommand } from './commands/spine/index.js';\nimport { setupCommand } from './commands/setup.js';\nimport { configCommand } from './commands/config.js';\n\nconst program = new Command();\n\nprogram\n .name('playtagon')\n .description('Playtagon CLI - Upload and manage game assets')\n .version('0.4.6');\n\n// Add commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(spineCommand);\nprogram.addCommand(setupCommand);\nprogram.addCommand(configCommand);\n\n// Parse arguments\nprogram.parse();\n","import { Command } from 'commander';\nimport * as readline from 'node:readline';\nimport open from 'open';\nimport ora from 'ora';\nimport { loginWithEmail, loginWithBrowser, getAuthUrl, getCurrentUser } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with Playtagon')\n .option('-e, --email <email>', 'Login with email/password instead of browser')\n .option('--no-browser', 'Use email/password login instead of browser')\n .action(async (options) => {\n // Check if already logged in\n if (credentials.isLoggedIn()) {\n const user = await getCurrentUser();\n if (user) {\n logger.info(`Already logged in as ${logger.value(user.email)}`);\n logger.info(`Run ${logger.command('playtagon logout')} to sign out.`);\n return;\n }\n }\n\n if (options.email) {\n await emailLogin(options.email);\n } else if (options.browser === false) {\n await promptEmailLogin();\n } else {\n // Default: browser-based login (like npm, gh, vercel)\n await browserLogin();\n }\n });\n\nasync function promptEmailLogin(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const question = (prompt: string): Promise<string> =>\n new Promise((resolve) => {\n rl.question(prompt, resolve);\n });\n\n try {\n const email = await question('Email: ');\n const password = await questionHidden('Password: ', rl);\n\n const spinner = ora('Logging in...').start();\n\n try {\n await loginWithEmail(email, password);\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n logger.header('Account');\n logger.item('Email', user.email);\n if (user.studios.length > 0) {\n logger.item(\n 'Studios',\n user.studios.map((s) => s.name).join(', ')\n );\n }\n }\n } catch (error) {\n spinner.fail('Login failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n } finally {\n rl.close();\n }\n}\n\nasync function emailLogin(email: string): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const password = await questionHidden('Password: ', rl);\n\n const spinner = ora('Logging in...').start();\n\n try {\n await loginWithEmail(email, password);\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n logger.header('Account');\n logger.item('Email', user.email);\n }\n } catch (error) {\n spinner.fail('Login failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n } finally {\n rl.close();\n }\n}\n\nasync function browserLogin(): Promise<void> {\n const authUrl = getAuthUrl();\n\n console.log();\n logger.info('Opening browser to log in...');\n logger.info('');\n logger.info(`If browser doesn't open, visit:`);\n logger.info(` ${logger.link(authUrl)}`);\n console.log();\n\n // Open browser\n try {\n await open(authUrl);\n } catch {\n // Browser failed to open, user can use the URL manually\n }\n\n const spinner = ora('Waiting for authentication...').start();\n\n // Start local server and wait for callback\n const result = await loginWithBrowser();\n\n if (result.success) {\n spinner.succeed('Logged in successfully!');\n\n const user = await getCurrentUser();\n if (user) {\n console.log();\n logger.header('Account');\n logger.item('Email', user.email);\n if (user.studios.length > 0) {\n logger.item(\n 'Studios',\n user.studios.map((s) => s.name).join(', ')\n );\n }\n }\n } else {\n spinner.fail('Login failed');\n logger.error(result.error || 'Unknown error');\n console.log();\n logger.info('You can also try email/password login:');\n logger.info(` ${logger.command('playtagon login --no-browser')}`);\n process.exit(1);\n }\n}\n\n// Hidden password input\nfunction questionHidden(\n prompt: string,\n rl: readline.Interface\n): Promise<string> {\n return new Promise((resolve) => {\n const stdin = process.stdin;\n const stdout = process.stdout;\n\n stdout.write(prompt);\n\n const wasRaw = stdin.isRaw;\n\n if (stdin.isTTY) {\n stdin.setRawMode(true);\n }\n\n let password = '';\n\n const onData = (char: Buffer) => {\n const c = char.toString('utf8');\n\n switch (c) {\n case '\\n':\n case '\\r':\n case '\\u0004':\n // Enter or Ctrl+D\n if (stdin.isTTY) {\n stdin.setRawMode(wasRaw ?? false);\n }\n stdin.removeListener('data', onData);\n stdout.write('\\n');\n resolve(password);\n break;\n case '\\u0003':\n // Ctrl+C\n process.exit(1);\n break;\n case '\\u007F':\n // Backspace\n password = password.slice(0, -1);\n break;\n default:\n password += c;\n break;\n }\n };\n\n stdin.on('data', onData);\n });\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\nimport * as http from 'node:http';\nimport * as crypto from 'node:crypto';\nimport { config, credentials } from './config.js';\nimport { logger } from '../utils/logger.js';\n\nlet supabaseClient: SupabaseClient | null = null;\n\n// PKCE helpers\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\nfunction sha256(buffer: string): Buffer {\n return crypto.createHash('sha256').update(buffer).digest();\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32));\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return base64URLEncode(sha256(verifier));\n}\n\nexport function getSupabaseClient(): SupabaseClient {\n if (!supabaseClient) {\n supabaseClient = createClient(config.supabaseUrl, config.supabaseAnonKey, {\n auth: {\n persistSession: false,\n autoRefreshToken: false,\n },\n });\n }\n return supabaseClient;\n}\n\nexport async function getAuthenticatedClient(): Promise<SupabaseClient> {\n const client = getSupabaseClient();\n\n if (!credentials.isLoggedIn()) {\n throw new Error('Not logged in. Run `playtagon login` first.');\n }\n\n // Check if token is expired and needs refresh\n if (credentials.isExpired() && credentials.refreshToken) {\n logger.debug('Token expired, refreshing...');\n await refreshSession();\n }\n\n // Set the session\n const accessToken = credentials.accessToken;\n if (!accessToken) {\n throw new Error('No access token found. Run `playtagon login` first.');\n }\n\n await client.auth.setSession({\n access_token: accessToken,\n refresh_token: credentials.refreshToken || '',\n });\n\n return client;\n}\n\nexport async function refreshSession(): Promise<void> {\n const client = getSupabaseClient();\n const refreshToken = credentials.refreshToken;\n\n if (!refreshToken) {\n throw new Error('No refresh token found. Run `playtagon login` first.');\n }\n\n const { data, error } = await client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n credentials.clear();\n throw new Error(`Failed to refresh session: ${error.message}`);\n }\n\n if (data.session) {\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n });\n }\n}\n\nexport async function loginWithEmail(\n email: string,\n password: string\n): Promise<void> {\n const client = getSupabaseClient();\n\n const { data, error } = await client.auth.signInWithPassword({\n email,\n password,\n });\n\n if (error) {\n throw new Error(`Login failed: ${error.message}`);\n }\n\n if (!data.session) {\n throw new Error('Login failed: No session returned');\n }\n\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n userId: data.user?.id,\n email: data.user?.email,\n });\n}\n\nexport interface OAuthLoginResult {\n success: boolean;\n error?: string;\n}\n\nexport async function loginWithBrowser(): Promise<OAuthLoginResult> {\n return new Promise((resolve) => {\n const port = 19419;\n const redirectUri = `http://localhost:${port}/callback`;\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n\n // Build the Supabase auth URL with PKCE\n const authUrl = new URL(`${config.supabaseUrl}/auth/v1/authorize`);\n authUrl.searchParams.set('provider', 'google'); // or use generic PKCE\n authUrl.searchParams.set('redirect_to', redirectUri);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n\n // For email login via browser, we use the Supabase hosted UI\n const loginUrl = new URL(`${config.supabaseUrl}/auth/v1/authorize`);\n // Use the platform's auth page instead\n const platformAuthUrl = `https://playtagon.com/cli-auth?redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${codeChallenge}`;\n\n let server: http.Server | null = null;\n let timeoutId: NodeJS.Timeout | null = null;\n\n const cleanup = () => {\n if (timeoutId) clearTimeout(timeoutId);\n if (server) {\n server.close();\n server = null;\n }\n };\n\n // Create local server to receive the callback\n server = http.createServer(async (req, res) => {\n const url = new URL(req.url || '/', `http://localhost:${port}`);\n\n if (url.pathname === '/callback') {\n const error = url.searchParams.get('error');\n const errorDescription = url.searchParams.get('error_description');\n\n if (error) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(errorDescription || error));\n cleanup();\n resolve({ success: false, error: errorDescription || error });\n return;\n }\n\n // Handle tokens directly (from platform CLI auth page)\n const accessToken = url.searchParams.get('access_token');\n const refreshToken = url.searchParams.get('refresh_token');\n\n if (accessToken) {\n credentials.save({\n accessToken,\n refreshToken: refreshToken || undefined,\n expiresAt: Date.now() + 3600 * 1000,\n });\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml(''));\n cleanup();\n resolve({ success: true });\n return;\n }\n\n // Handle OAuth code exchange flow (fallback)\n const code = url.searchParams.get('code');\n if (code) {\n try {\n // Exchange code for session\n const client = getSupabaseClient();\n const { data, error: exchangeError } = await client.auth.exchangeCodeForSession(code);\n\n if (exchangeError || !data.session) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(exchangeError?.message || 'Failed to exchange code'));\n cleanup();\n resolve({ success: false, error: exchangeError?.message || 'Failed to exchange code' });\n return;\n }\n\n // Save credentials\n credentials.save({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at\n ? data.session.expires_at * 1000\n : Date.now() + 3600 * 1000,\n userId: data.user?.id,\n email: data.user?.email,\n });\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getSuccessHtml(data.user?.email || ''));\n cleanup();\n resolve({ success: true });\n } catch (err) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml(err instanceof Error ? err.message : 'Unknown error'));\n cleanup();\n resolve({ success: false, error: err instanceof Error ? err.message : 'Unknown error' });\n }\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getErrorHtml('No authorization token received'));\n cleanup();\n resolve({ success: false, error: 'No authorization token received' });\n } else {\n res.writeHead(404);\n res.end('Not found');\n }\n });\n\n server.listen(port, () => {\n logger.info(`Waiting for authentication on port ${port}...`);\n });\n\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n cleanup();\n resolve({ success: false, error: `Port ${port} is already in use. Please close any applications using it.` });\n } else {\n cleanup();\n resolve({ success: false, error: err.message });\n }\n });\n\n // Timeout after 5 minutes\n timeoutId = setTimeout(() => {\n cleanup();\n resolve({ success: false, error: 'Authentication timed out. Please try again.' });\n }, 5 * 60 * 1000);\n });\n}\n\nexport function getAuthUrl(): string {\n const port = 19419;\n const redirectUri = `http://localhost:${port}/callback`;\n\n // Use platform's auth page which handles the Supabase flow\n return `https://playtagon.com/cli-auth?redirect_uri=${encodeURIComponent(redirectUri)}`;\n}\n\nfunction getSuccessHtml(email: string): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Login Successful - Playtagon CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n color: #fff;\n }\n .container {\n text-align: center;\n padding: 40px;\n background: rgba(255,255,255,0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n }\n .checkmark {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 { margin: 0 0 10px; font-size: 24px; }\n p { margin: 0; opacity: 0.8; }\n .email { font-weight: bold; color: #4ade80; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"checkmark\">✓</div>\n <h1>Login Successful!</h1>\n <p>You're now logged in${email ? ` as <span class=\"email\">${email}</span>` : ''}.</p>\n <p style=\"margin-top: 20px; opacity: 0.6;\">You can close this window and return to your terminal.</p>\n </div>\n</body>\n</html>`;\n}\n\nfunction getErrorHtml(error: string): string {\n return `\n<!DOCTYPE html>\n<html>\n<head>\n <title>Login Failed - Playtagon CLI</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n margin: 0;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n color: #fff;\n }\n .container {\n text-align: center;\n padding: 40px;\n background: rgba(255,255,255,0.1);\n border-radius: 16px;\n backdrop-filter: blur(10px);\n }\n .icon {\n font-size: 64px;\n margin-bottom: 20px;\n }\n h1 { margin: 0 0 10px; font-size: 24px; color: #f87171; }\n p { margin: 0; opacity: 0.8; }\n .error { color: #fca5a5; font-family: monospace; }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"icon\">✗</div>\n <h1>Login Failed</h1>\n <p class=\"error\">${error}</p>\n <p style=\"margin-top: 20px; opacity: 0.6;\">Please return to your terminal and try again.</p>\n </div>\n</body>\n</html>`;\n}\n\nexport function logout(): void {\n credentials.clear();\n}\n\nexport async function getCurrentUser(): Promise<{\n id: string;\n email: string;\n studios: Array<{ id: string; name: string; slug: string }>;\n} | null> {\n try {\n const client = await getAuthenticatedClient();\n\n const {\n data: { user },\n error,\n } = await client.auth.getUser();\n\n if (error || !user) {\n return null;\n }\n\n // Fetch user's studios\n const { data: memberships } = await client.from('studio_members').select(`\n studio:studios (\n id,\n name,\n slug\n )\n `)\n .eq('user_id', user.id);\n\n const studios =\n memberships\n ?.map((m) => m.studio as unknown as { id: string; name: string; slug: string })\n .filter(Boolean) || [];\n\n return {\n id: user.id,\n email: user.email || '',\n studios,\n };\n } catch {\n return null;\n }\n}\n\nexport function getAccessToken(): string | undefined {\n return credentials.accessToken;\n}\n","import Conf from 'conf';\n\nexport interface PlaytagonConfig {\n supabaseUrl?: string;\n supabaseAnonKey?: string;\n defaultStudio?: string;\n defaultGame?: string;\n}\n\nexport interface PlaytagonCredentials {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n userId?: string;\n email?: string;\n}\n\n// Default Supabase config - can be overridden via environment variables\nconst DEFAULT_SUPABASE_URL = process.env.PLAYTAGON_SUPABASE_URL || 'https://pthbeazcwnhjljwksuae.supabase.co';\nconst DEFAULT_SUPABASE_ANON_KEY = process.env.PLAYTAGON_SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB0aGJlYXpjd25oamxqd2tzdWFlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjcxMjIzNDEsImV4cCI6MjA4MjY5ODM0MX0.ls0hO-UigKnl9cj2NEkxjQL4TnijkIG50iImqZIThVc';\n\n// Config store for settings\nconst configStore = new Conf<PlaytagonConfig>({\n projectName: 'playtagon',\n configFileMode: 0o600,\n defaults: {\n supabaseUrl: DEFAULT_SUPABASE_URL,\n supabaseAnonKey: DEFAULT_SUPABASE_ANON_KEY,\n },\n});\n\n// Separate store for credentials (more sensitive)\nconst credentialsStore = new Conf<PlaytagonCredentials>({\n projectName: 'playtagon',\n configName: 'credentials',\n configFileMode: 0o600,\n});\n\nexport const config = {\n get supabaseUrl(): string {\n return configStore.get('supabaseUrl') || DEFAULT_SUPABASE_URL;\n },\n\n get supabaseAnonKey(): string {\n return configStore.get('supabaseAnonKey') || DEFAULT_SUPABASE_ANON_KEY;\n },\n\n get defaultStudio(): string | undefined {\n return configStore.get('defaultStudio');\n },\n\n set defaultStudio(value: string | undefined) {\n if (value) {\n configStore.set('defaultStudio', value);\n } else {\n configStore.delete('defaultStudio');\n }\n },\n\n get defaultGame(): string | undefined {\n return configStore.get('defaultGame');\n },\n\n set defaultGame(value: string | undefined) {\n if (value) {\n configStore.set('defaultGame', value);\n } else {\n configStore.delete('defaultGame');\n }\n },\n\n // Get full config\n getAll(): PlaytagonConfig {\n return configStore.store;\n },\n\n // Get config file path\n get path(): string {\n return configStore.path;\n },\n};\n\nexport const credentials = {\n get accessToken(): string | undefined {\n return credentialsStore.get('accessToken');\n },\n\n get refreshToken(): string | undefined {\n return credentialsStore.get('refreshToken');\n },\n\n get expiresAt(): number | undefined {\n return credentialsStore.get('expiresAt');\n },\n\n get userId(): string | undefined {\n return credentialsStore.get('userId');\n },\n\n get email(): string | undefined {\n return credentialsStore.get('email');\n },\n\n isLoggedIn(): boolean {\n return !!credentialsStore.get('accessToken');\n },\n\n isExpired(): boolean {\n const expiresAt = credentialsStore.get('expiresAt');\n if (!expiresAt) return true;\n // Consider expired if less than 5 minutes remaining\n return Date.now() > expiresAt - 5 * 60 * 1000;\n },\n\n save(creds: PlaytagonCredentials): void {\n if (creds.accessToken) credentialsStore.set('accessToken', creds.accessToken);\n if (creds.refreshToken) credentialsStore.set('refreshToken', creds.refreshToken);\n if (creds.expiresAt) credentialsStore.set('expiresAt', creds.expiresAt);\n if (creds.userId) credentialsStore.set('userId', creds.userId);\n if (creds.email) credentialsStore.set('email', creds.email);\n },\n\n clear(): void {\n credentialsStore.clear();\n },\n\n // Get credentials file path\n get path(): string {\n return credentialsStore.path;\n },\n};\n","import chalk from 'chalk';\n\nexport const logger = {\n info: (message: string) => {\n console.log(chalk.blue('info'), message);\n },\n\n success: (message: string) => {\n console.log(chalk.green('success'), message);\n },\n\n warn: (message: string) => {\n console.log(chalk.yellow('warn'), message);\n },\n\n error: (message: string) => {\n console.log(chalk.red('error'), message);\n },\n\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(chalk.gray('debug'), message);\n }\n },\n\n // Styled output for specific contexts\n file: (filename: string) => chalk.cyan(filename),\n value: (val: string | number) => chalk.yellow(val),\n command: (cmd: string) => chalk.bold.white(cmd),\n url: (url: string) => chalk.underline.blue(url),\n link: (url: string) => chalk.underline.cyan(url),\n\n // Section headers\n header: (title: string) => {\n console.log();\n console.log(chalk.bold.white(title));\n console.log(chalk.gray('─'.repeat(title.length)));\n },\n\n // List item\n item: (label: string, value: string) => {\n console.log(` ${chalk.gray(label + ':')} ${value}`);\n },\n\n // Validation result formatting\n validationError: (message: string, detail?: string) => {\n console.log(` ${chalk.red('✗')} ${message}`);\n if (detail) {\n console.log(` ${chalk.gray(detail)}`);\n }\n },\n\n validationSuccess: (message: string) => {\n console.log(` ${chalk.green('✓')} ${message}`);\n },\n\n validationWarn: (message: string) => {\n console.log(` ${chalk.yellow('!')} ${message}`);\n },\n};\n","import { Command } from 'commander';\nimport { logout } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Sign out of Playtagon')\n .action(() => {\n if (!credentials.isLoggedIn()) {\n logger.info('Not currently logged in.');\n return;\n }\n\n const email = credentials.email;\n logout();\n\n if (email) {\n logger.success(`Logged out from ${logger.value(email)}`);\n } else {\n logger.success('Logged out successfully');\n }\n });\n","import { Command } from 'commander';\nimport ora from 'ora';\nimport { getCurrentUser } from '../lib/auth.js';\nimport { credentials } from '../lib/config.js';\nimport { logger } from '../utils/logger.js';\n\nexport const whoamiCommand = new Command('whoami')\n .description('Show current logged in user')\n .action(async () => {\n if (!credentials.isLoggedIn()) {\n logger.info('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} to authenticate.`);\n return;\n }\n\n const spinner = ora('Fetching user info...').start();\n\n try {\n const user = await getCurrentUser();\n\n if (!user) {\n spinner.fail('Session expired');\n logger.info(`Run ${logger.command('playtagon login')} to re-authenticate.`);\n return;\n }\n\n spinner.stop();\n\n logger.header('Current User');\n logger.item('ID', user.id);\n logger.item('Email', user.email);\n\n if (user.studios.length > 0) {\n console.log();\n logger.header('Studios');\n for (const studio of user.studios) {\n console.log(` ${studio.name} (${logger.value(studio.slug)})`);\n }\n } else {\n console.log();\n logger.warn('No studios found. Join or create a studio in the platform.');\n }\n } catch (error) {\n spinner.fail('Failed to fetch user info');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport { validateCommand } from './validate.js';\nimport { uploadCommand } from './upload.js';\nimport { presetCommand } from './preset.js';\nimport { syncCommand } from './sync.js';\nimport { watchCommand } from './watch.js';\n\nexport const spineCommand = new Command('spine')\n .description('Manage Spine animation assets')\n .addCommand(validateCommand)\n .addCommand(uploadCommand)\n .addCommand(watchCommand)\n .addCommand(presetCommand)\n .addCommand(syncCommand);\n","import { Command } from 'commander';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { validateDirectory, type BatchValidation } from '../../lib/spine-validator.js';\nimport { formatFileSize } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const validateCommand = new Command('validate')\n .description('Validate Spine files before uploading')\n .argument('<directory>', 'Directory containing Spine files')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .action(async (directory: string, options: { batch?: boolean }) => {\n const absolutePath = path.resolve(directory);\n\n const spinner = ora(`Validating ${logger.file(directory)}...`).start();\n\n try {\n const result = validateDirectory(absolutePath, options.batch);\n spinner.stop();\n\n printValidationResult(result, directory);\n\n if (!result.isValid) {\n process.exit(1);\n }\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n\nfunction printValidationResult(result: BatchValidation, directory: string): void {\n console.log();\n logger.header(`Validation: ${directory}`);\n\n // Summary info\n if (result.isBatchMode) {\n console.log(` Mode: ${logger.value('Batch')} (${result.assets.length} skeletons)`);\n if (result.sharedAtlas) {\n console.log(` Shared Atlas: ${logger.file(path.basename(result.sharedAtlas))}`);\n console.log(` Shared Textures: ${result.sharedTextures.length}`);\n }\n } else if (result.assets.length > 0) {\n console.log(` Mode: ${logger.value('Single')}`);\n }\n\n console.log(` Total Size: ${logger.value(formatFileSize(result.totalSize))}`);\n console.log();\n\n // Print each asset\n for (const asset of result.assets) {\n const statusIcon = asset.isValid ? '✓' : '✗';\n const statusColor = asset.isValid ? 'green' : 'red';\n\n console.log(\n ` ${statusIcon} ${logger.file(asset.skeleton.name)}`\n );\n console.log(` Spine: ${asset.skeleton.spineVersion}`);\n console.log(` Animations: ${asset.skeleton.animations.length}`);\n console.log(` Skins: ${asset.skeleton.skins.length}`);\n\n if (asset.atlasPath) {\n console.log(` Atlas: ${path.basename(asset.atlasPath)}`);\n console.log(` Textures: ${asset.texturePaths.length}`);\n }\n }\n\n console.log();\n\n // Print all issues\n const errors = result.issues.filter((i) => i.type === 'error');\n const warnings = result.issues.filter((i) => i.type === 'warning');\n const infos = result.issues.filter((i) => i.type === 'info');\n\n // Info messages\n for (const info of infos) {\n logger.info(info.message);\n }\n\n // Warnings\n if (warnings.length > 0) {\n console.log();\n for (const warning of warnings) {\n logger.validationWarn(\n warning.file ? `${warning.file}: ${warning.message}` : warning.message\n );\n if ((warning as { detail?: string }).detail) {\n console.log(` ${(warning as { detail: string }).detail}`);\n }\n }\n }\n\n // Errors\n if (errors.length > 0) {\n console.log();\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message,\n (error as { detail?: string }).detail\n );\n }\n }\n\n // Final status\n console.log();\n if (result.isValid) {\n logger.success('Validation passed! Ready for upload.');\n } else {\n logger.error(`Validation failed with ${errors.length} error(s).`);\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport {\n discoverSpineFiles,\n matchSkeletonToAtlas,\n parseAtlasTextures,\n getFileSize,\n getTotalSize,\n formatFileSize,\n type DiscoveredFiles,\n} from '../utils/files.js';\n\n// Validation rules - keep in sync with server and platform\nexport const SPINE_VALIDATION_RULES = {\n supportedVersions: ['4.0', '4.1', '4.2', '4.3'] as const,\n maxTextureSize: 4096, // pixels per dimension\n maxTotalSize: 50 * 1024 * 1024, // 50MB\n maxTextureCount: 8,\n slugPattern: /^[a-z0-9-]+$/,\n animationNamePattern: /^[a-zA-Z0-9_-]+$/,\n} as const;\n\nexport interface ValidationError {\n type: 'error';\n message: string;\n file?: string;\n detail?: string;\n}\n\nexport interface ValidationWarning {\n type: 'warning';\n message: string;\n file?: string;\n detail?: string;\n}\n\nexport interface ValidationInfo {\n type: 'info';\n message: string;\n}\n\nexport type ValidationIssue = ValidationError | ValidationWarning | ValidationInfo;\n\nexport interface SkeletonInfo {\n path: string;\n name: string;\n spineVersion: string;\n animations: string[];\n skins: string[];\n hasEvents: boolean;\n boneCount: number;\n slotCount: number;\n}\n\nexport interface AssetValidation {\n skeleton: SkeletonInfo;\n atlasPath: string | null;\n texturePaths: string[];\n totalSize: number;\n issues: ValidationIssue[];\n isValid: boolean;\n}\n\nexport interface BatchValidation {\n assets: AssetValidation[];\n sharedAtlas: string | null;\n sharedTextures: string[];\n totalSize: number;\n issues: ValidationIssue[];\n isValid: boolean;\n isBatchMode: boolean;\n}\n\nexport function validateDirectory(\n directory: string,\n batchMode = false\n): BatchValidation {\n const discovered = discoverSpineFiles(directory);\n const issues: ValidationIssue[] = [];\n\n // Check if we found any skeleton files\n if (discovered.skeletons.length === 0) {\n issues.push({\n type: 'error',\n message: 'No Spine skeleton files found in this directory',\n detail: 'Expected exported files: skeleton.json + skeleton.atlas + texture.png. Export from Spine Editor first (File → Export → JSON).',\n });\n return {\n assets: [],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize: 0,\n issues,\n isValid: false,\n isBatchMode: false,\n };\n }\n\n // Determine if this is batch mode (multiple skeletons sharing atlas)\n const isBatchMode = batchMode || discovered.skeletons.length > 1;\n\n if (isBatchMode && discovered.skeletons.length > 1) {\n return validateBatch(discovered, issues);\n } else {\n return validateSingle(discovered, issues);\n }\n}\n\nfunction validateSingle(\n discovered: DiscoveredFiles,\n issues: ValidationIssue[]\n): BatchValidation {\n const skeletonPath = discovered.skeletons[0];\n const skeleton = parseSkeletonFile(skeletonPath);\n\n if (!skeleton) {\n issues.push({\n type: 'error',\n message: 'Failed to parse skeleton file',\n file: path.basename(skeletonPath),\n });\n return {\n assets: [],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize: 0,\n issues,\n isValid: false,\n isBatchMode: false,\n };\n }\n\n // Validate spine version\n const versionIssues = validateSpineVersion(skeleton);\n issues.push(...versionIssues);\n\n // Match atlas\n const atlasPath = matchSkeletonToAtlas(skeletonPath, discovered.atlases);\n if (!atlasPath) {\n if (discovered.atlases.length === 0) {\n issues.push({\n type: 'error',\n message: 'No atlas file found',\n detail: 'Expected .atlas file',\n });\n } else {\n issues.push({\n type: 'warning',\n message: 'Could not match skeleton to atlas',\n detail: `Found atlases: ${discovered.atlases.map((a) => path.basename(a)).join(', ')}`,\n });\n }\n }\n\n // Get textures from atlas\n let texturePaths: string[] = [];\n if (atlasPath) {\n texturePaths = parseAtlasTextures(atlasPath);\n const textureIssues = validateTextures(texturePaths);\n issues.push(...textureIssues);\n }\n\n // Check for orphan textures\n const orphanTextures = discovered.textures.filter(\n (t) => !texturePaths.includes(t)\n );\n if (orphanTextures.length > 0) {\n issues.push({\n type: 'warning',\n message: `${orphanTextures.length} texture(s) not referenced in atlas`,\n detail: orphanTextures.map((t) => path.basename(t)).join(', '),\n });\n }\n\n // Calculate total size\n const allFiles = [skeletonPath, atlasPath, ...texturePaths].filter(\n Boolean\n ) as string[];\n const totalSize = getTotalSize(allFiles);\n\n // Validate total size\n if (totalSize > SPINE_VALIDATION_RULES.maxTotalSize) {\n issues.push({\n type: 'error',\n message: `Total size ${formatFileSize(totalSize)} exceeds ${formatFileSize(SPINE_VALIDATION_RULES.maxTotalSize)} limit`,\n });\n }\n\n // Validate animation names\n const animationIssues = validateAnimationNames(skeleton.animations);\n issues.push(...animationIssues);\n\n const hasErrors = issues.some((i) => i.type === 'error');\n\n const asset: AssetValidation = {\n skeleton,\n atlasPath,\n texturePaths,\n totalSize,\n issues: issues.filter(\n (i) =>\n (i as ValidationError | ValidationWarning).file === undefined ||\n (i as ValidationError | ValidationWarning).file === path.basename(skeletonPath)\n ),\n isValid: !hasErrors,\n };\n\n return {\n assets: [asset],\n sharedAtlas: null,\n sharedTextures: [],\n totalSize,\n issues,\n isValid: !hasErrors,\n isBatchMode: false,\n };\n}\n\nfunction validateBatch(\n discovered: DiscoveredFiles,\n issues: ValidationIssue[]\n): BatchValidation {\n const assets: AssetValidation[] = [];\n\n // In batch mode, we expect a shared atlas\n let sharedAtlas: string | null = null;\n let sharedTextures: string[] = [];\n\n if (discovered.atlases.length === 1) {\n sharedAtlas = discovered.atlases[0];\n sharedTextures = parseAtlasTextures(sharedAtlas);\n\n issues.push({\n type: 'info',\n message: `Batch mode: ${discovered.skeletons.length} skeletons sharing 1 atlas`,\n });\n } else if (discovered.atlases.length === 0) {\n issues.push({\n type: 'error',\n message: 'No atlas file found for batch upload',\n });\n } else {\n issues.push({\n type: 'warning',\n message: `Multiple atlases found (${discovered.atlases.length}). Batch mode works best with shared atlas.`,\n });\n }\n\n // Validate each skeleton\n for (const skeletonPath of discovered.skeletons) {\n const skeleton = parseSkeletonFile(skeletonPath);\n\n if (!skeleton) {\n issues.push({\n type: 'error',\n message: 'Failed to parse skeleton file',\n file: path.basename(skeletonPath),\n });\n continue;\n }\n\n // Validate spine version\n const versionIssues = validateSpineVersion(skeleton);\n issues.push(...versionIssues);\n\n // Validate animation names\n const animationIssues = validateAnimationNames(skeleton.animations);\n issues.push(...animationIssues);\n\n // Each skeleton uses the shared atlas\n const atlasPath = sharedAtlas || matchSkeletonToAtlas(skeletonPath, discovered.atlases);\n const texturePaths = atlasPath ? parseAtlasTextures(atlasPath) : [];\n\n // Calculate size for this asset (skeleton only, atlas counted once at the end)\n const skeletonSize = getFileSize(skeletonPath);\n\n assets.push({\n skeleton,\n atlasPath,\n texturePaths,\n totalSize: skeletonSize,\n issues: [],\n isValid: true,\n });\n }\n\n // Validate shared textures\n if (sharedTextures.length > 0) {\n const textureIssues = validateTextures(sharedTextures);\n issues.push(...textureIssues);\n }\n\n // Calculate total size (atlas + textures counted once)\n const skeletonSizes = assets.reduce((sum, a) => sum + a.totalSize, 0);\n const atlasSize = sharedAtlas ? getFileSize(sharedAtlas) : 0;\n const textureSize = getTotalSize(sharedTextures);\n const totalSize = skeletonSizes + atlasSize + textureSize;\n\n // Validate total size\n if (totalSize > SPINE_VALIDATION_RULES.maxTotalSize) {\n issues.push({\n type: 'error',\n message: `Total batch size ${formatFileSize(totalSize)} exceeds ${formatFileSize(SPINE_VALIDATION_RULES.maxTotalSize)} limit`,\n });\n }\n\n const hasErrors = issues.some((i) => i.type === 'error');\n\n return {\n assets,\n sharedAtlas,\n sharedTextures,\n totalSize,\n issues,\n isValid: !hasErrors,\n isBatchMode: true,\n };\n}\n\nfunction parseSkeletonFile(filePath: string): SkeletonInfo | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const json = JSON.parse(content);\n\n if (!json.skeleton?.spine) {\n return null;\n }\n\n const name = path.basename(filePath, path.extname(filePath));\n const spineVersion = json.skeleton.spine;\n const animations = json.animations ? Object.keys(json.animations) : [];\n const skins = json.skins\n ? Array.isArray(json.skins)\n ? json.skins.map((s: { name?: string }) => s.name || 'default')\n : Object.keys(json.skins)\n : ['default'];\n const hasEvents = !!json.events && Object.keys(json.events).length > 0;\n const boneCount = json.bones ? json.bones.length : 0;\n const slotCount = json.slots ? json.slots.length : 0;\n\n return {\n path: filePath,\n name,\n spineVersion,\n animations,\n skins,\n hasEvents,\n boneCount,\n slotCount,\n };\n } catch {\n return null;\n }\n}\n\nfunction validateSpineVersion(skeleton: SkeletonInfo): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Extract major.minor version\n const version = skeleton.spineVersion;\n const majorMinor = version.match(/^(\\d+\\.\\d+)/)?.[1];\n\n if (\n !majorMinor ||\n !SPINE_VALIDATION_RULES.supportedVersions.includes(\n majorMinor as (typeof SPINE_VALIDATION_RULES.supportedVersions)[number]\n )\n ) {\n issues.push({\n type: 'error',\n message: `Unsupported Spine version: ${version}`,\n file: path.basename(skeleton.path),\n detail: `Supported versions: ${SPINE_VALIDATION_RULES.supportedVersions.join(', ')}`,\n });\n }\n\n return issues;\n}\n\nfunction validateAnimationNames(animations: string[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n for (const name of animations) {\n if (!SPINE_VALIDATION_RULES.animationNamePattern.test(name)) {\n issues.push({\n type: 'warning',\n message: `Animation name \"${name}\" contains invalid characters`,\n detail: 'Recommended: a-z, A-Z, 0-9, _, -',\n });\n }\n }\n\n return issues;\n}\n\nfunction validateTextures(texturePaths: string[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check texture count\n if (texturePaths.length > SPINE_VALIDATION_RULES.maxTextureCount) {\n issues.push({\n type: 'error',\n message: `Too many textures: ${texturePaths.length}`,\n detail: `Maximum allowed: ${SPINE_VALIDATION_RULES.maxTextureCount}`,\n });\n }\n\n // Check each texture\n for (const texturePath of texturePaths) {\n if (!fs.existsSync(texturePath)) {\n issues.push({\n type: 'error',\n message: `Texture file not found: ${path.basename(texturePath)}`,\n });\n continue;\n }\n\n // Check file size (basic check - full dimension check would require image parsing)\n const size = getFileSize(texturePath);\n if (size > 20 * 1024 * 1024) {\n // 20MB per texture is suspicious\n issues.push({\n type: 'warning',\n message: `Large texture file: ${path.basename(texturePath)} (${formatFileSize(size)})`,\n detail: 'Consider optimizing texture size',\n });\n }\n }\n\n return issues;\n}\n\nexport function generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\nexport function validateSlug(slug: string): boolean {\n return SPINE_VALIDATION_RULES.slugPattern.test(slug);\n}\n\n// Export preset for Spine Editor\n// Full preset with texture packing settings\n// Note: 'output' field should be set by user in Spine UI\nexport const SPINE_EXPORT_PRESET = {\n class: 'export-json',\n name: 'Playtagon Platform',\n extension: '.json',\n format: 'JSON',\n nonessential: false,\n cleanUp: true,\n pack: true,\n prettyPrint: false,\n packAtlas: {\n stripWhitespaceX: true,\n stripWhitespaceY: true,\n rotation: true,\n alias: true,\n ignoreBlankImages: false,\n alphaThreshold: 3,\n minWidth: 16,\n minHeight: 16,\n maxWidth: 2048,\n maxHeight: 2048,\n pot: true,\n square: false,\n multipleOfFour: false,\n outputFormat: 'png',\n jpegQuality: 0.9,\n premultiplyAlpha: false,\n paddingX: 2,\n paddingY: 2,\n edgePadding: true,\n duplicatePadding: false,\n filterMin: 'Linear',\n filterMag: 'Linear',\n wrapX: 'ClampToEdge',\n wrapY: 'ClampToEdge',\n format: 'RGBA8888',\n atlasExtension: '.atlas',\n combineSubdirectories: false,\n flattenPaths: false,\n useIndexes: false,\n packing: 'polygons',\n fast: false,\n limitMemory: true,\n scale: [0.5],\n scaleSuffix: [''],\n scaleResampling: ['bilinear'],\n legacyOutput: false,\n debug: false,\n silent: false,\n },\n packSource: 'attachments',\n packTarget: 'single',\n warnings: true,\n version: null,\n all: false,\n open: false,\n};\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nexport interface SpineFileSet {\n skeletonFile: string; // .json or .skel\n atlasFile: string | null; // .atlas\n textureFiles: string[]; // .png or .jpg\n}\n\nexport interface DiscoveredFiles {\n skeletons: string[];\n atlases: string[];\n textures: string[];\n}\n\n// File extensions\nconst SKELETON_EXTENSIONS = ['.json', '.skel'];\nconst ATLAS_EXTENSIONS = ['.atlas'];\nconst TEXTURE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp'];\n\nexport function discoverSpineFiles(directory: string): DiscoveredFiles {\n const absolutePath = path.resolve(directory);\n\n if (!fs.existsSync(absolutePath)) {\n throw new Error(`Directory not found: ${absolutePath}\\n\\nMake sure you're pointing to a folder containing exported Spine files (.json, .atlas, .png), not a .spine project file.`);\n }\n\n if (!fs.statSync(absolutePath).isDirectory()) {\n const ext = path.extname(absolutePath).toLowerCase();\n if (ext === '.spine') {\n throw new Error(`Cannot upload .spine project files directly.\\n\\nYou need to export from Spine Editor first:\\n 1. Open ${path.basename(absolutePath)} in Spine Editor\\n 2. Go to File → Export\\n 3. Export as JSON with atlas\\n 4. Upload the exported folder`);\n }\n throw new Error(`Not a directory: ${absolutePath}\\n\\nThe upload command expects a folder containing exported Spine files (.json, .atlas, .png).`);\n }\n\n const files = fs.readdirSync(absolutePath);\n\n const skeletons: string[] = [];\n const atlases: string[] = [];\n const textures: string[] = [];\n\n for (const file of files) {\n const ext = path.extname(file).toLowerCase();\n const fullPath = path.join(absolutePath, file);\n\n // Skip directories\n if (fs.statSync(fullPath).isDirectory()) continue;\n\n if (SKELETON_EXTENSIONS.includes(ext)) {\n // For .json files, we need to verify it's actually a Spine skeleton\n if (ext === '.json') {\n if (isSpineSkeletonJson(fullPath)) {\n skeletons.push(fullPath);\n }\n } else {\n skeletons.push(fullPath);\n }\n } else if (ATLAS_EXTENSIONS.includes(ext)) {\n atlases.push(fullPath);\n } else if (TEXTURE_EXTENSIONS.includes(ext)) {\n textures.push(fullPath);\n }\n }\n\n return { skeletons, atlases, textures };\n}\n\nexport function isSpineSkeletonJson(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const json = JSON.parse(content);\n // Spine skeleton files have a \"skeleton\" property with version info\n return json.skeleton && typeof json.skeleton.spine === 'string';\n } catch {\n return false;\n }\n}\n\nexport function matchSkeletonToAtlas(\n skeletonPath: string,\n atlases: string[]\n): string | null {\n const skeletonName = path.basename(skeletonPath, path.extname(skeletonPath));\n const skeletonDir = path.dirname(skeletonPath);\n\n // Try exact name match first\n for (const atlas of atlases) {\n const atlasName = path.basename(atlas, '.atlas');\n if (atlasName === skeletonName) {\n return atlas;\n }\n }\n\n // If only one atlas in same directory, use it\n const sameDirectoryAtlases = atlases.filter(\n (a) => path.dirname(a) === skeletonDir\n );\n if (sameDirectoryAtlases.length === 1) {\n return sameDirectoryAtlases[0];\n }\n\n return null;\n}\n\nexport function parseAtlasTextures(atlasPath: string): string[] {\n const content = fs.readFileSync(atlasPath, 'utf-8');\n const lines = content.split('\\n');\n const textures: string[] = [];\n const atlasDir = path.dirname(atlasPath);\n\n for (const line of lines) {\n const trimmed = line.trim();\n // Texture file names are on their own lines, can be .png, .jpg, or .webp\n // They can also include relative paths like \"subdir/texture.png\"\n if (trimmed.endsWith('.png') || trimmed.endsWith('.jpg') || trimmed.endsWith('.jpeg') || trimmed.endsWith('.webp')) {\n // Handle both absolute and relative paths\n const texturePath = path.isAbsolute(trimmed)\n ? trimmed\n : path.join(atlasDir, trimmed);\n\n if (fs.existsSync(texturePath)) {\n textures.push(texturePath);\n }\n }\n }\n\n return textures;\n}\n\nexport function getFileSize(filePath: string): number {\n return fs.statSync(filePath).size;\n}\n\nexport function getTotalSize(files: string[]): number {\n return files.reduce((total, file) => total + getFileSize(file), 0);\n}\n\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;\n}\n\nexport function readFileAsBuffer(filePath: string): Buffer {\n return fs.readFileSync(filePath);\n}\n\nexport function getBaseName(filePath: string): string {\n return path.basename(filePath);\n}\n\nexport function getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { getAccessToken } from '../../lib/auth.js';\nimport { uploadSpineAsset, resolveStudio, resolveGame } from '../../lib/api.js';\nimport {\n validateDirectory,\n generateSlug,\n validateSlug,\n type BatchValidation,\n} from '../../lib/spine-validator.js';\nimport { formatFileSize, getBaseName } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const uploadCommand = new Command('upload')\n .description('Upload Spine files to Playtagon')\n .argument('<directory>', 'Directory containing Spine files')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('-n, --name <name>', 'Asset name (defaults to directory name)')\n .option('--slug <slug>', 'Custom slug for the asset')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .option('--dry-run', 'Validate only, do not upload')\n .option('--description <text>', 'Asset description')\n .option('--tags <tags>', 'Comma-separated tags')\n .action(async (directory: string, options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n logger.info(` ${logger.command('playtagon setup spine-integration --studio <slug>')}`);\n process.exit(1);\n }\n\n const absolutePath = path.resolve(directory);\n\n // Validate directory first\n const spinner = ora('Validating files...').start();\n\n let validation: BatchValidation;\n try {\n validation = validateDirectory(absolutePath, options.batch);\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n\n if (!validation.isValid) {\n spinner.fail('Validation failed');\n printValidationErrors(validation);\n process.exit(1);\n }\n\n spinner.succeed(`Validated ${validation.assets.length} asset(s)`);\n\n // Resolve studio\n spinner.start('Resolving studio...');\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Determine asset name\n const assetName = options.name || path.basename(absolutePath);\n\n // Generate or validate slug\n let slug = options.slug || generateSlug(assetName);\n if (!validateSlug(slug)) {\n logger.error(`Invalid slug: \"${slug}\". Use lowercase letters, numbers, and hyphens only.`);\n process.exit(1);\n }\n\n // Print upload summary\n console.log();\n logger.header('Upload Summary');\n logger.item('Directory', directory);\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Name', assetName);\n logger.item('Slug', slug);\n logger.item('Size', formatFileSize(validation.totalSize));\n\n if (validation.isBatchMode) {\n logger.item('Mode', 'Batch');\n logger.item('Skeletons', String(validation.assets.length));\n }\n\n if (options.dryRun) {\n console.log();\n logger.success('Dry run complete. No files were uploaded.');\n return;\n }\n\n // Build FormData for upload\n console.log();\n spinner.start('Uploading...');\n\n try {\n const formData = await buildFormData(validation, {\n studioId: studio.id,\n gameId: game?.id,\n name: assetName,\n slug,\n description: options.description,\n tags: options.tags?.split(',').map((t: string) => t.trim()),\n batchMode: validation.isBatchMode,\n });\n\n const result = await uploadSpineAsset(formData);\n\n if (result.success) {\n spinner.succeed('Upload complete!');\n\n console.log();\n if (result.assets && result.assets.length > 1) {\n logger.header('Uploaded Assets');\n for (const asset of result.assets) {\n console.log(` ${logger.value(asset.name)} (${asset.slug})`);\n console.log(` ID: ${asset.id}`);\n console.log(` Status: ${asset.status}`);\n }\n } else if (result.asset) {\n logger.header('Uploaded Asset');\n logger.item('ID', result.asset.id);\n logger.item('Name', result.asset.name);\n logger.item('Slug', result.asset.slug);\n logger.item('Status', result.asset.status);\n }\n } else {\n spinner.fail('Upload failed');\n logger.error(result.error || 'Unknown error');\n process.exit(1);\n }\n } catch (error) {\n spinner.fail('Upload failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n });\n\nasync function buildFormData(\n validation: BatchValidation,\n options: {\n studioId: string;\n gameId?: string;\n name: string;\n slug: string;\n description?: string;\n tags?: string[];\n batchMode: boolean;\n }\n): Promise<FormData> {\n const formData = new FormData();\n\n // Add metadata\n formData.append('studioId', options.studioId);\n if (options.gameId) formData.append('gameId', options.gameId);\n formData.append('name', options.name);\n formData.append('slug', options.slug);\n if (options.description) formData.append('description', options.description);\n if (options.tags) formData.append('tags', JSON.stringify(options.tags));\n if (options.batchMode) formData.append('batchMode', 'true');\n\n // Collect all unique files\n const filesAdded = new Set<string>();\n\n // Add skeleton files\n for (const asset of validation.assets) {\n const filePath = asset.skeleton.path;\n if (!filesAdded.has(filePath)) {\n const buffer = fs.readFileSync(filePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(filePath));\n filesAdded.add(filePath);\n }\n }\n\n // Add shared atlas if exists\n if (validation.sharedAtlas && !filesAdded.has(validation.sharedAtlas)) {\n const buffer = fs.readFileSync(validation.sharedAtlas);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(validation.sharedAtlas));\n filesAdded.add(validation.sharedAtlas);\n }\n\n // Add shared textures\n for (const texturePath of validation.sharedTextures) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n\n // Add individual asset files (atlas and textures for non-batch mode)\n for (const asset of validation.assets) {\n if (asset.atlasPath && !filesAdded.has(asset.atlasPath)) {\n const buffer = fs.readFileSync(asset.atlasPath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(asset.atlasPath));\n filesAdded.add(asset.atlasPath);\n }\n\n for (const texturePath of asset.texturePaths) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n }\n\n return formData;\n}\n\nfunction printValidationErrors(validation: BatchValidation): void {\n const errors = validation.issues.filter((i) => i.type === 'error');\n console.log();\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message,\n (error as { detail?: string }).detail\n );\n }\n console.log();\n logger.info(`Run ${logger.command('playtagon spine validate <dir>')} for full report.`);\n}\n","import { config } from './config.js';\nimport { getAccessToken } from './auth.js';\n\nconst API_BASE = config.supabaseUrl;\n\nexport interface UploadResponse {\n success: boolean;\n asset?: {\n id: string;\n name: string;\n slug: string;\n version: number;\n status: string;\n };\n assets?: Array<{\n id: string;\n name: string;\n slug: string;\n version: number;\n status: string;\n }>;\n error?: string;\n}\n\nexport interface StudioInfo {\n id: string;\n name: string;\n slug: string;\n}\n\nexport interface GameInfo {\n id: string;\n name: string;\n slug: string;\n}\n\nexport interface SyncAsset {\n id: string;\n slug: string;\n name: string;\n version: number;\n skeleton_url: string;\n skeleton_format: 'json' | 'binary';\n atlas_url: string;\n texture_urls: string[];\n animations: { name: string; duration: number }[];\n skins: { name: string }[];\n events: { name: string }[];\n total_size_bytes: number;\n updated_at: string;\n}\n\nexport interface SyncManifestResponse {\n assets: SyncAsset[];\n syncedAt: string;\n}\n\nexport async function uploadSpineAsset(formData: FormData): Promise<UploadResponse> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(`${API_BASE}/functions/v1/spine-upload`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n body: formData,\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorText;\n } catch {\n errorMessage = errorText;\n }\n throw new Error(`Upload failed: ${errorMessage}`);\n }\n\n return response.json();\n}\n\nexport async function getStudios(): Promise<StudioInfo[]> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(\n `${API_BASE}/rest/v1/studio_members?select=studio:studios(id,name,slug)`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch studios');\n }\n\n const data = await response.json();\n return data.map((m: { studio: StudioInfo }) => m.studio).filter(Boolean);\n}\n\nexport async function getGames(studioId: string): Promise<GameInfo[]> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const response = await fetch(\n `${API_BASE}/rest/v1/games?studio_id=eq.${studioId}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch games');\n }\n\n return response.json();\n}\n\nexport async function resolveStudio(studioIdOrSlug: string): Promise<StudioInfo | null> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n // Try by ID first, then by slug (case-insensitive)\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n studioIdOrSlug\n );\n\n const query = isUuid\n ? `id=eq.${studioIdOrSlug}`\n : `slug=ilike.${studioIdOrSlug}`; // ilike = case-insensitive LIKE\n\n const response = await fetch(\n `${API_BASE}/rest/v1/studios?${query}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data[0] || null;\n}\n\nexport async function resolveGame(\n studioId: string,\n gameIdOrSlug: string\n): Promise<GameInfo | null> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(\n gameIdOrSlug\n );\n\n const idQuery = isUuid\n ? `id=eq.${gameIdOrSlug}`\n : `slug=ilike.${gameIdOrSlug}`; // ilike = case-insensitive LIKE\n\n const response = await fetch(\n `${API_BASE}/rest/v1/games?studio_id=eq.${studioId}&${idQuery}&select=id,name,slug`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n return null;\n }\n\n const data = await response.json();\n return data[0] || null;\n}\n\nexport async function getSyncManifest(\n studioId: string,\n gameId?: string,\n since?: string\n): Promise<SyncManifestResponse> {\n const token = getAccessToken();\n\n if (!token) {\n throw new Error('Not authenticated. Run `playtagon login` first.');\n }\n\n const params = new URLSearchParams();\n params.set('studioId', studioId);\n if (gameId) params.set('gameId', gameId);\n if (since) params.set('since', since);\n\n const response = await fetch(\n `${API_BASE}/functions/v1/spine-assets/sync?${params}`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n apikey: config.supabaseAnonKey,\n },\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || errorText;\n } catch {\n errorMessage = errorText;\n }\n throw new Error(`Failed to fetch sync manifest: ${errorMessage}`);\n }\n\n return response.json();\n}\n","import { Command } from 'commander';\nimport { SPINE_EXPORT_PRESET } from '../../lib/spine-validator.js';\nimport { logger } from '../../utils/logger.js';\n\nexport const presetCommand = new Command('preset')\n .description('Output Spine export preset JSON for consistent exports')\n .option('--pretty', 'Pretty print JSON (default: true)', true)\n .option('--compact', 'Output compact JSON')\n .action((options) => {\n const pretty = !options.compact;\n\n if (pretty) {\n // Print usage info to stderr so it doesn't interfere with piping\n console.error(logger.info('Spine Export Preset for Playtagon Platform'));\n console.error();\n console.error('Usage:');\n console.error(' playtagon spine preset > playtagon-export.json');\n console.error(' Import this file into Spine Editor as an export preset.');\n console.error();\n }\n\n // Output JSON to stdout for easy piping\n const json = pretty\n ? JSON.stringify(SPINE_EXPORT_PRESET, null, 2)\n : JSON.stringify(SPINE_EXPORT_PRESET);\n\n console.log(json);\n });\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { getSyncManifest, resolveStudio, resolveGame, type SyncAsset } from '../../lib/api.js';\nimport { generateAssetTypes, generateAssetStory, generateManifest } from '../../lib/codegen.js';\nimport { formatFileSize } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\ninterface SyncManifest {\n studioId: string;\n gameId?: string;\n syncedAt: string;\n assets: Record<string, {\n id: string;\n version: number;\n checksum: string;\n updatedAt: string;\n }>;\n}\n\nexport const syncCommand = new Command('sync')\n .description('Sync approved Spine assets to local project')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('-o, --output <dir>', 'Output directory', './src/assets/spine')\n .option('--types', 'Generate TypeScript types (default: true)', true)\n .option('--no-types', 'Skip TypeScript type generation')\n .option('--stories', 'Generate Storybook stories (default: true)', true)\n .option('--no-stories', 'Skip Storybook story generation')\n .option('--assets <slugs>', 'Comma-separated asset slugs to sync (default: all)')\n .option('--force', 'Overwrite local changes')\n .option('--dry-run', 'Show what would be synced without making changes')\n .action(async (options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n process.exit(1);\n }\n\n const outputDir = path.resolve(options.output);\n const manifestPath = path.join(outputDir, '.sync-manifest.json');\n\n // Resolve studio\n const spinner = ora('Resolving studio...').start();\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Load existing manifest for incremental sync\n let existingManifest: SyncManifest | null = null;\n let since: string | undefined;\n\n if (fs.existsSync(manifestPath) && !options.force) {\n try {\n existingManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n if (existingManifest && existingManifest.studioId === studio.id) {\n since = existingManifest.syncedAt;\n logger.info(`Incremental sync from ${new Date(since).toLocaleString()}`);\n }\n } catch {\n // Ignore invalid manifest\n }\n }\n\n // Fetch sync manifest from API\n spinner.start('Fetching asset manifest...');\n let manifest;\n try {\n manifest = await getSyncManifest(studio.id, game?.id, options.force ? undefined : since);\n } catch (error) {\n spinner.fail('Failed to fetch manifest');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n process.exit(1);\n }\n\n const assets = manifest.assets;\n\n // Filter by specific slugs if provided\n let assetsToSync = assets;\n if (options.assets) {\n const requestedSlugs = options.assets.split(',').map((s: string) => s.trim());\n assetsToSync = assets.filter((a: SyncAsset) => requestedSlugs.includes(a.slug));\n\n const found = assetsToSync.map((a: SyncAsset) => a.slug);\n const notFound = requestedSlugs.filter((s: string) => !found.includes(s));\n\n if (notFound.length > 0) {\n logger.warn(`Assets not found (or not approved): ${notFound.join(', ')}`);\n }\n }\n\n if (assetsToSync.length === 0) {\n spinner.succeed('No assets to sync');\n logger.info('All assets are up to date or no approved assets found.');\n return;\n }\n\n spinner.succeed(`Found ${assetsToSync.length} asset(s) to sync`);\n\n // Calculate total size\n const totalSize = assetsToSync.reduce((sum: number, a: SyncAsset) => sum + a.total_size_bytes, 0);\n\n // Print sync summary\n console.log();\n logger.header('Sync Summary');\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Output', outputDir);\n logger.item('Assets', String(assetsToSync.length));\n logger.item('Total Size', formatFileSize(totalSize));\n logger.item('TypeScript Types', options.types ? 'Yes' : 'No');\n logger.item('Storybook Stories', options.stories ? 'Yes' : 'No');\n\n console.log();\n logger.header('Assets');\n for (const asset of assetsToSync) {\n console.log(` ${logger.value(asset.name)} (${asset.slug}) v${asset.version}`);\n }\n\n if (options.dryRun) {\n console.log();\n logger.success('Dry run complete. No files were written.');\n return;\n }\n\n // Create output directory\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n // Download and generate files for each asset\n console.log();\n const syncedAssets: Record<string, { id: string; version: number; checksum: string; updatedAt: string }> = {};\n\n for (const asset of assetsToSync) {\n spinner.start(`Syncing ${asset.name}...`);\n\n try {\n const assetDir = path.join(outputDir, asset.slug);\n\n // Create asset directory\n if (!fs.existsSync(assetDir)) {\n fs.mkdirSync(assetDir, { recursive: true });\n }\n\n // Download skeleton file\n const skeletonExt = asset.skeleton_format === 'binary' ? '.skel' : '.json';\n const skeletonPath = path.join(assetDir, `${asset.slug}${skeletonExt}`);\n await downloadFile(asset.skeleton_url, skeletonPath);\n\n // Download atlas file\n const atlasPath = path.join(assetDir, `${asset.slug}.atlas`);\n await downloadFile(asset.atlas_url, atlasPath);\n\n // Download texture files\n for (const textureUrl of asset.texture_urls) {\n const textureName = path.basename(new URL(textureUrl).pathname);\n const texturePath = path.join(assetDir, textureName);\n await downloadFile(textureUrl, texturePath);\n }\n\n // Generate TypeScript types\n if (options.types) {\n const typesContent = generateAssetTypes(asset);\n const typesPath = path.join(assetDir, 'index.ts');\n fs.writeFileSync(typesPath, typesContent);\n }\n\n // Generate Storybook story (Svelte CSF format)\n if (options.stories) {\n const storyContent = generateAssetStory(asset);\n const storyPath = path.join(assetDir, `${pascalCase(asset.slug)}.stories.svelte`);\n fs.writeFileSync(storyPath, storyContent);\n }\n\n // Track synced asset\n syncedAssets[asset.slug] = {\n id: asset.id,\n version: asset.version,\n checksum: generateChecksum(asset),\n updatedAt: asset.updated_at,\n };\n\n spinner.succeed(`Synced ${asset.name}`);\n } catch (error) {\n spinner.fail(`Failed to sync ${asset.name}`);\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n }\n }\n\n // Merge with existing manifest\n const finalAssets = {\n ...(existingManifest?.assets || {}),\n ...syncedAssets,\n };\n\n // Generate manifest.ts with all asset exports\n if (options.types) {\n spinner.start('Generating manifest...');\n const manifestContent = generateManifest(Object.keys(finalAssets));\n fs.writeFileSync(path.join(outputDir, 'manifest.ts'), manifestContent);\n spinner.succeed('Generated manifest.ts');\n }\n\n // Save sync manifest\n const newManifest: SyncManifest = {\n studioId: studio.id,\n gameId: game?.id,\n syncedAt: manifest.syncedAt,\n assets: finalAssets,\n };\n fs.writeFileSync(manifestPath, JSON.stringify(newManifest, null, 2));\n\n console.log();\n logger.success(`Synced ${Object.keys(syncedAssets).length} asset(s) to ${outputDir}`);\n });\n\nasync function downloadFile(url: string, destPath: string): Promise<void> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download: ${response.status} ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n fs.writeFileSync(destPath, Buffer.from(buffer));\n}\n\nfunction generateChecksum(asset: SyncAsset): string {\n // Simple checksum based on version and updated_at\n const data = `${asset.id}:${asset.version}:${asset.updated_at}`;\n let hash = 0;\n for (let i = 0; i < data.length; i++) {\n const char = data.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(16);\n}\n\nfunction pascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n","import type { SyncAsset } from './api.js';\n\n/**\n * Convert a slug to PascalCase for type/const names\n */\nfunction pascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Convert a slug to camelCase for variable names\n */\nfunction camelCase(str: string): string {\n const pascal = pascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n\n/**\n * Escape a string for use in JavaScript string literals\n */\nfunction escapeString(str: string): string {\n return str.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate TypeScript types and config for a Spine asset\n */\nexport function generateAssetTypes(asset: SyncAsset): string {\n const name = pascalCase(asset.slug);\n const ext = asset.skeleton_format === 'binary' ? '.skel' : '.json';\n\n const animationNames = asset.animations.map(a => a.name);\n const skinNames = asset.skins.map(s => s.name);\n const eventNames = asset.events.map(e => e.name);\n\n return `// Auto-generated by @playtagon/cli\n// Do not edit manually - changes will be overwritten on next sync\n\n/**\n * ${asset.name}\n * @version ${asset.version}\n */\n\nexport const ${name}Animations = {\n${animationNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Animation = typeof ${name}Animations[keyof typeof ${name}Animations];\n\nexport const ${name}Skins = {\n${skinNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Skin = typeof ${name}Skins[keyof typeof ${name}Skins];\n\n${eventNames.length > 0 ? `export const ${name}Events = {\n${eventNames.map(n => ` '${escapeString(n)}': '${escapeString(n)}',`).join('\\n')}\n} as const;\n\nexport type ${name}Event = typeof ${name}Events[keyof typeof ${name}Events];\n` : `export const ${name}Events = {} as const;\n\nexport type ${name}Event = never;\n`}\nexport interface ${name}AnimationInfo {\n name: ${name}Animation;\n duration: number;\n}\n\nexport const ${name}AnimationDurations: Record<${name}Animation, number> = {\n${asset.animations.map(a => ` '${escapeString(a.name)}': ${a.duration},`).join('\\n')}\n};\n\nexport const ${name} = {\n id: '${asset.slug}',\n name: '${escapeString(asset.name)}',\n version: ${asset.version},\n skeleton: './${asset.slug}${ext}',\n atlas: './${asset.slug}.atlas',\n animations: ${name}Animations,\n skins: ${name}Skins,\n events: ${name}Events,\n animationDurations: ${name}AnimationDurations,\n defaultAnimation: '${escapeString(animationNames[0] || 'idle')}' as ${name}Animation,\n defaultSkin: '${escapeString(skinNames[0] || 'default')}' as ${name}Skin,\n} as const;\n\nexport type ${name}Config = typeof ${name};\n\nexport default ${name};\n`;\n}\n\n/**\n * Generate a Storybook story for a Spine asset (Svelte CSF format)\n * Compatible with pixi-svelte's SpineAnimation component\n */\nexport function generateAssetStory(asset: SyncAsset): string {\n const name = pascalCase(asset.slug);\n\n // Generate individual animation stories\n const animationStories = asset.animations.map(anim => {\n return `<Story name=\"${escapeString(anim.name)}\">\n {#snippet template(args)}\n <StoryPixiApp {assets}>\n <SpineAnimation {...args} asset={${name}} animation=\"${escapeString(anim.name)}\" />\n </StoryPixiApp>\n {/snippet}\n</Story>`;\n }).join('\\n\\n');\n\n return `<!-- Auto-generated by @playtagon/cli -->\n<!-- Do not edit manually - changes will be overwritten on next sync -->\n\n<script lang=\"ts\" module>\n import { defineMeta } from '@storybook/addon-svelte-csf';\n import { SpineAnimation, createSpineAssets } from 'pixi-svelte';\n import { StoryPixiApp } from 'components-storybook';\n import ${name}, { ${name}Animations, ${name}Skins } from './index';\n\n const { Story } = defineMeta({\n title: 'Spine/${escapeString(asset.name)}',\n args: {\n width: 400,\n height: 400,\n x: 200,\n y: 200,\n loop: true,\n speed: 1,\n },\n argTypes: {\n animation: {\n control: 'select',\n options: Object.values(${name}Animations),\n description: 'Animation to play',\n },\n skin: {\n control: 'select',\n options: Object.values(${name}Skins),\n description: 'Skin to apply',\n },\n loop: {\n control: 'boolean',\n description: 'Whether to loop the animation',\n },\n speed: {\n control: { type: 'range', min: 0.1, max: 3, step: 0.1 },\n description: 'Playback speed multiplier',\n },\n },\n });\n\n // Create assets for Storybook - adjust baseUrl to match your asset serving path\n const assets = createSpineAssets([${name}], '.');\n</script>\n\n<!-- Default story with all controls -->\n<Story name=\"Default\">\n {#snippet template(args)}\n <StoryPixiApp {assets}>\n <SpineAnimation\n {...args}\n asset={${name}}\n animation={args.animation ?? ${name}.defaultAnimation}\n skin={args.skin ?? ${name}.defaultSkin}\n />\n </StoryPixiApp>\n {/snippet}\n</Story>\n\n<!-- Individual animation stories -->\n${animationStories}\n`;\n}\n\n/**\n * Generate the main manifest.ts file that exports all assets\n */\nexport function generateManifest(slugs: string[]): string {\n const imports = slugs.map(slug => {\n const name = pascalCase(slug);\n return `import ${name} from './${slug}';`;\n }).join('\\n');\n\n const exports = slugs.map(slug => {\n const name = pascalCase(slug);\n return ` ${name},`;\n }).join('\\n');\n\n const reexports = slugs.map(slug => {\n const name = pascalCase(slug);\n return `export * from './${slug}';`;\n }).join('\\n');\n\n return `// Auto-generated by @playtagon/cli\n// Do not edit manually - changes will be overwritten on next sync\n\n${imports}\n\nexport const SpineAssets = {\n${exports}\n} as const;\n\nexport type SpineAssetName = keyof typeof SpineAssets;\n\n// Re-export all individual assets\n${reexports}\n\nexport default SpineAssets;\n`;\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport ora from 'ora';\nimport { credentials, config } from '../../lib/config.js';\nimport { uploadSpineAsset, resolveStudio, resolveGame } from '../../lib/api.js';\nimport {\n validateDirectory,\n generateSlug,\n validateSlug,\n type BatchValidation,\n} from '../../lib/spine-validator.js';\nimport { formatFileSize, getBaseName } from '../../utils/files.js';\nimport { logger } from '../../utils/logger.js';\n\ninterface WatchState {\n lastModified: Map<string, number>;\n isUploading: boolean;\n studioId: string;\n gameId?: string;\n lastChangeDetected: number;\n pendingUpload: boolean;\n}\n\nexport const watchCommand = new Command('watch')\n .description('Watch directory for new Spine exports and auto-upload')\n .argument('<directory>', 'Directory to watch for Spine files')\n .option('-s, --studio <studio>', 'Studio ID or slug (uses default if set)')\n .option('-g, --game <game>', 'Game ID or slug (uses default if set)')\n .option('--batch', 'Enable batch mode for multiple skeletons sharing atlas')\n .option('--interval <seconds>', 'Check interval in seconds', '2')\n .option('--debug', 'Enable debug output')\n .option('--upload-existing', 'Upload files that are already in the directory when watcher starts')\n .action(async (directory: string, options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n // Use defaults from config if not provided\n const studioOption = options.studio || config.defaultStudio;\n const gameOption = options.game || config.defaultGame;\n\n if (!studioOption) {\n logger.error('Studio is required.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default:`);\n logger.info(` ${logger.command('playtagon config --studio <slug>')}`);\n process.exit(1);\n }\n\n const absolutePath = path.resolve(directory);\n\n // Verify directory exists\n if (!fs.existsSync(absolutePath)) {\n logger.error(`Directory not found: ${absolutePath}`);\n process.exit(1);\n }\n\n // Resolve studio\n const spinner = ora('Resolving studio...').start();\n const studio = await resolveStudio(studioOption);\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${studioOption}\" not found or you don't have access.`);\n process.exit(1);\n }\n spinner.succeed(`Studio: ${studio.name}`);\n\n // Resolve game if provided\n let game = null;\n if (gameOption) {\n spinner.start('Resolving game...');\n game = await resolveGame(studio.id, gameOption);\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameOption}\" not found in studio \"${studio.name}\".`);\n process.exit(1);\n }\n spinner.succeed(`Game: ${game.name}`);\n }\n\n // Initialize watch state\n const state: WatchState = {\n lastModified: new Map(),\n isUploading: false,\n studioId: studio.id,\n gameId: game?.id,\n lastChangeDetected: 0,\n pendingUpload: false,\n };\n\n // Initial scan\n await scanDirectory(absolutePath, state);\n\n // Print watch info\n console.log();\n logger.header('Watching for Spine Exports');\n logger.item('Directory', absolutePath);\n logger.item('Studio', studio.name);\n if (game) logger.item('Game', game.name);\n logger.item('Batch Mode', options.batch ? 'Yes' : 'No');\n logger.item('Check Interval', `${options.interval}s`);\n\n // Show initial file count\n const initialFiles = getAllFiles(absolutePath);\n const initialSkeletons = initialFiles.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const initialAtlas = initialFiles.filter(f => f.endsWith('.atlas'));\n const initialTextures = initialFiles.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n console.log();\n logger.info(`Found ${initialFiles.length} file(s) in directory:`);\n logger.info(` - ${initialSkeletons.length} skeleton(s) (.json/.skel)`);\n logger.info(` - ${initialAtlas.length} atlas (.atlas)`);\n logger.info(` - ${initialTextures.length} texture(s) (.png/.jpg/.webp)`);\n\n if (options.debug && initialFiles.length > 0) {\n console.log();\n logger.info('Files found:');\n for (const file of initialFiles) {\n console.log(` ${path.relative(absolutePath, file)}`);\n }\n }\n\n // Upload existing files if requested\n if (options.uploadExisting && initialFiles.length > 0) {\n const hasAtlas = initialAtlas.length > 0;\n const hasTextures = initialTextures.length > 0;\n const hasSkeletons = initialSkeletons.length > 0;\n\n if (hasAtlas && hasTextures && hasSkeletons) {\n console.log();\n logger.info('--upload-existing flag detected, uploading current files...');\n await uploadDirectory(absolutePath, state, options.batch);\n console.log();\n } else {\n console.log();\n logger.warn('--upload-existing: Incomplete file set, skipping upload');\n logger.warn(` Missing: ${!hasAtlas ? 'atlas ' : ''}${!hasTextures ? 'textures ' : ''}${!hasSkeletons ? 'skeletons' : ''}`);\n console.log();\n }\n }\n\n console.log();\n logger.info('Watching for changes... (Press Ctrl+C to stop)');\n console.log();\n\n // Start watching\n const intervalMs = parseInt(options.interval) * 1000;\n setInterval(async () => {\n await checkForChanges(absolutePath, state, options.batch, options.debug);\n }, intervalMs);\n\n // Keep process alive\n process.on('SIGINT', () => {\n console.log();\n logger.success('Stopped watching.');\n process.exit(0);\n });\n });\n\nasync function scanDirectory(directory: string, state: WatchState): Promise<void> {\n const files = getAllFiles(directory);\n\n for (const file of files) {\n const stats = fs.statSync(file);\n state.lastModified.set(file, stats.mtimeMs);\n }\n}\n\nfunction getAllFiles(directory: string): string[] {\n const files: string[] = [];\n\n try {\n const entries = fs.readdirSync(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(directory, entry.name);\n\n if (entry.isFile()) {\n // Only track Spine-related files\n const ext = path.extname(entry.name).toLowerCase();\n if (['.json', '.skel', '.atlas', '.png', '.jpg', '.jpeg', '.webp'].includes(ext)) {\n files.push(fullPath);\n }\n } else if (entry.isDirectory()) {\n files.push(...getAllFiles(fullPath));\n }\n }\n } catch (error) {\n // Ignore errors\n }\n\n return files;\n}\n\nasync function checkForChanges(\n directory: string,\n state: WatchState,\n batchMode: boolean,\n debug: boolean = false\n): Promise<void> {\n if (state.isUploading) {\n return; // Skip if already uploading\n }\n\n const files = getAllFiles(directory);\n let hasChanges = false;\n const currentChangeTime = Date.now();\n\n if (debug && files.length > 0) {\n const skeletons = files.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const atlas = files.filter(f => f.endsWith('.atlas'));\n const textures = files.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n console.log(`[DEBUG] Checking ${files.length} files: ${skeletons.length} skeleton(s), ${atlas.length} atlas, ${textures.length} texture(s)`);\n }\n\n // Check for new or modified files\n for (const file of files) {\n try {\n const stats = fs.statSync(file);\n const lastModified = state.lastModified.get(file) || 0;\n\n if (stats.mtimeMs > lastModified) {\n hasChanges = true;\n // Update last change time\n state.lastChangeDetected = currentChangeTime;\n state.pendingUpload = true;\n }\n } catch (error) {\n // File might have been deleted\n }\n }\n\n // If files are still changing, reset the timer\n if (hasChanges) {\n return; // Wait for files to settle\n }\n\n // No new changes - check if we have a pending upload\n if (!state.pendingUpload) {\n return; // Nothing to upload\n }\n\n // Wait for files to stabilize (no changes for at least 5 seconds)\n const timeSinceLastChange = currentChangeTime - state.lastChangeDetected;\n if (timeSinceLastChange < 5000) {\n return; // Files still settling\n }\n\n // Verify we have a complete set of files before uploading\n const hasAtlas = files.some(f => f.endsWith('.atlas'));\n const hasTextures = files.some(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n const hasSkeletons = files.some(f => f.endsWith('.json') || f.endsWith('.skel'));\n\n if (!hasAtlas) {\n console.log(' Waiting for .atlas file...');\n return;\n }\n\n if (!hasTextures) {\n console.log(' Waiting for texture files (.png/.jpg/.webp)...');\n return;\n }\n\n if (!hasSkeletons) {\n console.log(' Waiting for skeleton files (.json/.skel)...');\n return;\n }\n\n // Additional check: count files to ensure we have the expected set\n // In batch mode with multiple skeletons, we should have:\n // - Multiple .json files (one per skeleton)\n // - One .atlas file (shared)\n // - One or more texture files (shared)\n const atlasFiles = files.filter(f => f.endsWith('.atlas'));\n const skeletonFiles = files.filter(f => f.endsWith('.json') || f.endsWith('.skel'));\n const textureFiles = files.filter(f => /\\.(png|jpg|jpeg|webp)$/i.test(f));\n\n console.log(` Found: ${skeletonFiles.length} skeleton(s), ${atlasFiles.length} atlas, ${textureFiles.length} texture(s)`);\n\n // Reset pending upload flag BEFORE upload starts\n state.pendingUpload = false;\n\n // Trigger upload\n state.isUploading = true;\n await uploadDirectory(directory, state, batchMode);\n state.isUploading = false;\n\n // Update lastModified AFTER successful upload\n // This prevents re-uploading the same files on next check\n for (const file of files) {\n try {\n const stats = fs.statSync(file);\n state.lastModified.set(file, stats.mtimeMs);\n } catch (error) {\n // Ignore\n }\n }\n}\n\nasync function uploadDirectory(\n directory: string,\n state: WatchState,\n batchMode: boolean\n): Promise<void> {\n const timestamp = new Date().toLocaleTimeString();\n console.log(`[${timestamp}] Changes detected, uploading...`);\n\n const spinner = ora('Validating files...').start();\n\n let validation: BatchValidation;\n try {\n validation = validateDirectory(directory, batchMode);\n } catch (error) {\n spinner.fail('Validation failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n console.log();\n return;\n }\n\n if (!validation.isValid) {\n spinner.fail('Validation failed');\n const errors = validation.issues.filter((i) => i.type === 'error');\n for (const error of errors) {\n logger.validationError(\n error.file ? `${error.file}: ${error.message}` : error.message\n );\n }\n console.log();\n return;\n }\n\n spinner.text = `Validated ${validation.assets.length} asset(s)`;\n spinner.succeed();\n\n // Determine asset name from directory\n const assetName = path.basename(directory);\n const slug = generateSlug(assetName);\n\n if (!validateSlug(slug)) {\n logger.error(`Invalid slug generated: \"${slug}\". Skipping upload.`);\n console.log();\n return;\n }\n\n spinner.start('Uploading...');\n\n try {\n const formData = await buildFormData(validation, {\n studioId: state.studioId,\n gameId: state.gameId,\n name: assetName,\n slug,\n batchMode: validation.isBatchMode,\n });\n\n const result = await uploadSpineAsset(formData);\n\n if (result.success) {\n spinner.succeed('Upload complete!');\n\n if (result.assets && result.assets.length > 1) {\n console.log(` Uploaded ${result.assets.length} assets (batch mode)`);\n for (const asset of result.assets) {\n console.log(` ${asset.name} (${asset.slug}) - ${asset.status}`);\n }\n } else if (result.asset) {\n console.log(` ${result.asset.name} (${result.asset.slug}) - ${result.asset.status}`);\n }\n console.log();\n } else {\n spinner.fail('Upload failed');\n logger.error(result.error || 'Unknown error');\n console.log();\n }\n } catch (error) {\n spinner.fail('Upload failed');\n logger.error(error instanceof Error ? error.message : 'Unknown error');\n console.log();\n }\n}\n\nasync function buildFormData(\n validation: BatchValidation,\n options: {\n studioId: string;\n gameId?: string;\n name: string;\n slug: string;\n batchMode: boolean;\n }\n): Promise<FormData> {\n const formData = new FormData();\n\n // Add metadata\n formData.append('studioId', options.studioId);\n if (options.gameId) formData.append('gameId', options.gameId);\n formData.append('name', options.name);\n formData.append('slug', options.slug);\n if (options.batchMode) formData.append('batchMode', 'true');\n\n // Collect all unique files\n const filesAdded = new Set<string>();\n\n // Add skeleton files\n for (const asset of validation.assets) {\n const filePath = asset.skeleton.path;\n if (!filesAdded.has(filePath)) {\n const buffer = fs.readFileSync(filePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(filePath));\n filesAdded.add(filePath);\n }\n }\n\n // Add shared atlas if exists\n if (validation.sharedAtlas && !filesAdded.has(validation.sharedAtlas)) {\n const buffer = fs.readFileSync(validation.sharedAtlas);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(validation.sharedAtlas));\n filesAdded.add(validation.sharedAtlas);\n }\n\n // Add shared textures\n for (const texturePath of validation.sharedTextures) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n\n // Add individual asset files (atlas and textures for non-batch mode)\n for (const asset of validation.assets) {\n if (asset.atlasPath && !filesAdded.has(asset.atlasPath)) {\n const buffer = fs.readFileSync(asset.atlasPath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(asset.atlasPath));\n filesAdded.add(asset.atlasPath);\n }\n\n for (const texturePath of asset.texturePaths) {\n if (!filesAdded.has(texturePath)) {\n const buffer = fs.readFileSync(texturePath);\n const blob = new Blob([buffer]);\n formData.append('files', blob, getBaseName(texturePath));\n filesAdded.add(texturePath);\n }\n }\n }\n\n return formData;\n}\n","import { Command } from 'commander';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\nimport { execFile } from 'node:child_process';\nimport ora from 'ora';\nimport { credentials, config } from '../lib/config.js';\nimport { getCurrentUser } from '../lib/auth.js';\nimport { getStudios, getGames } from '../lib/api.js';\nimport { SPINE_EXPORT_PRESET } from '../lib/spine-validator.js';\nimport { logger } from '../utils/logger.js';\n\nconst PLAYTAGON_DIR = path.join(os.homedir(), '.playtagon');\n\nexport const setupCommand = new Command('setup')\n .description('Set up integrations')\n .addCommand(spineIntegrationCommand());\n\nfunction spineIntegrationCommand(): Command {\n return new Command('spine-integration')\n .description('Set up automatic Spine Editor to Platform upload')\n .option('-s, --studio <studio>', 'Default studio for uploads')\n .option('-g, --game <game>', 'Default game for uploads')\n .option('--force', 'Overwrite existing setup files')\n .action(async (options) => {\n // Check authentication\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const spinner = ora('Checking authentication...').start();\n\n // Verify auth and get user info\n const user = await getCurrentUser();\n if (!user) {\n spinner.fail('Session expired');\n logger.info(`Run ${logger.command('playtagon login')} to re-authenticate.`);\n process.exit(1);\n }\n\n spinner.succeed(`Logged in as ${user.email}`);\n\n // Get studios\n let studioSlug = options.studio;\n if (!studioSlug) {\n spinner.start('Fetching studios...');\n const studios = await getStudios();\n spinner.stop();\n\n if (studios.length === 0) {\n logger.error('No studios found. Join or create a studio first.');\n process.exit(1);\n }\n\n if (studios.length === 1) {\n studioSlug = studios[0].slug;\n logger.info(`Using studio: ${logger.value(studios[0].name)}`);\n } else {\n logger.header('Available Studios');\n studios.forEach((s, i) => {\n console.log(` ${i + 1}. ${s.name} (${logger.value(s.slug)})`);\n });\n console.log();\n logger.info(`Specify studio with ${logger.command('--studio <slug>')}`);\n logger.info(`Example: ${logger.command(`playtagon setup spine-integration --studio ${studios[0].slug}`)}`);\n process.exit(1);\n }\n }\n\n // Create .playtagon directory\n spinner.start('Creating setup files...');\n\n if (!fs.existsSync(PLAYTAGON_DIR)) {\n fs.mkdirSync(PLAYTAGON_DIR, { recursive: true, mode: 0o700 });\n }\n\n // Generate post-export scripts\n const scriptPaths = generatePostExportScripts(studioSlug, options.game, options.force);\n\n // Generate Spine export preset with postScript\n const presetPath = generateExportPreset(scriptPaths.sh, options.force);\n\n spinner.succeed('Setup complete!');\n\n // Print instructions\n console.log();\n logger.header('Setup Complete');\n console.log();\n logger.info('Files created:');\n console.log(` ${logger.file(scriptPaths.sh)}`);\n if (process.platform === 'win32') {\n console.log(` ${logger.file(scriptPaths.bat)}`);\n }\n console.log(` ${logger.file(presetPath)}`);\n\n console.log();\n logger.header('Next Steps');\n console.log();\n console.log(' 1. Open Spine Editor');\n console.log(' 2. Go to File → Export...');\n console.log(' 3. Click the gear icon (⚙) next to the preset dropdown');\n console.log(' 4. Click \"Import\" and select the preset file from the folder that just opened');\n console.log(' 5. The preset \"Upload to Playtagon\" will be available');\n console.log();\n console.log(' Now when you export with this preset, files automatically');\n console.log(' upload to Playtagon Platform!');\n console.log();\n\n // Open the folder in Finder/Explorer so user can find the preset file\n openFolder(PLAYTAGON_DIR);\n\n // Verify game if provided\n let gameSlug = options.game;\n if (gameSlug) {\n spinner.start('Verifying game...');\n const studios = await getStudios();\n const studio = studios.find((s) => s.slug.toLowerCase() === studioSlug.toLowerCase());\n if (studio) {\n const games = await getGames(studio.id);\n const game = games.find(\n (g) => g.slug.toLowerCase() === gameSlug.toLowerCase() ||\n g.id === gameSlug ||\n g.name.toLowerCase() === gameSlug.toLowerCase()\n );\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${gameSlug}\" not found in studio \"${studioSlug}\".`);\n if (games.length > 0) {\n console.log();\n logger.info('Available games:');\n games.forEach((g) => {\n console.log(` ${logger.value(g.slug)} - ${g.name}`);\n });\n }\n process.exit(1);\n }\n gameSlug = game.slug; // Normalize to slug\n spinner.succeed(`Game: ${game.name}`);\n }\n }\n\n // Save defaults to config\n config.defaultStudio = studioSlug;\n if (gameSlug) {\n config.defaultGame = gameSlug;\n }\n\n if (gameSlug) {\n logger.info(`Uploads will go to: ${logger.value(studioSlug)} / ${logger.value(gameSlug)}`);\n } else {\n logger.info(`Uploads will go to studio: ${logger.value(studioSlug)}`);\n logger.info(`Add ${logger.command('--game <slug>')} to also set default game.`);\n }\n\n console.log();\n logger.info('Defaults saved. You can change them later with:');\n logger.info(` ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n });\n}\n\nfunction generatePostExportScripts(\n studioSlug: string,\n gameSlug?: string,\n force = false\n): { sh: string; bat: string } {\n const shPath = path.join(PLAYTAGON_DIR, 'upload.sh');\n const batPath = path.join(PLAYTAGON_DIR, 'upload.bat');\n\n // Build upload command\n let uploadCmd = `playtagon spine upload \"$1\" --studio ${studioSlug}`;\n if (gameSlug) {\n uploadCmd += ` --game ${gameSlug}`;\n }\n\n // Shell script (Mac/Linux)\n const shScript = `#!/bin/bash\n# Playtagon Spine Upload Script\n# Auto-generated by: playtagon setup spine-integration\n#\n# This script is called by Spine Editor after export.\n# It uploads the exported files to Playtagon Platform.\n\nset -e\n\nEXPORT_DIR=\"$1\"\n\nif [ -z \"$EXPORT_DIR\" ]; then\n echo \"Error: No export directory provided\"\n exit 1\nfi\n\necho \"Uploading to Playtagon...\"\n${uploadCmd}\n\n# macOS notification (optional)\nif command -v osascript &> /dev/null; then\n osascript -e 'display notification \"Spine export uploaded successfully\" with title \"Playtagon\"' 2>/dev/null || true\nfi\n\n# Linux notification (optional)\nif command -v notify-send &> /dev/null; then\n notify-send \"Playtagon\" \"Spine export uploaded successfully\" 2>/dev/null || true\nfi\n\necho \"Upload complete!\"\n`;\n\n // Batch script (Windows)\n let uploadCmdWin = `playtagon spine upload \"%~1\" --studio ${studioSlug}`;\n if (gameSlug) {\n uploadCmdWin += ` --game ${gameSlug}`;\n }\n\n const batScript = `@echo off\nREM Playtagon Spine Upload Script\nREM Auto-generated by: playtagon setup spine-integration\nREM\nREM This script is called by Spine Editor after export.\nREM It uploads the exported files to Playtagon Platform.\n\nset EXPORT_DIR=%~1\nset LOG_FILE=%USERPROFILE%\\\\.playtagon\\\\upload.log\n\nREM Log script execution\necho [%date% %time%] Script started with directory: %EXPORT_DIR% >> \"%LOG_FILE%\"\n\nif \"%EXPORT_DIR%\"==\"\" (\n echo Error: No export directory provided\n echo [%date% %time%] ERROR: No export directory provided >> \"%LOG_FILE%\"\n exit /b 1\n)\n\necho Uploading to Playtagon...\necho [%date% %time%] Running upload command... >> \"%LOG_FILE%\"\n${uploadCmdWin} >> \"%LOG_FILE%\" 2>&1\n\nif %ERRORLEVEL% EQU 0 (\n echo [%date% %time%] Upload successful >> \"%LOG_FILE%\"\n REM Windows notification (PowerShell)\n powershell -Command \"& {Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('Spine export uploaded successfully', 'Playtagon', 'OK', 'Information')}\" 2>nul\n echo Upload complete!\n) else (\n echo [%date% %time%] Upload failed with error code %ERRORLEVEL% >> \"%LOG_FILE%\"\n powershell -Command \"& {Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('Upload failed! Check log file', 'Playtagon Error', 'OK', 'Error')}\" 2>nul\n)\n`;\n\n // Write scripts\n if (!fs.existsSync(shPath) || force) {\n fs.writeFileSync(shPath, shScript, { mode: 0o755 });\n } else {\n logger.warn(`${shPath} already exists. Use --force to overwrite.`);\n }\n\n if (!fs.existsSync(batPath) || force) {\n fs.writeFileSync(batPath, batScript);\n }\n\n return { sh: shPath, bat: batPath };\n}\n\nfunction generateExportPreset(scriptPath: string, force = false): string {\n const presetPath = path.join(PLAYTAGON_DIR, 'playtagon-spine-preset.export.json');\n\n // Extend the base preset with postScript\n const preset = {\n ...SPINE_EXPORT_PRESET,\n name: 'Upload to Playtagon',\n postScript: process.platform === 'win32'\n ? `\"${scriptPath.replace('.sh', '.bat')}\" \"{output}\"`\n : `\"${scriptPath}\" \"{output}\"`,\n };\n\n if (!fs.existsSync(presetPath) || force) {\n fs.writeFileSync(presetPath, JSON.stringify(preset, null, 2));\n } else {\n logger.warn(`${presetPath} already exists. Use --force to overwrite.`);\n }\n\n return presetPath;\n}\n\nfunction openFolder(folderPath: string): void {\n // Open folder in system file manager using execFile (safe from injection)\n const platform = process.platform;\n let cmd: string;\n let args: string[];\n\n if (platform === 'darwin') {\n cmd = 'open';\n args = [folderPath];\n } else if (platform === 'win32') {\n cmd = 'explorer';\n args = [folderPath];\n } else {\n // Linux - try xdg-open\n cmd = 'xdg-open';\n args = [folderPath];\n }\n\n execFile(cmd, args, (error) => {\n if (error) {\n // Silently fail - user can still navigate manually\n logger.debug(`Could not open folder: ${error.message}`);\n }\n });\n}\n","import { Command } from 'commander';\nimport { config, credentials } from '../lib/config.js';\nimport { getStudios, getGames } from '../lib/api.js';\nimport { logger } from '../utils/logger.js';\nimport ora from 'ora';\n\nexport const configCommand = new Command('config')\n .description('View or set CLI configuration')\n .option('-s, --studio <studio>', 'Set default studio')\n .option('-g, --game <game>', 'Set default game')\n .option('--clear', 'Clear all default settings')\n .action(async (options) => {\n // If --clear flag is set, clear all defaults\n if (options.clear) {\n config.defaultStudio = undefined;\n config.defaultGame = undefined;\n logger.success('Default settings cleared.');\n return;\n }\n\n // If setting studio\n if (options.studio) {\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const spinner = ora('Verifying studio...').start();\n const studios = await getStudios();\n const studio = studios.find(\n (s) => s.slug === options.studio || s.id === options.studio || s.name === options.studio\n );\n\n if (!studio) {\n spinner.fail('Studio not found');\n logger.error(`Studio \"${options.studio}\" not found or you don't have access.`);\n console.log();\n logger.info('Available studios:');\n studios.forEach((s) => {\n console.log(` ${logger.value(s.slug)} - ${s.name}`);\n });\n process.exit(1);\n }\n\n spinner.succeed(`Default studio set: ${studio.name} (${studio.slug})`);\n config.defaultStudio = studio.slug;\n }\n\n // If setting game\n if (options.game) {\n if (!credentials.isLoggedIn()) {\n logger.error('Not logged in.');\n logger.info(`Run ${logger.command('playtagon login')} first.`);\n process.exit(1);\n }\n\n const studioSlug = options.studio || config.defaultStudio;\n if (!studioSlug) {\n logger.error('Studio is required to set default game.');\n logger.info(`Either provide ${logger.command('--studio <slug>')} or set a default studio first.`);\n process.exit(1);\n }\n\n const spinner = ora('Verifying game...').start();\n const studios = await getStudios();\n const studio = studios.find(\n (s) => s.slug === studioSlug || s.id === studioSlug || s.name === studioSlug\n );\n\n if (!studio) {\n spinner.fail('Studio not found');\n process.exit(1);\n }\n\n const games = await getGames(studio.id);\n const game = games.find(\n (g) => g.slug === options.game || g.id === options.game || g.name === options.game\n );\n\n if (!game) {\n spinner.fail('Game not found');\n logger.error(`Game \"${options.game}\" not found in studio \"${studio.name}\".`);\n console.log();\n if (games.length > 0) {\n logger.info('Available games:');\n games.forEach((g) => {\n console.log(` ${logger.value(g.slug)} - ${g.name}`);\n });\n } else {\n logger.info('No games in this studio yet.');\n }\n process.exit(1);\n }\n\n spinner.succeed(`Default game set: ${game.name} (${game.slug})`);\n config.defaultGame = game.slug;\n }\n\n // If no options, show current config\n if (!options.studio && !options.game && !options.clear) {\n logger.header('Current Configuration');\n console.log();\n logger.item('Config file', config.path);\n console.log();\n\n const currentStudio = config.defaultStudio;\n const currentGame = config.defaultGame;\n\n if (currentStudio || currentGame) {\n logger.header('Default Upload Target');\n if (currentStudio) {\n logger.item('Studio', currentStudio);\n }\n if (currentGame) {\n logger.item('Game', currentGame);\n }\n console.log();\n logger.info('These defaults are used when --studio/--game are not provided.');\n console.log();\n logger.info(`To change: ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n logger.info(`To clear: ${logger.command('playtagon config --clear')}`);\n } else {\n logger.info('No default studio or game set.');\n console.log();\n logger.info(`Set defaults: ${logger.command('playtagon config --studio <slug> --game <slug>')}`);\n logger.info(`Or run setup: ${logger.command('playtagon setup spine-integration')}`);\n }\n }\n });\n"],"mappings":"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","names":["Command","resolve","resolve","Command","Command","Command","ora","Command","ora","Command","Command","path","ora","fs","path","Command","ora","Command","fs","path","ora","Command","ora","Command","Command","Command","fs","path","ora","Command","ora","pascalCase","Command","fs","path","ora","Command","ora","buildFormData","Command","Command","fs","path","ora","Command","ora","Command","ora","Command","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playtagon/cli",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Playtagon CLI for uploading Spine assets",
5
5
  "type": "module",
6
6
  "bin": {