@enerlence/suntropy-cli 0.11.9 → 0.13.0
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/README.md +81 -1
- package/dist/bin/suntropy.js +1267 -24
- package/dist/bin/suntropy.js.map +1 -1
- package/package.json +1 -1
- package/skills/satvolt-api.md +279 -0
- package/skills/satvolt-campaign.md +228 -0
- package/skills/satvolt-cli.md +185 -0
- package/skills/satvolt-lead-troubleshooting.md +89 -0
- package/skills/satvolt-probe-to-full-campaign.md +185 -0
package/dist/bin/suntropy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/config.ts","../../src/client.ts","../../src/output.ts","../../src/commands/auth.ts","../../src/commands/config/shared.ts","../../src/commands/config/theme.ts","../../src/commands/config/advanced.ts","../../src/commands/config/solarform.ts","../../src/commands/config.ts","../../src/commands/inventory/factory.ts","../../src/commands/inventory/kits.ts","../../src/commands/inventory/manufacturers.ts","../../src/commands/inventory/custom-fields.ts","../../src/commands/inventory/index.ts","../../src/commands/studies/builder.ts","../../node_modules/uuid/dist/esm-node/rng.js","../../node_modules/uuid/dist/esm-node/regex.js","../../node_modules/uuid/dist/esm-node/validate.js","../../node_modules/uuid/dist/esm-node/stringify.js","../../node_modules/uuid/dist/esm-node/v4.js","../../src/commands/studies/index.ts","../../src/commands/curves/index.ts","../../src/commands/consumption/index.ts","../../src/commands/solarform/index.ts","../../src/commands/ppa/index.ts","../../src/commands/shareables/index.ts","../../src/commands/templates/index.ts","../../src/commands/geocode/index.ts","../../src/commands/notifications/index.ts","../../src/access.ts","../../src/commands/command-profile.ts","../../bin/suntropy.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerAuthCommands } from './commands/auth.js';\nimport { registerConfigCommands } from './commands/config.js';\nimport { registerInventoryCommands } from './commands/inventory/index.js';\nimport { registerStudiesCommands } from './commands/studies/index.js';\nimport { registerCurvesCommands } from './commands/curves/index.js';\nimport { registerConsumptionCommands } from './commands/consumption/index.js';\nimport { registerSolarformCommands } from './commands/solarform/index.js';\nimport { registerPPACommands } from './commands/ppa/index.js';\nimport { registerShareableCommands } from './commands/shareables/index.js';\nimport { registerTemplatesCommands } from './commands/templates/index.js';\nimport { registerGeocodeCommands } from './commands/geocode/index.js';\nimport { registerNotificationsCommands } from './commands/notifications/index.js';\nimport { registerCommandProfileCommand } from './commands/command-profile.js';\nimport { applyCommandProfile } from './access.js';\n\n// Injected at build time by tsup (define) from package.json. In dev (tsx, no\n// define) the identifier is undefined, so we fall back without throwing.\ndeclare const __CLI_VERSION__: string;\nconst CLI_VERSION = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : '0.0.0-dev';\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('suntropy')\n .description('Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.')\n .version(CLI_VERSION)\n .option('--format <format>', 'Output format: json (default), human, csv', 'json')\n .option('--fields <fields>', 'Comma-separated fields to include in output')\n .option('--server <url>', 'Override API server URL')\n .option('--token <jwt>', 'Override authentication token')\n .option('--profile <name>', 'Use a specific config profile')\n .option('--verbose', 'Show HTTP request/response details on stderr')\n .option('--quiet', 'Suppress non-data output')\n .option('--save <file>', 'Save output to file (also writes to stdout)');\n\n registerAuthCommands(program);\n registerConfigCommands(program);\n registerInventoryCommands(program);\n registerStudiesCommands(program);\n registerCurvesCommands(program);\n registerConsumptionCommands(program);\n registerSolarformCommands(program);\n registerPPACommands(program);\n registerShareableCommands(program);\n registerTemplatesCommands(program);\n registerGeocodeCommands(program);\n registerNotificationsCommands(program);\n\n // Hidden admin command to manage the command access profile. Registered last\n // and always exempt from gating, so it can raise/lower the tier from any tier.\n registerCommandProfileCommand(program);\n\n // Gate the command tree by the active permission tier (env > config > default\n // 'delete'). Commands above the tier are pruned: absent from --help and\n // reported as \"unknown command\" when invoked.\n applyCommandProfile(program);\n\n return program;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport interface SuntropyProfile {\n server: string;\n token?: string;\n authMethod?: 'api-key' | 'login';\n email?: string;\n clientUID?: string;\n userUID?: string;\n}\n\nexport interface SuntropyConfig {\n activeProfile: string;\n profiles: Record<string, SuntropyProfile>;\n /**\n * Command access profile (permission tier). Gates which commands are\n * registered/visible. Cumulative: read ⊂ write ⊂ delete. Absent → 'delete'\n * (full access, preserves legacy behavior). Managed via the hidden\n * `command-profile` admin command or the SUNTROPY_COMMAND_PROFILE env var.\n */\n commandProfile?: 'read' | 'write' | 'delete';\n}\n\nconst CONFIG_DIR = join(homedir(), '.suntropy');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\nconst DEFAULT_CONFIG: SuntropyConfig = {\n activeProfile: 'default',\n profiles: {\n default: {\n server: 'https://api.enerlence.com',\n },\n },\n};\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): SuntropyConfig {\n ensureConfigDir();\n if (!existsSync(CONFIG_FILE)) {\n writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));\n return { ...DEFAULT_CONFIG };\n }\n return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));\n}\n\nexport function saveConfig(config: SuntropyConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nexport function getActiveProfile(config: SuntropyConfig, profileOverride?: string): SuntropyProfile {\n const name = profileOverride || config.activeProfile;\n const profile = config.profiles[name];\n if (!profile) {\n throw new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`);\n }\n return profile;\n}\n\nexport function setConfigValue(key: string, value: string, profileName?: string): void {\n const config = loadConfig();\n const name = profileName || config.activeProfile;\n if (!config.profiles[name]) {\n config.profiles[name] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[name] as Record<string, unknown>;\n profile[key] = value;\n saveConfig(config);\n}\n\nexport function getConfigValue(key: string, profileName?: string): unknown {\n const config = loadConfig();\n const profile = getActiveProfile(config, profileName);\n return (profile as Record<string, unknown>)[key];\n}\n\n/** Service path mapping */\nconst SERVICE_PATHS: Record<string, string> = {\n security: '/security',\n solar: '/solar',\n templates: '/templates',\n profiles: '/profiles',\n periods: '/periods',\n notifications: '/notifications',\n};\n\nconst LOCAL_PORTS: Record<string, number> = {\n security: 8080,\n solar: 8086,\n templates: 8090,\n profiles: 8085,\n periods: 8084,\n notifications: 8093,\n};\n\nexport function getServiceUrl(baseServer: string, service: keyof typeof SERVICE_PATHS): string {\n // If baseServer looks like localhost without path, use port-based routing\n if (baseServer.includes('localhost') || baseServer.match(/:\\d+$/)) {\n const port = LOCAL_PORTS[service];\n const host = baseServer.replace(/:\\d+$/, '').replace(/\\/$/, '');\n return `${host}:${port}`;\n }\n // Production: path-based routing\n return `${baseServer.replace(/\\/$/, '')}${SERVICE_PATHS[service]}`;\n}\n","import axios, { AxiosInstance, AxiosError } from 'axios';\nimport { loadConfig, getActiveProfile, getServiceUrl, type SuntropyProfile } from './config.js';\n\nexport interface ClientOptions {\n server?: string;\n token?: string;\n profile?: string;\n verbose?: boolean;\n}\n\nexport interface ApiError {\n error: true;\n status: number;\n message: string;\n details?: unknown;\n}\n\nfunction resolveAuth(opts: ClientOptions): { server: string; token: string } {\n const config = loadConfig();\n const profile = getActiveProfile(config, opts.profile);\n const server = opts.server || profile.server;\n // Auth token resolution order: explicit --token flag > SUNTROPY_API_KEY env var > stored profile token.\n // The env var fallback lets host runtimes (e.g. ShellPilot) inject a just-in-time credential\n // without requiring a prior `auth login` / `auth set-key` to write the config file.\n const token = opts.token || process.env.SUNTROPY_API_KEY || profile.token;\n if (!token) {\n throw new Error('Not authenticated. Run: suntropy auth set-key --key <jwt> or suntropy auth login, or set the SUNTROPY_API_KEY env var.');\n }\n return { server, token };\n}\n\nexport function createServiceClient(service: 'security' | 'solar' | 'templates' | 'profiles' | 'periods' | 'notifications', opts: ClientOptions): AxiosInstance {\n const { server, token } = resolveAuth(opts);\n const baseURL = getServiceUrl(server, service);\n\n const client = axios.create({\n baseURL,\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (opts.verbose) {\n client.interceptors.request.use((req) => {\n process.stderr.write(`→ ${req.method?.toUpperCase()} ${req.baseURL}${req.url}\\n`);\n if (req.data) process.stderr.write(` Body: ${JSON.stringify(req.data).slice(0, 200)}\\n`);\n return req;\n });\n client.interceptors.response.use(\n (res) => {\n process.stderr.write(`← ${res.status} (${JSON.stringify(res.data).length} bytes)\\n`);\n return res;\n },\n (err: AxiosError) => {\n process.stderr.write(`← ERROR ${err.response?.status || 'NETWORK'}: ${err.message}\\n`);\n return Promise.reject(err);\n },\n );\n }\n\n return client;\n}\n\n/** Unauthenticated client for login */\nexport function createUnauthClient(baseURL: string): AxiosInstance {\n return axios.create({\n baseURL,\n timeout: 15000,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/** A MongoDB ObjectId serializes to exactly 24 hexadecimal characters. */\nconst OBJECT_ID_RE = /^[a-f0-9]{24}$/i;\n\n/**\n * Guards a solar-study `_id` argument before it reaches the backend.\n *\n * `GET /solar-study/findById/:_id` runs `solarStudyModel.findOne({ _id })`,\n * which makes Mongoose cast the value to an ObjectId. A non-ObjectId string\n * (e.g. a UUID like a chat/shareable uid) throws a `CastError` server-side and\n * surfaces as an opaque **HTTP 500**, so the caller gets no hint about what\n * went wrong. Every real study `_id` is a 24-hex ObjectId, so we can reject\n * bad ids client-side with an actionable message instead.\n *\n * Throws so the caller's try/catch surfaces it via `outputError` (exit != 0).\n */\nexport function assertStudyObjectId(id: string): string {\n if (OBJECT_ID_RE.test(id)) return id;\n const looksLikeUuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id);\n const hint = looksLikeUuid\n ? `It looks like a UUID (e.g. a chat or shareable uid), not a study _id.`\n : `A study _id is a 24-character hex MongoDB ObjectId.`;\n throw new Error(\n `Invalid study id: \"${id}\". ${hint} ` +\n `Get the correct id from \\`suntropy studies list\\` (the \\`solarStudyId\\` field).`,\n );\n}\n\n/**\n * Validates that an API response body actually contains an entity.\n *\n * The solar backend returns `200` with an EMPTY body when `findById` /\n * `addSolarStudyComment` don't match a document (wrong id, or the id belongs to\n * a different clientUID / environment). Without this guard the CLI either\n * crashes downstream (`'_id' in data`, `data.solarStudyProgress = ...` on `\"\"`)\n * or — worse, for writes — reports `success` even though nothing was saved.\n *\n * Throws a clear, actionable error so the caller's try/catch surfaces it via\n * `outputError` with a non-zero exit code.\n */\nexport function assertFound<T>(data: T, entity: string, id: string): T {\n const isEmptyObject =\n data != null &&\n typeof data === 'object' &&\n !Array.isArray(data) &&\n Object.keys(data as Record<string, unknown>).length === 0;\n if (data == null || typeof data !== 'object' || Array.isArray(data) || isEmptyObject) {\n throw new Error(\n `${entity} not found: ${id}. The backend returned an empty response — ` +\n `verify the id is correct and belongs to your account and environment ` +\n `(the CLI and the app must point to the same backend).`,\n );\n }\n return data;\n}\n\nexport function handleApiError(err: unknown): ApiError {\n if (axios.isAxiosError(err)) {\n const ae = err as AxiosError;\n return {\n error: true,\n status: ae.response?.status || 0,\n message: ae.response?.statusText || ae.message,\n details: ae.response?.data,\n };\n }\n return {\n error: true,\n status: 0,\n message: err instanceof Error ? err.message : String(err),\n };\n}\n","import chalk from 'chalk';\nimport { writeFileSync } from 'fs';\n\nexport type OutputFormat = 'json' | 'human' | 'csv';\n\nexport interface OutputOptions {\n format?: OutputFormat;\n fields?: string;\n quiet?: boolean;\n save?: string;\n}\n\n/** Pick only specified fields from an object */\nfunction pickFields(obj: Record<string, unknown>, fields: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.includes('.')) {\n const parts = f.split('.');\n let val: unknown = obj;\n for (const p of parts) {\n val = val && typeof val === 'object' ? (val as Record<string, unknown>)[p] : undefined;\n }\n result[f] = val;\n } else {\n result[f] = obj[f];\n }\n }\n return result;\n}\n\nfunction applyFieldSelection(data: unknown, fields?: string): unknown {\n if (!fields) return data;\n const fieldList = fields.split(',').map((f) => f.trim());\n if (Array.isArray(data)) {\n return data.map((item) => pickFields(item as Record<string, unknown>, fieldList));\n }\n if (typeof data === 'object' && data !== null) {\n return pickFields(data as Record<string, unknown>, fieldList);\n }\n return data;\n}\n\nfunction formatHumanValue(val: unknown): string {\n if (val === null || val === undefined) return '-';\n if (typeof val === 'object') return JSON.stringify(val);\n return String(val);\n}\n\nfunction formatHuman(data: unknown): string {\n if (Array.isArray(data)) {\n if (data.length === 0) return chalk.dim('(empty)');\n const keys = Object.keys(data[0] as Record<string, unknown>);\n const widths = keys.map((k) => Math.max(k.length, ...data.map((r) => formatHumanValue((r as Record<string, unknown>)[k]).length)));\n const header = keys.map((k, i) => chalk.bold(k.padEnd(widths[i]))).join(' ');\n const rows = data.map((row) =>\n keys.map((k, i) => formatHumanValue((row as Record<string, unknown>)[k]).padEnd(widths[i])).join(' '),\n );\n return [header, keys.map((_, i) => '─'.repeat(widths[i])).join(' '), ...rows].join('\\n');\n }\n if (typeof data === 'object' && data !== null) {\n const entries = Object.entries(data as Record<string, unknown>);\n const maxKey = Math.max(...entries.map(([k]) => k.length));\n return entries.map(([k, v]) => `${chalk.bold(k.padEnd(maxKey))} ${formatHumanValue(v)}`).join('\\n');\n }\n return String(data);\n}\n\nfunction formatCsv(data: unknown): string {\n if (!Array.isArray(data)) {\n if (typeof data === 'object' && data !== null) data = [data];\n else return String(data);\n }\n const arr = data as Record<string, unknown>[];\n if (arr.length === 0) return '';\n const keys = Object.keys(arr[0]);\n const escape = (v: unknown) => {\n const s = v === null || v === undefined ? '' : String(v);\n return s.includes(',') || s.includes('\"') || s.includes('\\n') ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [keys.join(','), ...arr.map((r) => keys.map((k) => escape(r[k])).join(','))].join('\\n');\n}\n\nexport function output(data: unknown, opts: OutputOptions = {}): void {\n const filtered = applyFieldSelection(data, opts.fields);\n let text: string;\n\n switch (opts.format) {\n case 'human':\n text = formatHuman(filtered);\n break;\n case 'csv':\n text = formatCsv(filtered);\n break;\n default:\n text = JSON.stringify(filtered, null, 2);\n }\n\n process.stdout.write(text + '\\n');\n\n if (opts.save) {\n writeFileSync(opts.save, JSON.stringify(filtered, null, 2));\n }\n}\n\nexport function outputError(err: unknown): void {\n if (err && typeof err === 'object' && 'error' in err) {\n // ApiError object — include details\n const apiErr = err as { error: boolean; status?: number; message?: string; details?: unknown };\n const out: Record<string, unknown> = { error: true, message: apiErr.message || 'Unknown error' };\n if (apiErr.status) out.status = apiErr.status;\n if (apiErr.details) out.details = apiErr.details;\n process.stderr.write(JSON.stringify(out) + '\\n');\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(JSON.stringify({ error: true, message: msg }) + '\\n');\n }\n process.exitCode = 1;\n}\n\n/** Wrap paginated response */\nexport function outputPaginated(data: unknown[], total: number, limit: number, offset: number, opts: OutputOptions = {}): void {\n if (opts.format === 'human') {\n const filtered = applyFieldSelection(data, opts.fields);\n const end = Math.min(offset + limit, total);\n process.stdout.write(chalk.dim(`Showing ${offset + 1}-${end} of ${total}\\n\\n`));\n process.stdout.write(formatHuman(filtered) + '\\n');\n } else {\n output({ data: applyFieldSelection(data, opts.fields), total, limit, offset, hasMore: offset + limit < total }, { ...opts, fields: undefined });\n }\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, getActiveProfile, getServiceUrl } from '../config.js';\nimport { createUnauthClient, createServiceClient, handleApiError } from '../client.js';\nimport { output, outputError, type OutputOptions } from '../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command('auth').description('Authentication management');\n\n // --- set-key (preferred for agents) ---\n auth\n .command('set-key')\n .description('Set an API key (JWT) for authentication. Preferred method for agents.')\n .requiredOption('--key <jwt>', 'JWT API key')\n .action(async (opts) => {\n try {\n // --server / --profile are global root options (see createProgram);\n // read them from there instead of redefining them locally, otherwise\n // Commander assigns them to the root and they never reach this action.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n profile.token = opts.key;\n profile.authMethod = 'api-key';\n if (global.server) profile.server = global.server as string;\n\n // Decode JWT to extract clientUID\n try {\n const payload = JSON.parse(Buffer.from(opts.key.split('.')[1], 'base64').toString());\n profile.clientUID = payload.clientUID;\n profile.userUID = payload.userUID;\n } catch {\n // If JWT decode fails, just save the key\n }\n\n saveConfig(config);\n output({ success: true, method: 'api-key', profile: profileName, clientUID: profile.clientUID, server: profile.server }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- login ---\n auth\n .command('login')\n .description('Login with email and password')\n .requiredOption('--email <email>', 'User email')\n .requiredOption('--password <password>', 'User password')\n .action(async (opts) => {\n try {\n // --server / --profile come from the global root options.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n if (global.server) profile.server = global.server as string;\n\n const securityUrl = getServiceUrl(profile.server, 'security');\n const client = createUnauthClient(securityUrl);\n const res = await client.post('/auth/login', { email: opts.email, password: opts.password });\n\n if (res.data?.token?.access_token) {\n profile.token = res.data.token.access_token;\n profile.authMethod = 'login';\n profile.email = opts.email;\n profile.clientUID = res.data.user?.clientUID;\n profile.userUID = res.data.user?.userUID;\n saveConfig(config);\n output({\n success: true,\n method: 'login',\n profile: profileName,\n user: {\n email: res.data.user?.email,\n clientUID: res.data.user?.clientUID,\n userUID: res.data.user?.userUID,\n },\n }, getGlobalOpts(auth));\n } else {\n outputError(new Error(res.data?.errors?.[0]?.message || 'Login failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- status ---\n auth\n .command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profile = getActiveProfile(config, global.profile as string);\n if (!profile.token) {\n output({ authenticated: false, message: 'No token configured' }, getGlobalOpts(auth));\n return;\n }\n\n // Decode JWT to check expiry\n let expiresAt: string | undefined;\n let expired = false;\n try {\n const payload = JSON.parse(Buffer.from(profile.token.split('.')[1], 'base64').toString());\n if (payload.exp) {\n const expDate = new Date(payload.exp * 1000);\n expiresAt = expDate.toISOString();\n expired = expDate < new Date();\n }\n } catch {\n // ignore decode errors\n }\n\n output({\n authenticated: !expired,\n method: profile.authMethod || 'unknown',\n server: profile.server,\n email: profile.email,\n clientUID: profile.clientUID,\n userUID: profile.userUID,\n expiresAt,\n expired,\n }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- refresh ---\n auth\n .command('refresh')\n .description('Refresh the current JWT token')\n .action(async () => {\n try {\n // --profile is a global root option.\n const globalOpts = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (globalOpts.profile as string) || config.activeProfile;\n const client = createServiceClient('security', { ...globalOpts, profile: profileName });\n const res = await client.get('/auth/jwt/refreshToken');\n\n if (res.data?.access_token || res.data?.token?.access_token) {\n const newToken = res.data.access_token || res.data.token.access_token;\n config.profiles[profileName].token = newToken;\n saveConfig(config);\n output({ success: true, message: 'Token refreshed' }, getGlobalOpts(auth));\n } else {\n outputError(new Error('Refresh failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- logout ---\n auth\n .command('logout')\n .description(\n 'Clear stored credentials for the active profile (or --profile). Removes the\\n' +\n 'token and account identity but keeps the profile and its server URL.\\n' +\n 'Use --all to log out of every profile.'\n )\n .option('--all', 'Clear credentials for ALL profiles')\n .action(async (opts) => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n\n // Strip credentials/identity from a profile, keep server. Returns\n // whether the profile actually had a token before clearing.\n const clearProfile = (name: string): boolean => {\n const profile = config.profiles[name];\n if (!profile) return false;\n const hadToken = !!profile.token;\n delete profile.token;\n delete profile.authMethod;\n delete profile.email;\n delete profile.clientUID;\n delete profile.userUID;\n return hadToken;\n };\n\n if (opts.all) {\n const names = Object.keys(config.profiles);\n const clearedWithToken = names.filter(clearProfile);\n saveConfig(config);\n output({\n success: true,\n message: `Logged out of ${names.length} profile(s).`,\n profiles: names,\n hadCredentials: clearedWithToken,\n }, global);\n return;\n }\n\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n outputError(new Error(`Profile \"${profileName}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n const hadToken = clearProfile(profileName);\n saveConfig(config);\n output({\n success: true,\n profile: profileName,\n message: hadToken\n ? `Logged out of profile \"${profileName}\". Credentials cleared (server kept).`\n : `Profile \"${profileName}\" had no stored credentials.`,\n }, global);\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync, writeFileSync, unlinkSync } from 'fs';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { spawnSync } from 'child_process';\nimport type { OutputOptions } from '../../output.js';\n\nexport type GlobalOpts = OutputOptions & Record<string, unknown>;\n\n/** Walk up to the root program and return its options. */\nexport function getGlobalOpts(cmd: Command): GlobalOpts {\n let root: Command = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as GlobalOpts;\n}\n\n/** Coerce a string value into boolean / number / JSON when it makes sense. */\nexport function coerceValue(raw: string): unknown {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (raw === 'null') return null;\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10);\n if (/^-?\\d*\\.\\d+$/.test(raw)) return parseFloat(raw);\n if ((raw.startsWith('{') && raw.endsWith('}')) || (raw.startsWith('[') && raw.endsWith(']'))) {\n try { return JSON.parse(raw); } catch { /* fall through to string */ }\n }\n return raw;\n}\n\n/** Parse an array of `--set key=value` entries into a flat object. */\nexport function parseSetFlags(entries: string[] | undefined): Record<string, unknown> {\n if (!entries || entries.length === 0) return {};\n const out: Record<string, unknown> = {};\n for (const entry of entries) {\n const eq = entry.indexOf('=');\n if (eq < 0) throw new Error(`Invalid --set value \"${entry}\" (expected key=value)`);\n const key = entry.slice(0, eq).trim();\n const rawVal = entry.slice(eq + 1);\n if (!key) throw new Error(`Invalid --set value \"${entry}\" (empty key)`);\n out[key] = coerceValue(rawVal);\n }\n return out;\n}\n\n/** Load a JSON file (absolute or relative path). */\nexport function loadFromFile(path: string): Record<string, unknown> {\n const raw = readFileSync(path, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`File ${path} must contain a JSON object at the top level`);\n }\n return parsed as Record<string, unknown>;\n}\n\n/** Pick a subset of keys from an object (shallow). */\nexport function pickKeys<T extends Record<string, unknown>>(obj: T | undefined | null, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!obj) return out;\n for (const k of keys) {\n if (k in obj) out[k] = (obj as Record<string, unknown>)[k];\n }\n return out;\n}\n\n/** Build a merge payload from: --from-file, --set key=value, and direct flag mappings. */\nexport function buildPayload(\n flagValues: Record<string, unknown>,\n setEntries: string[] | undefined,\n fromFile: string | undefined,\n allowedKeys?: readonly string[],\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n if (fromFile) Object.assign(payload, loadFromFile(fromFile));\n if (setEntries) Object.assign(payload, parseSetFlags(setEntries));\n for (const [k, v] of Object.entries(flagValues)) {\n if (v !== undefined) payload[k] = v;\n }\n if (allowedKeys) {\n for (const k of Object.keys(payload)) {\n if (!allowedKeys.includes(k)) {\n throw new Error(`Field \"${k}\" does not belong to this section. Allowed: ${allowedKeys.join(', ')}`);\n }\n }\n }\n return payload;\n}\n\n/** Open $EDITOR (or vi) on a JSON blob and return the parsed result. */\nexport function editJson(initial: unknown, filenameHint = 'config'): Record<string, unknown> {\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi';\n const tmp = join(tmpdir(), `suntropy-${filenameHint}-${Date.now()}.json`);\n writeFileSync(tmp, JSON.stringify(initial ?? {}, null, 2));\n try {\n const res = spawnSync(editor, [tmp], { stdio: 'inherit' });\n if (res.status !== 0) throw new Error(`Editor \"${editor}\" exited with status ${res.status}`);\n const updated = readFileSync(tmp, 'utf-8');\n const parsed = JSON.parse(updated);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Edited content must be a JSON object at the top level');\n }\n return parsed as Record<string, unknown>;\n } finally {\n try { unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\n\n/**\n * Keys accepted by POST /clients/config/updateTheme.\n * Mirrors ClientThemeConfig in backend/security.\n */\nconst THEME_KEYS = [\n 'idClientThemeConfig',\n 'primary',\n 'btnPrimary',\n 'btnSecondary',\n 'background',\n 'navbarBackgroundColor',\n 'graph1', 'graph2', 'graph3', 'graph4', 'graph5', 'graph6',\n 'logoUrl',\n 'faviconUrl',\n 'clientAppTitle',\n 'carouselLinks',\n 'enableCustomTheme',\n] as const;\n\nexport function registerThemeCommands(configRoot: Command): void {\n const theme = configRoot\n .command('theme')\n .description(\n 'Client branding & theme (security service).\\n' +\n 'Colours, logo, favicon and app title applied across Suntropy.\\n' +\n 'Endpoints: GET /clients/config/clientThemeByClientUID/:uid (public)\\n' +\n ' POST /clients/config/updateTheme (requires admin role)\\n\\n' +\n 'Fields:\\n' +\n ' primary, btnPrimary, btnSecondary Core palette (hex).\\n' +\n ' background, navbarBackgroundColor Surface colours.\\n' +\n ' graph1..graph6 Chart palette (6 slots).\\n' +\n ' logoUrl, faviconUrl Asset URLs.\\n' +\n ' clientAppTitle Visible app title.\\n' +\n ' carouselLinks JSON-serialised carousel config.\\n' +\n ' enableCustomTheme Toggles the custom theme on/off.'\n );\n\n theme\n .command('get')\n .description('Fetch the theme of a client (public endpoint, no auth required for reads).')\n .requiredOption('--client-uid <uid>', 'Client UID whose theme should be fetched')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const res = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('set')\n .description(\n 'Update the theme of the authenticated client (requires admin role).\\n' +\n 'Combine individual flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Example:\\n' +\n ' suntropy config theme set --primary \"#0066ff\" --logo-url https://cdn/logo.svg\\n' +\n ' suntropy config theme set --set graph1=#ff0000 --set graph2=#00ff00\\n' +\n ' suntropy config theme set --from-file theme.json'\n )\n .option('--primary <hex>', 'Primary colour')\n .option('--btn-primary <hex>', 'Primary button colour')\n .option('--btn-secondary <hex>', 'Secondary button colour')\n .option('--background <hex>', 'Background colour')\n .option('--navbar-background-color <hex>', 'Navbar background colour')\n .option('--logo-url <url>', 'Logo URL')\n .option('--favicon-url <url>', 'Favicon URL')\n .option('--client-app-title <title>', 'Visible app title')\n .option('--enable-custom-theme [bool]', 'Toggle the custom theme (true/false)')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n\n const flagValues: Record<string, unknown> = {\n primary: opts.primary,\n btnPrimary: opts.btnPrimary,\n btnSecondary: opts.btnSecondary,\n background: opts.background,\n navbarBackgroundColor: opts.navbarBackgroundColor,\n logoUrl: opts.logoUrl,\n faviconUrl: opts.faviconUrl,\n clientAppTitle: opts.clientAppTitle,\n enableCustomTheme: opts.enableCustomTheme === undefined ? undefined : opts.enableCustomTheme === true || opts.enableCustomTheme === 'true',\n };\n\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, THEME_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const res = await client.post('/clients/config/updateTheme', payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('edit')\n .description('Open $EDITOR with the theme JSON and PUT the edited result.')\n .requiredOption('--client-uid <uid>', 'Client UID to fetch the current theme from')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const current = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n const subset = pickKeys(current.data as Record<string, unknown>, THEME_KEYS);\n const edited = editJson(subset, 'theme');\n const res = await client.post('/clients/config/updateTheme', edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { AxiosInstance } from 'axios';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys, coerceValue } from './shared.js';\n\n/** camelCase → kebab-case (\"logoUrl\" → \"logo-url\"). */\nfunction kebab(key: string): string {\n return key.replace(/[A-Z0-9]+/g, (m, i) => (i === 0 ? m.toLowerCase() : '-' + m.toLowerCase()));\n}\n\n/** One category of the advanced panel. */\ninterface Section {\n name: string;\n title: string;\n summary: string;\n fields: readonly string[];\n fieldDocs: Record<string, string>;\n}\n\nconst GENERAL: Section = {\n name: 'general',\n title: 'General configuration (branding, language, tracking, base aesthetics).',\n summary:\n 'Applies to the entire widget: navbar, favicon, global theme, analytics/pixels\\n' +\n 'and page-wide injected scripts. Equivalent to the \"General Configuration\"\\n' +\n 'panel in the Suntropy admin.',\n fields: [\n 'logoUrl', 'faviconUrl', 'tabTitle',\n 'onAddressButtonClick', 'onSendButtonClick',\n 'googleConversionId', 'googleConversionLabelOnAddress', 'googleConversionLabelOnSend',\n 'metaConversionId', 'customTrackingHTML',\n 'defaultLanguage', 'enableLanguageMenu',\n 'customColorOfElements', 'steticVariant', 'themeColor', 'navbarColor',\n 'addNumberToSteps', 'showFooter',\n ],\n fieldDocs: {\n logoUrl: 'Logo displayed in the navbar (and on the cover if includeLogoInCover=true). Empty = no logo.',\n faviconUrl: 'Browser tab favicon.',\n tabTitle: 'Browser tab title (HTML <title>).',\n onAddressButtonClick: 'JavaScript evaluated (eval) when the user hits \"Continue\" on the address step. ⚠ XSS risk; never accept untrusted input.',\n onSendButtonClick: 'JavaScript evaluated (eval) when the final form is submitted. Same XSS risk as above.',\n googleConversionId: 'Google Ads ID; injects gtag.js in <head>.',\n googleConversionLabelOnAddress: 'Google conversion label fired after the address step.',\n googleConversionLabelOnSend: 'Google conversion label fired on submit.',\n metaConversionId: 'Meta/Facebook pixel ID; fires a \"Lead\" event on submit.',\n customTrackingHTML: 'Arbitrary HTML/JS injected in <head> (Hotjar, Mixpanel, GTM…).',\n defaultLanguage: 'Initial language: en|es|fr|it|pt|cat. Falls back to browser pref, then \"en\".',\n enableLanguageMenu: 'Shows the language picker in the navbar. false pins the user to defaultLanguage.',\n customColorOfElements: 'Accent colour for buttons / active borders.',\n steticVariant: 'Visual variant: default (rounded) | sharped (hard corners) | simple (minimalist, no shadows).',\n themeColor: 'Primary colour (navbar, buttons, focus ring). Default #575757.',\n navbarColor: 'Overrides themeColor for the navbar only.',\n addNumberToSteps: 'Prefix step names with their number (\"1. Address\", …).',\n showFooter: 'Pins the footer to the bottom instead of inlining it in the flow.',\n },\n};\n\nconst COVER: Section = {\n name: 'cover',\n title: 'Cover / hero screen shown before the address step.',\n summary: 'Configures the first screen the user sees: title, subtitle, carousel background, colours and logo placement.',\n fields: [\n 'coverTitle', 'coverSubtitle',\n 'coverBackgroundImageUrl1', 'coverBackgroundImageUrl2', 'coverBackgroundImageUrl3', 'coverBackgroundImageUrl4',\n 'staticCoverImages',\n 'coverTextColor', 'coverFilterColor',\n 'includeLogoInCover',\n ],\n fieldDocs: {\n coverTitle: 'Hero title.',\n coverSubtitle: 'Hero subtitle below the title.',\n coverBackgroundImageUrl1: 'Background image #1 (also first frame of the carousel).',\n coverBackgroundImageUrl2: 'Background image #2.',\n coverBackgroundImageUrl3: 'Background image #3.',\n coverBackgroundImageUrl4: 'Background image #4.',\n staticCoverImages: 'true = no rotation (always shows the first image). false = carousel auto-rotates.',\n coverTextColor: 'Colour applied to coverTitle and coverSubtitle.',\n coverFilterColor: 'Overlay colour on top of the image. Default rgba(75,55,30,0.7); improves text contrast.',\n includeLogoInCover: 'true repeats the navbar logo on the cover. false keeps it only in the navbar.',\n },\n};\n\nconst SURFACES: Section = {\n name: 'surfaces',\n title: 'Surfaces step: the map where the user draws the roof polygon(s).',\n summary: 'Controls whether the step runs, how many surfaces are allowed, and the per-device help messages.',\n fields: ['surfaceStepEnabled', 'multipleSurfaces', 'enableMapMarker', 'messageOnDesktopDevices', 'messageOnMobileDevices'],\n fieldDocs: {\n surfaceStepEnabled: 'Enables/disables the whole step. false = the lead is sized without any polygon input.',\n multipleSurfaces: 'Allows drawing more than one roof surface per lead.',\n enableMapMarker: 'Drops a pin on the installation location over the satellite view.',\n messageOnDesktopDevices: 'Instruction text shown on desktop during the step.',\n messageOnMobileDevices: 'Instruction text shown on mobile (e.g. \"Tap to draw\").',\n },\n};\n\nconst CONSUMER: Section = {\n name: 'consumer',\n title: 'Consumer step: residential / commercial / community picker.',\n summary: 'Each subtype has its own visibility flag, image and label. defaultConsumptionPattern feeds the calculation engine.',\n fields: [\n 'consumerStepEnabled',\n 'residentialConsumerTypeEnabled', 'residentialConsumerImageUrl', 'residentialConsumerTitle',\n 'commercialConsumerTypeEnabled', 'commercialConsumerImageUrl', 'commercialConsumerTitle',\n 'communityConsumerTypeEnabled', 'communityConsumerImageUrl', 'communityConsumerTitle',\n 'defaultConsumptionPattern',\n ],\n fieldDocs: {\n consumerStepEnabled: 'Shows/hides the whole step.',\n residentialConsumerTypeEnabled: 'Makes the \"Residential\" option visible.',\n residentialConsumerImageUrl: 'Icon/photo for the Residential option.',\n residentialConsumerTitle: 'Residential label (e.g. \"Home\").',\n commercialConsumerTypeEnabled: 'Makes the \"Commercial\" option visible.',\n commercialConsumerImageUrl: 'Icon/photo for the Commercial option.',\n commercialConsumerTitle: 'Commercial label (e.g. \"Business\").',\n communityConsumerTypeEnabled: 'Makes the \"Community\" option visible.',\n communityConsumerImageUrl: 'Icon/photo for the Community option.',\n communityConsumerTitle: 'Community label.',\n defaultConsumptionPattern: 'Preselected pattern: Balance | Nightly | Morning | Afternoon | Domestic | Commercial | Community. Feeds the hourly curve used by the engine.',\n },\n};\n\nconst INCLINATION: Section = {\n name: 'inclination',\n title: 'Roof inclination step (flat / inclined / very inclined).',\n summary: 'Each variant carries its own image and label. defaultInclination is also used when the step is disabled.',\n fields: [\n 'inclinationStepEnabled',\n 'flatRoofImageUrl', 'textFlatRoof',\n 'inclinedRoofImageUrl', 'textInclinedRoof',\n 'veryInclinedRoofImageUrl', 'textVeryInclinedRoof',\n 'defaultInclination', 'inclinationStepTitle',\n ],\n fieldDocs: {\n inclinationStepEnabled: 'Shows/hides the step. When false, defaultInclination is fed directly into the calculation.',\n flatRoofImageUrl: 'Image for the flat-roof option (0-15°).',\n textFlatRoof: 'Label for flat roof. Default \"0-15°\".',\n inclinedRoofImageUrl: 'Image for the inclined-roof option (15-30°).',\n textInclinedRoof: 'Label for inclined roof. Default \"15-30°\".',\n veryInclinedRoofImageUrl: 'Image for the very-inclined option (>30°).',\n textVeryInclinedRoof: 'Label for very inclined roof. Default \">30°\".',\n defaultInclination: 'Degrees (0-90). Preselected value and fallback when the step is disabled.',\n inclinationStepTitle: 'Title for the step.',\n },\n};\n\nconst ORIENTATION: Section = {\n name: 'orientation',\n title: 'Roof orientation (azimuth) step.',\n summary: 'Directly impacts yield estimates.',\n fields: ['orientationStepEnabled', 'defaultOrientation'],\n fieldDocs: {\n orientationStepEnabled: 'Shows/hides the step. When false, defaultOrientation is fed to the engine.',\n defaultOrientation: 'Degrees 0-360 (0=N, 90=E, 180=S, 270=W).',\n },\n};\n\nconst PANELS: Section = {\n name: 'panels',\n title: 'Solar panel & kit-category selection step.',\n summary: 'Drives which panel + kit category the lead is sized with.',\n fields: ['panelStepEnabled', 'defaultSolarPanel', 'kitCategories', 'defaultKitCategoryId', 'panelSectionTitle', 'panelTitle'],\n fieldDocs: {\n panelStepEnabled: 'Shows/hides the step. When false, the backend uses defaultSolarPanel + defaultKitCategoryId unattended.',\n defaultSolarPanel: 'ID of the preselected SolarPanel (reference to the client inventory).',\n kitCategories: 'Array of kit categories offered to the lead. Each item: { id, name, description, priority }. Use --from-file for multi-item payloads.',\n defaultKitCategoryId: 'ID of the preselected kit category.',\n panelSectionTitle: 'Navbar/breadcrumb label for the panel section.',\n panelTitle: 'Step title.',\n },\n};\n\nconst CONSUMPTION: Section = {\n name: 'consumption',\n title: 'Electric-consumption input step.',\n summary: 'Controls the input mode and display density of the consumption step.',\n fields: ['showOnlyOneConsumptionFieldAtATime', 'defaultConsumptionIntroductionMode'],\n fieldDocs: {\n showOnlyOneConsumptionFieldAtATime: 'true = guided mode (one field per screen). false = all fields visible at once.',\n defaultConsumptionIntroductionMode: 'monthlyConsumption (kWh/month) | monthlySpending (EUR/month). User can toggle if both are enabled.',\n },\n};\n\nconst RESULTS: Section = {\n name: 'results',\n title: 'Results screen, contact form and calculation-engine hooks.',\n summary: 'Largest section: visual layout, form fields for lead capture, confirmation modal, and engine toggles (batteries, PPA, alternative endpoint).',\n fields: [\n 'resultsMode', 'resultsBackgroundImageUrl', 'hideBackgroundImageInResults', 'colorOfBackgroundInResults',\n 'includeLogoInResults', 'includeMapInResults', 'hideResults', 'hideROI', 'formTitle', 'formSubtitle',\n 'resultsWhenSent', 'colorOfResultsPanelBackground',\n 'showDniFieldOnResults', 'showPhonePrefixFieldOnResults', 'showTypeOfDocumentFieldOnResults',\n 'showDniValidationFieldOnResults', 'showPhoneNumberValidationFieldOnResults',\n 'showIdentifierValidationFieldOnResults', 'showSurnameValidationFieldOnResults', 'showTypeOfClientSelectorOnResults',\n 'titleModalOfConfirm', 'textModalOfConfirm',\n 'businessName', 'enablePeakPowerLimitation', 'includeBatteries', 'enabledPPACalculation',\n 'hideCommentField', 'alternativeCalculationEndpoint', 'alternativeCalculationLoadingMessage', 'redirectToShareable',\n ],\n fieldDocs: {\n resultsMode: 'Default (ROI, payback, savings) | SolarResource (irradiance map + technical data).',\n resultsBackgroundImageUrl: 'Background image behind the results panel.',\n hideBackgroundImageInResults: 'Hides the background image even when set.',\n colorOfBackgroundInResults: 'Overlay colour on top of the background image. Default rgba(75,55,30,0.7).',\n colorOfResultsPanelBackground: 'Background of the metrics card. Default rgba(0,0,0,0.5).',\n includeLogoInResults: 'Shows the logo on the results screen.',\n includeMapInResults: 'Shows the interactive map with the drawn panels.',\n hideResults: 'true = no metrics shown, only the contact form.',\n hideROI: 'Hides the payback/ROI widget.',\n formTitle: 'Contact form title.',\n formSubtitle: 'Contact form subtitle.',\n resultsWhenSent: 'true = results shown before submit. false = form must be filled first.',\n showDniFieldOnResults: 'Adds a DNI/CIF input to the form.',\n showPhonePrefixFieldOnResults: 'Adds a phone-prefix selector.',\n showTypeOfDocumentFieldOnResults: 'Adds a document-type selector.',\n showDniValidationFieldOnResults: 'Visual DNI validation (green check).',\n showPhoneNumberValidationFieldOnResults: 'Visual phone validation.',\n showIdentifierValidationFieldOnResults: 'Visual identifier validation.',\n showSurnameValidationFieldOnResults: 'Visual surname validation.',\n showTypeOfClientSelectorOnResults: 'Selector for Individual / Company / Community.',\n titleModalOfConfirm: 'Title of the confirmation modal shown before submit.',\n textModalOfConfirm: 'Body of the confirmation modal.',\n businessName: 'Adds a \"Business name\" field to the form.',\n enablePeakPowerLimitation: 'Adds a peak-power limiter to the consumption section. Affects engine sizing.',\n includeBatteries: 'Includes battery sizing in the results.',\n enabledPPACalculation: 'Enables PPA (Power Purchase Agreement) modelling.',\n hideCommentField: 'Hides the free-text comment field.',\n alternativeCalculationEndpoint: 'URL to which calculation data is POSTed instead of the default engine endpoint. For white-label integrations.',\n alternativeCalculationLoadingMessage: 'Loading text while awaiting the alternative endpoint response.',\n redirectToShareable: 'After calculation, redirect to the shareable-study URL instead of rendering results in-place.',\n },\n};\n\nconst CUSTOM_FIELDS: Section = {\n name: 'custom-fields',\n title: 'Extra lead fields persisted on the SolarStudy (plugin-gated).',\n summary: 'Only available when the client has the \"studyCustomFields\" plugin active.',\n fields: ['solarStudyCustomFields'],\n fieldDocs: {\n solarStudyCustomFields: 'Array of custom-field definitions, serialised. Each item: { id, label, type, required, options? }. Types: text|number|select|boolean. Use --from-file to avoid quoting headaches.',\n },\n};\n\nconst SECTIONS: readonly Section[] = [\n GENERAL, COVER, SURFACES, CONSUMER, INCLINATION, ORIENTATION, PANELS, CONSUMPTION, RESULTS, CUSTOM_FIELDS,\n];\n\nfunction getAdvanced(client: AxiosInstance): Promise<Record<string, unknown>> {\n return client.get('/solar-form/config/advanced').then((r) => r.data as Record<string, unknown>);\n}\n\nfunction putAdvanced(client: AxiosInstance, payload: Record<string, unknown>): Promise<unknown> {\n return client.put('/solar-form/config/advanced', payload).then((r) => r.data);\n}\n\n/** Build a \"Fields:\" help block for a section. */\nfunction formatFieldsHelp(section: Section): string {\n const longest = Math.max(...section.fields.map((f) => f.length));\n return [\n section.title,\n '',\n section.summary,\n '',\n 'Fields:',\n ...section.fields.map((f) => ` ${f.padEnd(longest)} ${section.fieldDocs[f] ?? ''}`),\n '',\n 'Operations: get | set [--set key=value] [--from-file] [--<field> <value>] | edit',\n ].join('\\n');\n}\n\nfunction attachSectionCommand(advanced: Command, section: Section): void {\n const sec = advanced\n .command(section.name)\n .description(formatFieldsHelp(section));\n\n sec\n .command('get')\n .description(`Fetch only the ${section.name} fields of the advanced config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const doc = await getAdvanced(client);\n output(pickKeys(doc, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n const setCmd = sec\n .command('set')\n .description(\n `Update the ${section.name} fields of the advanced config.\\n` +\n 'Combine per-field flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Internally GETs the current config, merges this section, and PUTs the whole thing.'\n )\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file');\n\n for (const field of section.fields) {\n setCmd.option(`--${kebab(field)} <value>`, section.fieldDocs[field] ?? field);\n }\n\n setCmd.action(async (opts) => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {};\n for (const field of section.fields) {\n const val = opts[field];\n if (val !== undefined) flagValues[field] = coerceValue(String(val));\n }\n const partial = buildPayload(flagValues, opts.set, opts.fromFile, section.fields);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const current = await getAdvanced(client);\n const merged = { ...current, ...partial };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n sec\n .command('edit')\n .description(`Open $EDITOR on the ${section.name} subset of the advanced config, then PUT the whole config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const current = await getAdvanced(client);\n const subset = pickKeys(current, section.fields);\n const edited = editJson(subset, `advanced-${section.name}`);\n const merged = { ...current, ...edited };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\nexport function registerAdvancedCommands(solarform: Command): void {\n const advanced = solarform\n .command('advanced')\n .description(\n 'SolarForm Advanced configuration (white-label microsite).\\n' +\n 'Each subcommand maps 1:1 with a section of the admin accordion and with a\\n' +\n 'subset of fields in the AdvancedSolarFormConfig DTO.\\n\\n' +\n 'Whole-payload operations:\\n' +\n ' get Fetch the full advanced config.\\n' +\n ' update Merge a partial payload (--set / --from-file).\\n' +\n ' delete Delete the authenticated client\\'s advanced config.\\n' +\n ' init-default Create the default config for a clientUID (superadmin / localhost).\\n\\n' +\n 'Sections (each: get / set / edit):\\n' +\n SECTIONS.map((s) => ` ${s.name.padEnd(14)} ${s.title}`).join('\\n') + '\\n\\n' +\n 'Conventions:\\n' +\n ' --set <field>=<value> Assign a single field (repeatable).\\n' +\n ' --from-file <path> Load a partial payload from JSON.\\n' +\n ' edit Open $EDITOR on the section\\'s current state.'\n );\n\n advanced\n .command('get')\n .description('Fetch the full AdvancedSolarFormConfig for the authenticated client.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const data = await getAdvanced(client);\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('update')\n .description('Merge a partial AdvancedSolarFormConfig from --set / --from-file and PUT.')\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const partial = buildPayload({}, opts.set, opts.fromFile);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use --set or --from-file.'));\n return;\n }\n const current = await getAdvanced(client);\n const res = await putAdvanced(client, { ...current, ...partial });\n output(res, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('delete')\n .description('Delete the authenticated client\\'s advanced config.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const res = await client.delete('/solar-form/config/advanced');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('init-default')\n .description(\n 'Create the default advanced config for a clientUID.\\n' +\n 'Restricted: requires the \"suntropy-auth: <clientUID>\" header or localhost execution.'\n )\n .requiredOption('--client-uid <uid>', 'Client UID to initialise')\n .option('--email <email>', 'Operator email (optional)')\n .option('--url <url>', 'Site URL (optional)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.email) params.email = opts.email;\n if (opts.url) params.url = opts.url;\n const res = await client.post(\n `/solar-form/config/default/advanced/${opts.clientUid}`,\n {},\n { params, headers: { 'suntropy-auth': opts.clientUid } },\n );\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n for (const section of SECTIONS) attachSectionCommand(advanced, section);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\nimport { registerAdvancedCommands } from './advanced.js';\n\n/** Fields accepted on SolarFormConfig (solar backend). */\nconst SOLARFORM_KEYS = [\n 'idSolarFormConfig',\n 'clientUID',\n 'solarFormUrl',\n 'enabled',\n 'notificationEmailAddress',\n 'confirmationReplytoEmailAdress',\n 'notificationEmailSubject',\n 'enableNotificationEmail',\n 'enableSendConfirmationEmailToClient',\n 'confirmationEmailSubject',\n 'confirmationEmailBody',\n 'enableConfirmationEmailBody',\n 'formTitle',\n 'formSubtitle',\n 'formBackgroundColor',\n 'formBackgroundImageURL',\n 'formFaviconUrl',\n 'locationMode',\n 'hideFinalProjectPrice',\n 'enableRequiredPhoneNumberField',\n 'enableRequiredNameField',\n 'callToActionButtonText',\n 'renderPDF',\n 'defaultSolarStudyTemplateId',\n 'redirectUrl',\n 'privacyPolicy',\n 'advertisingPolicy',\n 'generateShareable',\n 'incentiveTemplateGroup',\n 'disabledSolarForm',\n 'redirectOnClose',\n] as const;\n\nexport function registerSolarformConfigCommands(configRoot: Command): void {\n const solarform = configRoot\n .command('solarform')\n .description(\n 'SolarForm (basic) and SolarForm Advanced configuration (solar service).\\n' +\n 'The basic config controls the public lead-capture form (URL, notifications,\\n' +\n 'appearance, mandatory fields). The advanced subtree configures the modern\\n' +\n 'white-label widget rendered by the \"advanced-solar-form\" microsite.\\n\\n' +\n 'Endpoints:\\n' +\n ' GET /solar-form/get-solar-form-config?getParameters=\\n' +\n ' GET /solar-form/solar-form-config (public, resolved by Origin)\\n' +\n ' POST /solar-form/solar-form-config?getParameters=\\n' +\n ' PUT /solar-form/solar-form-config/:id'\n );\n\n solarform\n .command('get')\n .description('Fetch the current SolarForm configuration for the authenticated client.')\n .option('--with-parameters', 'Include the associated SolarFormParameters in the response')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.get('/solar-form/get-solar-form-config', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('create')\n .description(\n 'Create a new SolarFormConfig for the authenticated client.\\n' +\n '--url is the public slug/URL of the form. Other fields may come from flags,\\n' +\n '--set key=value, or --from-file. Accepted keys:\\n' +\n ' ' + SOLARFORM_KEYS.join(', ')\n )\n .requiredOption('--url <slug>', 'Public URL/slug of the form (solarFormUrl)')\n .option('--enabled [bool]', 'Whether the form is publicly enabled', 'true')\n .option('--form-title <text>', 'Form title displayed to the end user')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--form-background-color <color>', 'Background colour of the form container')\n .option('--form-background-image-url <url>', 'Background image URL')\n .option('--form-favicon-url <url>', 'Favicon URL')\n .option('--call-to-action-button-text <text>', 'Primary CTA button label')\n .option('--notification-email-address <email>', 'Where new lead notifications go')\n .option('--location-mode <mode>', 'fullSurface | locationOnly')\n .option('--with-parameters', 'Include SolarFormParameters in the response')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n solarFormUrl: opts.url,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n formBackgroundColor: opts.formBackgroundColor,\n formBackgroundImageURL: opts.formBackgroundImageUrl,\n formFaviconUrl: opts.formFaviconUrl,\n callToActionButtonText: opts.callToActionButtonText,\n notificationEmailAddress: opts.notificationEmailAddress,\n locationMode: opts.locationMode,\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.post('/solar-form/solar-form-config', payload, { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('update <idSolarFormConfig>')\n .description('Update an existing SolarFormConfig by numeric ID.')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .option('--form-title <text>', 'Form title')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--enabled [bool]', 'Whether the form is publicly enabled')\n .option('--disabled-solar-form [bool]', 'Explicit disable flag')\n .action(async (idSolarFormConfig, opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n disabledSolarForm: opts.disabledSolarForm === undefined ? undefined : opts.disabledSolarForm === true || opts.disabledSolarForm === 'true',\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields to update.'));\n return;\n }\n\n const res = await client.put(`/solar-form/solar-form-config/${idSolarFormConfig}`, payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('edit')\n .description('Fetch the current SolarForm config, open $EDITOR, and PUT the edited result.')\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const current = await client.get('/solar-form/get-solar-form-config');\n const doc = current.data as Record<string, unknown>;\n const id = doc?.idSolarFormConfig;\n if (!id) {\n outputError(new Error('No existing SolarFormConfig found to edit. Use \"create\" first.'));\n return;\n }\n const subset = pickKeys(doc, SOLARFORM_KEYS);\n const edited = editJson(subset, 'solarform');\n const res = await client.put(`/solar-form/solar-form-config/${id}`, edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n registerAdvancedCommands(solarform);\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, setConfigValue, getConfigValue } from '../config.js';\nimport { output, outputError } from '../output.js';\nimport { registerThemeCommands } from './config/theme.js';\nimport { registerSolarformConfigCommands } from './config/solarform.js';\n\nexport function registerConfigCommands(program: Command): void {\n const cfg = program\n .command('config')\n .description(\n 'CLI configuration (profiles, server, token) plus tenant configuration\\n' +\n '(theme & SolarForm / SolarForm Advanced) served by the security and solar backends.'\n );\n\n cfg\n .command('set <key> <value>')\n .description('Set a configuration value. Keys: server, token, activeProfile')\n .option('--profile <name>', 'Profile to modify')\n .action((key, value, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n config.activeProfile = value;\n saveConfig(config);\n } else {\n setConfigValue(key, value, opts.profile);\n }\n output({ success: true, key, value });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('get <key>')\n .description('Get a configuration value')\n .option('--profile <name>', 'Profile to read from')\n .action((key, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n output({ activeProfile: config.activeProfile });\n } else {\n output({ [key]: getConfigValue(key, opts.profile) });\n }\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('list')\n .description('Show all configuration')\n .action(() => {\n try {\n const config = loadConfig();\n // Redact tokens for display\n const safe = JSON.parse(JSON.stringify(config));\n for (const [name, profile] of Object.entries(safe.profiles)) {\n const p = profile as Record<string, unknown>;\n if (p.token) p.token = (p.token as string).slice(0, 20) + '...';\n }\n output(safe);\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('create-profile <name>')\n .description('Create a new profile')\n .option('--server <url>', 'API server URL', 'https://api.enerlence.com')\n .action((name, opts) => {\n try {\n const config = loadConfig();\n if (config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" already exists`));\n return;\n }\n config.profiles[name] = { server: opts.server };\n saveConfig(config);\n output({ success: true, profile: name, server: opts.server });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('use <name>')\n .description('Switch to a profile')\n .action((name) => {\n try {\n const config = loadConfig();\n if (!config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n config.activeProfile = name;\n saveConfig(config);\n output({ success: true, activeProfile: name });\n } catch (err) {\n outputError(err);\n }\n });\n\n registerThemeCommands(cfg);\n registerSolarformConfigCommands(cfg);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\n\nexport interface ResourceConfig {\n /** Command name (e.g. 'panels') */\n name: string;\n /** Singular display name (e.g. 'solar panel') */\n singular: string;\n /** API base path (e.g. '/solar-panels') */\n basePath: string;\n /** ID field name in the entity (e.g. 'solarPanelId') */\n idField: string;\n /** Fields to show in list view (summary) */\n listFields: string[];\n /** POST path for advanced filter, if different from basePath + '/filter' */\n filterPath?: string;\n /** Batch delete path suffix */\n batchDeletePath?: string;\n /** PUT uses body without ID in URL (some endpoints use PUT / with body containing id) */\n putBodyOnly?: boolean;\n /** Backend service */\n service?: 'solar' | 'templates' | 'security';\n /** Custom GET path pattern. Use ':id' as placeholder (e.g. '/custom-asset/id/:id') */\n getPath?: string;\n /** Use POST filter to get by ID (when no GET :id endpoint exists) */\n getViaFilter?: boolean;\n}\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & { server?: string; token?: string; profile?: string; verbose?: boolean } {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n if (data === '-') {\n // Read from stdin - synchronous for simplicity\n const { readFileSync } = require('fs');\n const input = readFileSync(0, 'utf-8');\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function createResourceCommands(cfg: ResourceConfig): Command {\n const cmd = new Command(cfg.name).description(`Manage ${cfg.singular}s`);\n const service = cfg.service || 'solar';\n\n // --- list ---\n cmd\n .command('list')\n .description(`List ${cfg.singular}s with pagination. Fields: ${cfg.listFields.join(', ')}`)\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--active-only', 'Only active items (exclude inactive)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const params: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (!opts.activeOnly) params.unactive = true;\n\n const res = await client.get(cfg.basePath, { params });\n // API may return: [items[], totalCount] tuple, {data: [], total} object, or plain array\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n // Tuple format: [items[], totalCount]\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || [];\n total = res.data?.total ?? data.length;\n }\n\n // Apply list field summary unless user specified --fields\n const outOpts: OutputOptions = { ...global };\n if (!global.fields && cfg.listFields.length > 0) {\n outOpts.fields = [cfg.idField, ...cfg.listFields].join(',');\n }\n\n if (Array.isArray(data)) {\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } else {\n output(data, outOpts);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n cmd\n .command('get <id>')\n .description(`Get a ${cfg.singular} by ID. All fields returned by default.`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n if (cfg.getViaFilter) {\n // No GET :id endpoint — fetch all and filter client-side\n const res = await client.get(cfg.basePath, { params: { unactive: true } });\n const all = Array.isArray(res.data) ? res.data : (Array.isArray(res.data?.[0]) ? res.data[0] : res.data?.data || []);\n const idNum = parseInt(id);\n const item = all.find((r: Record<string, unknown>) => r[cfg.idField] === idNum || r[cfg.idField] === id);\n if (!item) { outputError(new Error(`${cfg.singular} with ${cfg.idField}=${id} not found`)); return; }\n output(item, global);\n } else {\n const url = cfg.getPath ? cfg.getPath.replace(':id', id) : `${cfg.basePath}/${id}`;\n const res = await client.get(url);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n cmd\n .command('create')\n .description(`Create a new ${cfg.singular}. Pass JSON via --data or stdin (--data -)`)\n .requiredOption('--data <json>', 'JSON data (or - for stdin)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n const res = await client.post(cfg.basePath, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n cmd\n .command('update <id>')\n .description(`Update a ${cfg.singular}`)\n .requiredOption('--data <json>', 'JSON data with fields to update (or - for stdin)')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n if (cfg.putBodyOnly) {\n // The id goes in the body for these resources; send it as a number so\n // TypeORM matches the integer primary key on the other side.\n const numericId = Number(id);\n const res = await client.put(cfg.basePath, {\n ...body,\n [cfg.idField]: Number.isFinite(numericId) ? numericId : id,\n });\n output(res.data, global);\n } else {\n const res = await client.put(`${cfg.basePath}/${id}`, body);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n cmd\n .command('delete <id>')\n .description(`Delete a ${cfg.singular}`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const res = await client.delete(`${cfg.basePath}/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete-batch ---\n if (cfg.batchDeletePath) {\n cmd\n .command('delete-batch')\n .description(`Batch delete ${cfg.singular}s`)\n .requiredOption('--ids <ids>', 'Comma-separated IDs')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const ids = opts.ids.split(',').map((s: string) => s.trim());\n const res = await client.post(`${cfg.basePath}/${cfg.batchDeletePath}`, ids);\n output(res.data ?? { success: true, deleted: ids.length }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n }\n\n // --- filter ---\n cmd\n .command('filter')\n .description(`Advanced filter for ${cfg.singular}s. Pass filter query as JSON.`)\n .requiredOption('--query <json>', 'Filter query JSON (or - for stdin)')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const query = parseData(opts.query);\n const filterUrl = cfg.filterPath || `${cfg.basePath}/filter`;\n const res = await client.post(filterUrl, {\n ...query,\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || res.data;\n const total = res.data?.total ?? (Array.isArray(data) ? data.length : 0);\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { createResourceCommands } from './factory.js';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string): Record<string, unknown> {\n if (data === '-') {\n const { readFileSync } = require('fs');\n return JSON.parse(readFileSync(0, 'utf-8'));\n }\n return JSON.parse(data);\n}\n\nexport function registerKitsCommands(inventory: Command): void {\n // Base kit CRUD via factory\n const kits = createResourceCommands({\n name: 'kits',\n singular: 'solar kit',\n basePath: '/solar-kits',\n idField: 'idSolarKit',\n listFields: ['identifier', 'peakPower', 'panelNumber', 'inverterNumber', 'price', 'totalPrice', 'phaseNumber', 'active'],\n filterPath: '/solar-kits/filters',\n batchDeletePath: 'delete-batch-solar-kits',\n getViaFilter: true,\n });\n\n // Remove factory-generated 'create' — use 'assemble' instead for safe kit creation\n const kitsCreateIdx = kits.commands.findIndex((c: Command) => c.name() === 'create');\n if (kitsCreateIdx !== -1) kits.commands.splice(kitsCreateIdx, 1);\n\n // --- archive ---\n kits\n .command('archive <kitId>')\n .description('Archive a solar kit (soft-disable)')\n .action(async (kitId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/archive/${kitId}`);\n output(res.data ?? { success: true, archived: kitId }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit panels sub-commands ---\n const kitPanels = kits.command('panels').description('Manage kit solar panels');\n\n kitPanels\n .command('list')\n .description('List all kit solar panels. Fields: idKitSolarPanel, name, manufacturer, peakPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/solar-panels', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('get <id>')\n .description('Get a kit solar panel by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n // Use filter to get by ID since there's no direct GET by ID\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: id });\n const data = Array.isArray(res.data) ? res.data[0] : res.data?.data?.[0] || res.data;\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('create')\n .description('Create a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/solar-panels', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('update <id>')\n .description('Update a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/solar-panels/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('delete <id>')\n .description('Delete a kit solar panel')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/solar-panels/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('featured <kitPanelId>')\n .description('List solar kits that feature this kit panel')\n .action(async (kitPanelId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/solar-panels/findFeaturedSolarKits/${kitPanelId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit inverters sub-commands ---\n const kitInverters = kits.command('inverters').description('Manage kit inverters');\n\n kitInverters\n .command('list')\n .description('List all kit inverters. Fields: idKitInverter, name, manufacturer, nominalPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/inverters', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('create')\n .description('Create a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/inverters', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('update <id>')\n .description('Update a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/inverters/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('delete <id>')\n .description('Delete a kit inverter')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/inverters/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('featured <kitInverterId>')\n .description('List solar kits that feature this kit inverter')\n .action(async (kitInverterId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/inverters/findFeaturedSolarKits/${kitInverterId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit batteries sub-commands ---\n const kitBatteries = kits.command('batteries').description('Manage kit batteries');\n\n kitBatteries\n .command('list')\n .description('List all kit batteries. Fields: idKitBattery, name, manufacturer, capacity, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/batteries', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('create')\n .description('Create a kit battery')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/batteries', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('delete <id>')\n .description('Delete a kit battery')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/batteries/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- assemble: create kit from existing components by ID ---\n kits\n .command('assemble')\n .description(\n 'Assemble a solar kit from existing components by ID.\\n' +\n 'References kit panels, inverters, batteries, and custom assets by their IDs.\\n\\n' +\n 'Custom assets format: --custom-asset <assetId>:<units> (repeatable)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy inventory kits assemble --name \"Kit 5kW\" --panel 123 --inverter 456 --panels-count 12 --price 6500\\n' +\n ' suntropy inventory kits assemble --name \"Kit Premium\" --panel 123 --inverter 456 --battery 789 \\\\\\n' +\n ' --panels-count 12 --inverters-count 1 --batteries-count 1 --peak-power 5.4 --price 8500 \\\\\\n' +\n ' --custom-asset 100:12 --custom-asset 200:1 --phase single_phase'\n )\n .requiredOption('--name <identifier>', 'Kit name/identifier')\n .option('--panel <kitPanelId>', 'Kit panel ID (idKitSolarPanel)')\n .option('--inverter <kitInverterId>', 'Kit inverter ID (idKitInverter)')\n .option('--battery <batteryId>', 'Battery ID from inventory (batteryId)')\n .option('--panels-count <n>', 'Number of panels', '12')\n .option('--inverters-count <n>', 'Number of inverters', '1')\n .option('--batteries-count <n>', 'Number of batteries', '0')\n .option('--peak-power <kW>', 'Total peak power in kW')\n .requiredOption('--price <eur>', 'Kit price in EUR (required)')\n .option('--phase <type>', 'Phase: single_phase or three_phase', 'single_phase')\n .option('--coplanar', 'Coplanar mounting')\n .option('--taxes <pct>', 'Default tax percentage', '21')\n .option('--custom-asset <id:units>', 'Custom asset as id:units (repeatable)', collectCustomAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n\n // Validate component IDs exist as kit entities before assembling\n const validationErrors: string[] = [];\n\n if (opts.panel) {\n try {\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: parseInt(opts.panel) });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || [];\n if (data.length === 0) {\n validationErrors.push(\n `Panel ID ${opts.panel} is not a KitSolarPanel. ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels, ` +\n `or \"suntropy inventory kits panels create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate panel ID ${opts.panel}. ` +\n `Make sure it is a KitSolarPanel ID (not a regular inventory panel). ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels.`\n );\n }\n }\n\n if (opts.inverter) {\n try {\n const res = await client.get('/solar-kits/inverters', { params: { limit: 200 } });\n const inverters = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = inverters.find((inv: Record<string, unknown>) =>\n String(inv.idKitInverter) === String(opts.inverter)\n );\n if (!found) {\n validationErrors.push(\n `Inverter ID ${opts.inverter} is not a KitInverter. ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters, ` +\n `or \"suntropy inventory kits inverters create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate inverter ID ${opts.inverter}. ` +\n `Make sure it is a KitInverter ID (not a regular inventory inverter). ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters.`\n );\n }\n }\n\n if (opts.battery) {\n try {\n const res = await client.get('/solar-kits/batteries', { params: { limit: 200 } });\n const batteries = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = batteries.find((bat: Record<string, unknown>) =>\n String(bat.idKitBattery) === String(opts.battery)\n );\n if (!found) {\n validationErrors.push(\n `Battery ID ${opts.battery} is not a KitBattery. ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries, ` +\n `or \"suntropy inventory kits batteries create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate battery ID ${opts.battery}. ` +\n `Make sure it is a KitBattery ID (not a regular inventory battery). ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries.`\n );\n }\n }\n\n if (validationErrors.length > 0) {\n outputError({\n error: true,\n message: 'Kit assembly validation failed',\n issues: validationErrors,\n hint: 'The assemble command requires KitSolarPanel, KitInverter, and KitBattery IDs — these are kit-specific entities, not regular inventory items.',\n });\n return;\n }\n\n const body: Record<string, unknown> = {\n identifier: opts.name,\n panelNumber: parseInt(opts.panelsCount),\n inverterNumber: parseInt(opts.invertersCount),\n batteriesNumber: parseInt(opts.batteriesCount),\n phaseNumber: opts.phase,\n defaultTaxesPercentage: parseFloat(opts.taxes),\n active: true,\n };\n\n if (opts.panel) body.kitSolarPanel = { idKitSolarPanel: parseInt(opts.panel) };\n if (opts.inverter) body.kitInverter = { idKitInverter: parseInt(opts.inverter) };\n if (opts.battery) body.battery = { batteryId: parseInt(opts.battery) };\n if (opts.peakPower) body.peakPower = parseFloat(opts.peakPower);\n body.price = parseFloat(opts.price);\n if (opts.coplanar) body.coplanar = true;\n\n if (opts.customAsset && opts.customAsset.length > 0) {\n body.solarKitCustomAssets = opts.customAsset.map((ca: { id: number; units: number }) => ({\n customAsset: { idCustomAsset: ca.id },\n units: ca.units,\n }));\n }\n\n const res = await client.post('/solar-kits', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n inventory.addCommand(kits);\n}\n\n/** Collector for repeatable --custom-asset <id:units> option */\nfunction collectCustomAssets(value: string, previous: { id: number; units: number }[]): { id: number; units: number }[] {\n const [idStr, unitsStr] = value.split(':');\n const id = parseInt(idStr);\n const units = unitsStr ? parseInt(unitsStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid custom asset format: \"${value}\". Use <id>:<units> (e.g. 100:12)`);\n return [...previous, { id, units }];\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerManufacturersCommands(inventory: Command): void {\n const mfr = inventory.command('manufacturers').description('Manage manufacturers (referenced by all inventory devices)');\n\n mfr\n .command('list')\n .description('List all manufacturers. Fields: idManufacturer, name, imageUrl')\n .action(async () => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const res = await client.get('/manufacturers');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n mfr\n .command('create')\n .description('Create a new manufacturer')\n .requiredOption('--data <json>', 'JSON: { \"name\": \"Manufacturer Name\", \"imageUrl\": \"...\" }')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const body = JSON.parse(opts.data);\n const res = await client.post('/manufacturers', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n return JSON.parse(data);\n}\n\nexport function registerCustomFieldsCommands(inventory: Command): void {\n const fields = inventory.command('custom-fields').description(\n 'Manage custom fields for custom asset types.\\n' +\n 'Fields define the schema of a custom asset type (e.g. text, number, options).\\n' +\n 'Types: text, number, date, datetime, time, email, phonenumber, website, options, labels, currency, large_text, user'\n );\n\n // --- list ---\n fields\n .command('list')\n .description('List all custom fields')\n .action(async () => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get('/custom-asset/custom-field/all');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n fields\n .command('get <id>')\n .description('Get a custom field by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/custom-asset/custom-field/id/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n fields\n .command('create')\n .description(\n 'Create a custom field for a custom asset type.\\n' +\n 'Required: label, type, customAssetTypeId\\n' +\n 'For options/labels type, include customFieldOptions array.\\n\\n' +\n 'Example:\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Power\",\"type\":\"number\",\"customAssetTypeId\":1}\\'\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Size\",\"type\":\"options\",\"customAssetTypeId\":1,\"customFieldOptions\":[{\"label\":\"S\",\"value\":\"s\"},{\"label\":\"M\",\"value\":\"m\"},{\"label\":\"L\",\"value\":\"l\"}]}\\''\n )\n .requiredOption('--data <json>', 'Field definition as JSON')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.post('/custom-asset/custom-field', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n fields\n .command('update <id>')\n .description('Update a custom field')\n .requiredOption('--data <json>', 'Updated field data as JSON')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.put(`/custom-asset/custom-field/${id}`, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n fields\n .command('delete <id>')\n .description('Delete a custom field')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/custom-asset/custom-field/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createResourceCommands, type ResourceConfig } from './factory.js';\nimport { registerKitsCommands } from './kits.js';\nimport { registerManufacturersCommands } from './manufacturers.js';\nimport { registerCustomFieldsCommands } from './custom-fields.js';\n\nconst RESOURCES: ResourceConfig[] = [\n {\n name: 'panels',\n singular: 'solar panel',\n basePath: '/solar-panels',\n idField: 'solarPanelId',\n listFields: ['name', 'manufacturer', 'peakPower', 'efficiency', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-panels',\n },\n {\n name: 'inverters',\n singular: 'solar inverter',\n basePath: '/solar-inverter',\n idField: 'idInverter',\n listFields: ['name', 'manufacturer', 'nominalPower', 'efficiency', 'phaseNumber', 'isMicroinverter', 'isHybrid', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-inverters',\n putBodyOnly: true,\n },\n {\n name: 'batteries',\n singular: 'battery',\n basePath: '/solar-battery',\n idField: 'batteryId',\n listFields: ['name', 'manufacturer', 'capacity', 'isModular', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-batteries',\n },\n {\n name: 'chargers',\n singular: 'VE charger',\n basePath: '/charger',\n idField: 'idCharger',\n listFields: ['name', 'manufacturer', 'maxPower', 'connectorType', 'phaseNumber', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-chargers',\n putBodyOnly: true,\n },\n {\n name: 'heatpumps',\n singular: 'heat pump',\n basePath: '/heat-pump',\n idField: 'idHeatpump',\n listFields: ['name', 'manufacturer', 'lowerPower', 'upperPower', 'scop', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-heatpumps',\n putBodyOnly: true,\n },\n {\n name: 'custom-assets',\n singular: 'custom asset',\n basePath: '/custom-asset',\n idField: 'idCustomAsset',\n listFields: ['label', 'customAssetType', 'identifier', 'isMaterial', 'costPerUnit', 'active'],\n getPath: '/custom-asset/id/:id',\n },\n {\n name: 'custom-asset-types',\n singular: 'custom asset type',\n basePath: '/custom-asset/type',\n idField: 'idCustomAssetType',\n listFields: ['label', 'isMaterialConcept', 'panelsQuantity'],\n getPath: '/custom-asset/type/id/:id',\n },\n {\n name: 'charger-kits',\n singular: 'VE charger kit',\n basePath: '/charger/ve-charger-kits',\n idField: 'idVEChargerKit',\n listFields: ['identifier', 'charger', 'price', 'phaseNumber', 'active'],\n filterPath: '/charger/ve-charger-kits/filter',\n batchDeletePath: 'delete-batch-ve-charger-kits',\n putBodyOnly: true,\n },\n {\n name: 'heatpump-kits',\n singular: 'heat pump kit',\n basePath: '/heat-pump/heatpump-kits',\n idField: 'idHeatpumpKit',\n listFields: ['identifier', 'heatpump', 'price', 'phaseNumber', 'active'],\n filterPath: '/heat-pump/heatpump-kits/filter',\n batchDeletePath: 'delete-batch-heatpump-kits',\n putBodyOnly: true,\n },\n];\n\nexport function registerInventoryCommands(program: Command): void {\n const inventory = program.command('inventory').description('Manage inventory: panels, inverters, batteries, chargers, heatpumps, custom-assets, kits');\n\n // Register manufacturer commands (special - simpler CRUD)\n registerManufacturersCommands(inventory);\n\n // Register all standard CRUD resources\n for (const resource of RESOURCES) {\n inventory.addCommand(createResourceCommands(resource));\n }\n\n // Register custom fields (separate CRUD)\n registerCustomFieldsCommands(inventory);\n\n // Register kits (complex - has sub-resources)\n registerKitsCommands(inventory);\n}\n","import { Command, Option } from 'commander';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { v4 } from 'uuid';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\n// ─── Types ───\n\ninterface StepsProgress {\n clientDetails: boolean | undefined;\n consumption: boolean | undefined;\n surfacesSelector: boolean | undefined;\n production: boolean | undefined;\n results: boolean | undefined;\n economicBalance: boolean | undefined;\n}\n\ninterface SolarStudyProgress {\n stepsProgress: StepsProgress;\n stepsUpdates: Record<string, boolean | undefined>;\n editingSolarStudy: boolean;\n lastStateUpdateMomentMS: number;\n}\n\ninterface ByPeriodValues {\n p1?: number;\n p2?: number;\n p3?: number;\n p4?: number;\n p5?: number;\n p6?: number;\n [key: string]: number | undefined;\n}\n\ntype Study = Record<string, unknown>;\n\n// ─── Study defaults (replicates SolarStudy constructor) ───\n\nfunction createDefaultStudy(name?: string): Study {\n const now = new Date();\n const dateStr = now.toISOString().split('T')[0];\n return {\n id: v4(),\n surfaces: undefined,\n clientDetails: {\n identifier: undefined,\n sector: undefined,\n email: undefined,\n cups: undefined,\n phoneNumber: undefined,\n address: undefined,\n instalationLocation: undefined,\n region: undefined,\n subregion: undefined,\n addressCode: undefined,\n dniOrCif: undefined,\n includeTaxes: false,\n taxesPercentage: 0,\n },\n location: undefined,\n atrTariff: undefined,\n geographicalZone: undefined,\n energyPrices: { units: '€/kWh' },\n contractedPower: {},\n powerPrices: { units: '€/kW · dia' },\n results: undefined,\n consumptionIntroductionMode: 'periods',\n peakPowerIntroductionMode: 'solarKit',\n instalationPhaseNumber: 'single_phase',\n peakPowerOptimizationMethod: {\n maxNumberOfOverproductionMonths: 3,\n },\n useAlternativePrices: false,\n economicResults: {\n guaranteeProductionPercentage: 85,\n inflation: 3,\n instalationLifeTime: 25,\n commercialFeePercentage: 85,\n instalationFinancingPercentage: 0,\n taxesPercentage: 21,\n includeTaxes: false,\n margen: 0,\n },\n creationTimestamp: dateStr,\n solarStudyProgress: {\n stepsProgress: {\n clientDetails: undefined,\n consumption: undefined,\n economicBalance: undefined,\n production: undefined,\n results: undefined,\n surfacesSelector: undefined,\n },\n stepsUpdates: {\n clientDetails: false,\n consumption: false,\n economicBalance: false,\n production: false,\n results: false,\n surfacesSelector: false,\n },\n editingSolarStudy: false,\n lastStateUpdateMomentMS: now.getTime(),\n } as SolarStudyProgress,\n activeBatteries: false,\n batteriesConfiguration: {\n initialCapacityPercentage: 100,\n maxCapacityPercentage: 100,\n minCapacityPercentage: 0,\n },\n layout: 'v2',\n lastStateUpdateMomentMS: now.getTime(),\n name: name || `Estudio Solar ${dateStr}`,\n notes: undefined,\n market: 'es',\n };\n}\n\n// ─── Auto-validation engine (replicates frontend step conditions) ───\n\nfunction checkByPeriodCompletion(periodNumber: number, element: ByPeriodValues | undefined): boolean {\n if (!element) return false;\n let assigned = 0;\n for (let i = 1; i <= 6; i++) {\n const val = element['p' + i];\n if (val !== undefined && val !== null && !isNaN(val)) {\n assigned++;\n }\n }\n return assigned >= periodNumber;\n}\n\nfunction evaluateSteps(study: Study): { stepsProgress: StepsProgress; missing: Record<string, string> } {\n const missing: Record<string, string> = {};\n\n // --- clientDetails ---\n const atrTariff = study.atrTariff as { periods?: number } | undefined;\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n const geographicalZone = study.geographicalZone as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const extraCostPrice = study.extraCostPrice as ByPeriodValues | undefined;\n\n let clientDetailsComplete = true;\n if (!atrTariff) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs atrTariff (use: studies set tariff)';\n } else if (!checkByPeriodCompletion(atrTariff.periods || 3, energyPrices)) {\n clientDetailsComplete = false;\n missing.clientDetails = `Needs energyPrices with ${atrTariff.periods || 3} periods filled (use: studies set prices)`;\n } else if (!geographicalZone) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs geographicalZone (use: studies set tariff --zone-id N)';\n } else if (market === 'pt' && !checkByPeriodCompletion(1, extraCostPrice)) {\n clientDetailsComplete = false;\n missing.clientDetails = 'PT market needs extraCostPrice with 1 period (use: studies set prices --extra-cost-p1 N)';\n }\n\n // --- consumption ---\n const consumption = study.consumption as { days?: unknown[] } | undefined;\n const consumptionComplete = !!consumption?.days?.length;\n if (!consumptionComplete) {\n missing.consumption = 'Needs consumption curve (use: studies set consumption)';\n }\n\n // --- surfacesSelector ---\n const surfaces = study.surfaces as unknown[] | undefined;\n const surfacesComplete = !!surfaces?.length;\n if (!surfacesComplete) {\n missing.surfacesSelector = 'Needs at least one surface (use: studies add surface)';\n }\n\n // --- production ---\n // Requires: at least one surface with production curve AND equipment (panel or kit) selected\n const solarPanel = study.solarPanel as Record<string, unknown> | undefined;\n const solarKit = study.solarKit as Record<string, unknown> | undefined;\n const hasEquipment = !!solarPanel || !!solarKit;\n let hasProductionCurve = false;\n if (surfaces && surfaces.length > 0) {\n for (const s of surfaces) {\n const surf = s as { production?: { days?: unknown[] } };\n if (surf.production?.days?.length) {\n hasProductionCurve = true;\n break;\n }\n }\n }\n const productionComplete = hasProductionCurve && hasEquipment;\n if (!productionComplete) {\n const reasons: string[] = [];\n if (!hasEquipment) reasons.push('no panel or kit selected (use: studies set panel or studies set kit)');\n if (!hasProductionCurve) reasons.push('no surface has a production curve (use: studies calculate production)');\n missing.production = reasons.join('; ');\n }\n\n // --- results ---\n const results = study.results as Record<string, unknown> | undefined;\n const resultsComplete = results !== undefined;\n if (!resultsComplete) {\n missing.results = 'Results not calculated (use: studies calculate results)';\n }\n\n // --- economicBalance ---\n const economicResults = study.economicResults as Record<string, unknown> | undefined;\n const economicBalanceComplete =\n economicResults?.margen !== undefined &&\n economicResults?.totalCost !== undefined &&\n results !== undefined;\n if (!economicBalanceComplete) {\n const reasons: string[] = [];\n if (economicResults?.margen === undefined) reasons.push('margen');\n if (economicResults?.totalCost === undefined) reasons.push('totalCost');\n if (!results) reasons.push('results');\n missing.economicBalance = `Needs: ${reasons.join(', ')} (use: studies set economics)`;\n }\n\n return {\n stepsProgress: {\n clientDetails: clientDetailsComplete,\n consumption: consumptionComplete,\n surfacesSelector: surfacesComplete,\n production: productionComplete,\n results: resultsComplete,\n economicBalance: economicBalanceComplete,\n },\n missing,\n };\n}\n\nfunction calculateCompletionPercentage(stepsProgress: StepsProgress): number {\n const completed = Object.values(stepsProgress).filter(Boolean).length;\n return Math.round((completed / 6) * 100);\n}\n\n// ─── Cascade resets ───\n\ntype StepName = keyof StepsProgress;\n\nconst CASCADE_RESETS: Record<string, StepName[]> = {\n consumption: ['production', 'results', 'economicBalance'],\n surfaces: ['production', 'results', 'economicBalance'],\n};\n\nfunction applyCascadeResets(study: Study, changedField: string): string[] {\n const resetSteps = CASCADE_RESETS[changedField];\n if (!resetSteps) return [];\n\n const progress = (study.solarStudyProgress as SolarStudyProgress);\n const resets: string[] = [];\n for (const step of resetSteps) {\n if (progress.stepsProgress[step] !== undefined) {\n progress.stepsProgress[step] = undefined;\n resets.push(step);\n }\n }\n\n // Also clear dependent data for full resets\n if (changedField === 'consumption') {\n // Don't clear surfaces production, only results\n study.results = undefined;\n }\n if (changedField === 'surfaces') {\n study.results = undefined;\n }\n\n return resets;\n}\n\n// ─── File I/O helpers ───\n\nfunction readStudy(filePath: string): Study {\n if (!existsSync(filePath)) {\n throw new Error(`Study file not found: ${filePath}. Use 'studies init --file ${filePath}' to create one.`);\n }\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n}\n\nfunction writeStudy(filePath: string, study: Study): void {\n writeFileSync(filePath, JSON.stringify(study, null, 2), 'utf-8');\n}\n\n/** Read study, apply changes, re-validate, write back, return status */\nfunction updateStudy(\n filePath: string,\n updater: (study: Study) => string | undefined, // returns cascade field name or undefined\n): { stepsProgress: StepsProgress; completionPercentage: number; missing: Record<string, string>; cascadeResets: string[] } {\n const study = readStudy(filePath);\n const cascadeField = updater(study);\n\n // Apply cascade resets\n let cascadeResets: string[] = [];\n if (cascadeField) {\n cascadeResets = applyCascadeResets(study, cascadeField);\n }\n\n // Re-evaluate all steps\n const { stepsProgress, missing } = evaluateSteps(study);\n\n // Update solarStudyProgress\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n study.lastStateUpdateMomentMS = Date.now();\n\n writeStudy(filePath, study);\n\n return {\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n cascadeResets,\n };\n}\n\n/**\n * Spreads a total panel count over the study surfaces, keeping the current\n * proportion between them (equal split when none of them has a count yet).\n * Any remainder from the rounding goes to the largest surface.\n *\n * `--panels-count` used to write the whole figure into `surfaces[0]`, which on a\n * multi-surface study silently added panels instead of setting the total: a\n * 24 + 24 roof asked for 48 ended up with 48 + 24 = 72.\n */\nfunction distributePanels(\n surfaces: Record<string, unknown>[],\n total: number,\n): number[] {\n if (!surfaces.length) return [];\n if (surfaces.length === 1) return [total];\n\n const current = surfaces.map((s) => Number(s.panelNumber) || 0);\n const currentTotal = current.reduce((a, b) => a + b, 0);\n const weights = currentTotal > 0\n ? current.map((n) => n / currentTotal)\n : surfaces.map(() => 1 / surfaces.length);\n\n const counts = weights.map((w) => Math.floor(total * w));\n let remainder = total - counts.reduce((a, b) => a + b, 0);\n\n // Hand the leftovers out one by one, largest surface first.\n const order = counts\n .map((n, i) => ({ n, i }))\n .sort((a, b) => b.n - a.n)\n .map((x) => x.i);\n for (let k = 0; remainder > 0; k = (k + 1) % order.length) {\n counts[order[k]] += 1;\n remainder -= 1;\n }\n\n return counts;\n}\n\n/** Deep merge: target ← source (non-destructive, arrays replaced not merged) */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key of Object.keys(source)) {\n const sv = source[key];\n const tv = target[key];\n if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {\n deepMerge(tv as Record<string, unknown>, sv as Record<string, unknown>);\n } else {\n target[key] = sv;\n }\n }\n}\n\n// ─── CLI helpers ───\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction resolveFile(opts: { file?: string }): string {\n return opts.file || process.env.SUNTROPY_STUDY || './study.json';\n}\n\ntype LatLng = { lat: number; lng: number };\n\n/**\n * Resolve the geographic coordinates used to calculate a surface, in order of\n * preference:\n * 1. surface.center — explicit surface centre (e.g. set by `add surface`)\n * 2. study.location — study-level location\n * 3. polygonPath centroid — average of the drawn polygon vertices\n * 4. polygonPath first point — fallback when the centroid is degenerate\n *\n * A surface drawn in the editor arrives with a full `polygonPath` but no\n * `center`, and studies from that flow may also lack `location`. Deriving the\n * coordinate from the polygon lets those surfaces be calculated instead of\n * failing with \"no coordinates\". Returns null only when no usable point exists.\n */\nexport function resolveSurfaceCoordinates(\n surface: Record<string, unknown>,\n study: Study,\n): LatLng | null {\n const isValid = (c: unknown): c is LatLng => {\n const p = c as LatLng | undefined;\n return !!p && Number.isFinite(p.lat) && Number.isFinite(p.lng);\n };\n\n const center = surface.center as LatLng | undefined;\n if (isValid(center)) return { lat: center.lat, lng: center.lng };\n\n const studyLocation = study.location as LatLng | undefined;\n if (isValid(studyLocation)) return { lat: studyLocation.lat, lng: studyLocation.lng };\n\n const path = surface.polygonPath as Array<{ lat?: number; lng?: number }> | undefined;\n if (Array.isArray(path) && path.length > 0) {\n const points = path.filter(\n (p): p is LatLng => Number.isFinite(p?.lat) && Number.isFinite(p?.lng),\n );\n if (points.length > 0) {\n // Centroid: average of the polygon vertices.\n const sum = points.reduce(\n (acc, p): LatLng => ({ lat: acc.lat + p.lat, lng: acc.lng + p.lng }),\n { lat: 0, lng: 0 },\n );\n const centroid = { lat: sum.lat / points.length, lng: sum.lng / points.length };\n if (isValid(centroid)) return centroid;\n // Fallback: first valid point of the path.\n return { lat: points[0].lat, lng: points[0].lng };\n }\n }\n\n return null;\n}\n\n/**\n * Installed DC power (Watts) sent to `/solar-study/calculateProduction` for a\n * surface, replicating the frontend `generateCalculateProductionDto`:\n *\n * installedPower = (panelsLayoutPolygons?.length ?? panelNumber) * panelPeakPower\n *\n * The panel peak power comes from `study.solarPanel.peakPower` — kit mode also\n * populates `solarPanel` from `solarKit.kitSolarPanel`, so both peak-power modes\n * resolve. An explicit `surface.installedPower` (e.g. from `add surface --power`)\n * takes precedence. The old code read only `surface.installedPower || 5000`, a\n * field the frontend never sets, so studies built in the UI were silently\n * calculated for the 5000 W (5 kWp) default.\n *\n * Returns `isDefault: true` when it had to fall back to 5000 W so the caller can\n * warn instead of emitting wrong production numbers silently.\n */\nexport function resolveSurfaceInstalledPower(\n surface: Record<string, unknown>,\n study: Study,\n): { installedPower: number; isDefault: boolean } {\n const explicit = surface.installedPower as number | undefined;\n if (Number.isFinite(explicit) && (explicit as number) > 0) {\n return { installedPower: explicit as number, isDefault: false };\n }\n\n const solarPanel = study.solarPanel as { peakPower?: number } | undefined;\n const kitPanel = (study.solarKit as { kitSolarPanel?: { peakPower?: number } } | undefined)?.kitSolarPanel;\n const panelPeakPower = (solarPanel?.peakPower as number) || (kitPanel?.peakPower as number) || undefined;\n\n // Frontend precedence: drawn panel layout length, else surface.panelNumber.\n const layout = surface.panelsLayoutPolygons as unknown[] | undefined;\n const panelCount = layout !== undefined\n ? (layout.length || 0)\n : (surface.panelNumber as number | undefined);\n\n if (panelPeakPower && Number.isFinite(panelCount) && (panelCount as number) > 0) {\n return { installedPower: (panelCount as number) * panelPeakPower, isDefault: false };\n }\n\n return { installedPower: 5000, isDefault: true };\n}\n\n// ─── Register commands ───\n\nexport function registerStudyBuilderCommands(studies: Command): void {\n\n // ═══════════════════════════════════════════\n // INIT\n // ═══════════════════════════════════════════\n studies\n .command('init')\n .description(\n 'Create a new study workspace (local JSON file with defaults).\\n' +\n 'Example: suntropy studies init --file /tmp/study.json --name \"Residencial 5kW\"'\n )\n .option('--file <path>', 'Output file path (default: ./study.json)')\n .option('--name <studyName>', 'Study name')\n .option('--market <code>', 'Market country: es, pt, it, fr, de, etc.', 'es')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const study = createDefaultStudy(opts.name);\n if (opts.market) study.market = opts.market;\n writeStudy(filePath, study);\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n file: filePath,\n id: study.id,\n name: study.name,\n stepsProgress,\n completionPercentage: 0,\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // VALIDATE\n // ═══════════════════════════════════════════\n studies\n .command('validate')\n .description(\n 'Check completion status of all study steps.\\n' +\n 'Returns stepsProgress, completionPercentage, and what is missing for each incomplete step.'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const study = readStudy(resolveFile(opts));\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // SAVE\n // ═══════════════════════════════════════════\n studies\n .command('save')\n .description(\n 'Save study to the backend (POST /solar-study).\\n' +\n 'If the study has _id, it updates the existing study. Otherwise creates new.\\n' +\n 'Example: suntropy studies save --file /tmp/study.json --state-id 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--state-id <n>', 'Solar study metadata state ID')\n .option('--credit-amount <n>', 'Credit amount to consume')\n .option('--save-as-new', 'Force save as new study (even if _id exists)')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const study = readStudy(filePath);\n\n // Re-validate before saving\n const { stepsProgress } = evaluateSteps(study);\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n\n // Auto-add comment like frontend SaveStudyModal\n const isEditing = progress.editingSolarStudy || !!study._id;\n const comments = (study.comments || []) as Record<string, unknown>[];\n const commentType = opts.saveAsNew ? 'duplicated' : (isEditing ? 'modified' : 'created');\n comments.push(createComment(commentType));\n study.comments = comments;\n\n if (opts.saveAsNew) {\n delete study._id;\n }\n\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.stateId) params.idSolarStudyState = opts.stateId;\n if (opts.creditAmount) params.creditAmount = opts.creditAmount;\n if (opts.saveAsNew) params.saveAsNew = 'true';\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const url = `/solar-study${queryString ? '?' + queryString : ''}`;\n\n const res = await client.post(url, study);\n\n // If response contains _id or solarStudyId, update local file\n const responseData = res.data as Record<string, unknown>;\n if (responseData?.solarStudyId) {\n study._id = responseData.solarStudyId as string;\n progress.editingSolarStudy = true;\n writeStudy(filePath, study);\n }\n\n output({\n saved: true,\n metadata: responseData,\n file: filePath,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // PULL\n // ═══════════════════════════════════════════\n studies\n .command('pull <studyId>')\n .description(\n 'Download an existing study from the backend into a local file.\\n' +\n 'Example: suntropy studies pull abc123 --file /tmp/study.json'\n )\n .option('--file <path>', 'Output file path')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Study;\n\n // Re-validate\n const { stepsProgress, missing } = evaluateSteps(study);\n const progress = (study.solarStudyProgress || {}) as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.editingSolarStudy = true;\n study.solarStudyProgress = progress;\n\n writeStudy(filePath, study);\n output({\n file: filePath,\n _id: study._id,\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // SET — parent command for all sub-commands\n // ═══════════════════════════════════════════\n const set = studies.command('set').description('Set study properties. Each sub-command auto-validates after changes.');\n\n // --- set name ---\n set\n .command('name')\n .description('Set the study name')\n .option('--file <path>', 'Study file path')\n .requiredOption('--name <studyName>', 'Study name')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.name = opts.name;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set market ---\n set\n .command('market')\n .description('Set the market country code (es, pt, it, fr, de, etc.)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--market <code>', 'Market country code')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.market = opts.market;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set client ---\n set\n .command('client')\n .description(\n 'Set client details (name, email, phone, cups, address, etc.)\\n' +\n 'Example: suntropy studies set client --file study.json --name \"Juan García\" --email j@co.com --cups ES001234'\n )\n .option('--file <path>', 'Study file path')\n .option('--name <clientName>', 'Client name (identifier/razón social)')\n .option('--email <email>', 'Client email')\n .option('--phone <phone>', 'Phone number')\n .option('--cups <cups>', 'CUPS code')\n .option('--address <addr>', 'Address')\n .option('--city <city>', 'City')\n .option('--region <region>', 'Region (comunidad autónoma)')\n .option('--subregion <subregion>', 'Subregion (provincia)')\n .option('--dni <dni>', 'DNI or CIF')\n .option('--sector <sector>', 'Client sector')\n .option('--installation-location <loc>', 'Installation location description')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const cd = (study.clientDetails || {}) as Record<string, unknown>;\n if (opts.name) cd.identifier = opts.name;\n if (opts.email) cd.email = opts.email;\n if (opts.phone) cd.phoneNumber = opts.phone;\n if (opts.cups) cd.cups = opts.cups;\n if (opts.address) cd.address = opts.address;\n if (opts.city) cd.city = opts.city;\n if (opts.region) cd.region = opts.region;\n if (opts.subregion) cd.subregion = opts.subregion;\n if (opts.dni) cd.dniOrCif = opts.dni;\n if (opts.sector) cd.sector = opts.sector;\n if (opts.installationLocation) cd.instalationLocation = opts.installationLocation;\n study.clientDetails = cd;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set tariff ---\n set\n .command('tariff')\n .description(\n 'Set ATR tariff and geographical zone. Auto-sets phase (>3 periods → three_phase).\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD (3 periods), 14=3.0TD (6 periods)\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n' +\n 'Example: suntropy studies set tariff --file study.json --tariff-id 13 --zone-id 1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--tariff-id <n>', 'ATR tariff ID')\n .option('--zone-id <n>', 'Geographical zone ID', '1')\n .option('--market <code>', 'Market code for tariff lookup', 'es')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('periods', global);\n\n // Fetch tariff info\n const tariffRes = await client.get('/tarifas-atr', {\n params: { market: opts.market },\n });\n const tariffs = (Array.isArray(tariffRes.data) ? tariffRes.data : tariffRes.data?.data || []) as Record<string, unknown>[];\n const tariffId = parseInt(opts.tariffId);\n const tariff = tariffs.find((t) => t.idTarifaATR === tariffId);\n if (!tariff) {\n outputError(new Error(`Tariff ID ${tariffId} not found. Available: ${tariffs.map((t) => `${t.idTarifaATR}=${t.nombre}`).join(', ')}`));\n return;\n }\n\n // Fetch zone info\n const zoneRes = await client.get('/zonas', {\n params: { market: opts.market },\n });\n const zones = (Array.isArray(zoneRes.data) ? zoneRes.data : zoneRes.data?.data || []) as Record<string, unknown>[];\n const zoneId = parseInt(opts.zoneId);\n const zone = zones.find((z) => z.idZona === zoneId);\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.atrTariff = tariff;\n if (zone) study.geographicalZone = zone;\n\n // Auto-set phase based on tariff periods (replicates frontend logic)\n const periods = (tariff.periods as number) || 3;\n study.instalationPhaseNumber = periods > 3 ? 'three_phase' : 'single_phase';\n\n return undefined; // no cascade reset for tariff change\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set prices ---\n set\n .command('prices')\n .description(\n 'Set energy prices by period.\\n' +\n 'Examples:\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,\"p2\":0.08,\"p3\":0.06}\\'\\n' +\n ' suntropy studies set prices --file study.json --energy-p1 0.15 --energy-p2 0.08 --energy-p3 0.06\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,...}\\' --power \\'{\"p1\":40,...}\\' --contracted \\'{\"p1\":5.5,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--energy <json>', 'Energy prices JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--energy-p1 <n>', 'Energy price period 1 (€/kWh)')\n .option('--energy-p2 <n>', 'Energy price period 2 (€/kWh)')\n .option('--energy-p3 <n>', 'Energy price period 3 (€/kWh)')\n .option('--energy-p4 <n>', 'Energy price period 4 (€/kWh)')\n .option('--energy-p5 <n>', 'Energy price period 5 (€/kWh)')\n .option('--energy-p6 <n>', 'Energy price period 6 (€/kWh)')\n .option('--power <json>', 'Power prices JSON: {\"p1\":N,\"p2\":N,...} (€/kW·day)')\n .option('--contracted <json>', 'Contracted power JSON: {\"p1\":N,\"p2\":N,...} (kW)')\n .option('--extra-cost-p1 <n>', 'Extra cost price P1 (Portugal market)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n // Energy prices: from JSON or individual flags\n const ep = (study.energyPrices || { units: '€/kWh' }) as Record<string, unknown>;\n if (opts.energy) {\n const parsed = JSON.parse(opts.energy);\n Object.assign(ep, parsed);\n }\n for (let i = 1; i <= 6; i++) {\n const val = opts[`energyP${i}`];\n if (val !== undefined) ep[`p${i}`] = parseFloat(val);\n }\n study.energyPrices = ep;\n\n // Power prices\n if (opts.power) {\n const pp = (study.powerPrices || { units: '€/kW · dia' }) as Record<string, unknown>;\n Object.assign(pp, JSON.parse(opts.power));\n study.powerPrices = pp;\n }\n\n // Contracted power\n if (opts.contracted) {\n const cp = (study.contractedPower || {}) as Record<string, unknown>;\n Object.assign(cp, JSON.parse(opts.contracted));\n study.contractedPower = cp;\n }\n\n // Extra cost (Portugal)\n if (opts.extraCostP1 !== undefined) {\n study.extraCostPrice = { p1: parseFloat(opts.extraCostP1), units: '€/kWh' };\n }\n\n return undefined; // no cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set consumption ---\n set\n .command('consumption')\n .description(\n 'Set the consumption curve.\\n' +\n 'Modes:\\n' +\n ' --from-file <path> Load PowerCurve from JSON file\\n' +\n ' --annual + --pattern Generate via consumption-estimation API\\n' +\n ' --by-period <json> Period consumption: {\"p1\":N,\"p2\":N,\"p3\":N} + REE profile\\n' +\n ' --monthly <json> Monthly consumption: {\"1\":N,\"2\":N,...,\"12\":N} + REE profile\\n' +\n ' --monthly-by-period Monthly by period: {\"1\":{\"p1\":N,\"p2\":N},...} + REE profile\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies set consumption --file study.json --from-file /tmp/cons.json\\n' +\n ' suntropy studies set consumption --file study.json --annual 4000 --pattern Balance\\n' +\n ' suntropy studies set consumption --file study.json --by-period \\'{\"p1\":2500,\"p2\":1000,\"p3\":500}\\'\\n' +\n ' suntropy studies set consumption --file study.json --monthly \\'{\"1\":350,\"2\":320,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--from-file <curvePath>', 'Load PowerCurve from JSON file')\n .option('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--by-period <json>', 'Period consumption JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--monthly <json>', 'Monthly consumption JSON: {\"1\":N,...,\"12\":N}')\n .option('--monthly-by-period <json>', 'Monthly by period: {\"1\":{\"p1\":N,...},...}')\n .option('--tariff <code>', 'Tariff code for profile lookup (default: from study)')\n .option('--market <code>', 'Market code (default: from study)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const studyTariff = (study.atrTariff as Record<string, unknown>)?.nombre as string || '3.0TD';\n const studyMarket = (study.market as string) || 'es';\n const tariff = opts.tariff || studyTariff;\n const market = opts.market || studyMarket;\n const year = new Date().getFullYear();\n\n let curveData: unknown;\n let introductionMode: string;\n\n if (opts.fromFile) {\n // Load from file\n curveData = JSON.parse(readFileSync(opts.fromFile, 'utf-8'));\n introductionMode = 'upload';\n\n } else if (opts.annual && opts.pattern) {\n // Generate via backend /consumption-estimation\n const profilesClient = createServiceClient('profiles', global);\n const params: Record<string, string> = {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n anualConsumption: opts.annual,\n market,\n consumptionType: opts.pattern,\n };\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const res = await profilesClient.post(`/consumption-estimation?${queryString}`, {});\n curveData = res.data;\n introductionMode = 'consumption_patterns';\n\n } else if (opts.byPeriod) {\n // Fetch REE profile + period distribution, apply locally\n const periodValues = JSON.parse(opts.byPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'CONSUMPTION_BY_PERIOD', periodValues);\n introductionMode = 'periods';\n\n } else if (opts.monthly) {\n // Fetch REE profile, apply monthly consumption\n const monthValues = JSON.parse(opts.monthly);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTH_CONSUMPTION', monthValues);\n introductionMode = 'monthly_consumption';\n\n } else if (opts.monthlyByPeriod) {\n // Complex: monthly by period\n const monthPeriodValues = JSON.parse(opts.monthlyByPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTHLY_BY_PERIOD', monthPeriodValues);\n introductionMode = 'monthly_periods';\n\n } else {\n outputError(new Error('Specify one of: --from-file, --annual + --pattern, --by-period, --monthly, --monthly-by-period'));\n return;\n }\n\n // Update study with consumption\n const result = updateStudy(filePath, (s) => {\n s.consumption = curveData;\n s.consumptionIntroductionMode = introductionMode;\n if (opts.annual) s.monthlyConsumption = parseFloat(opts.annual) / 12;\n if (opts.pattern) s.selectedConsumptionPattern = opts.pattern;\n if (opts.byPeriod) s.periodConsumptionDictionary = JSON.parse(opts.byPeriod);\n if (opts.monthly) s.monthConsumptionDictionary = JSON.parse(opts.monthly);\n if (opts.monthlyByPeriod) s.monthPeriodConsumptionDictionary = JSON.parse(opts.monthlyByPeriod);\n return 'consumption'; // trigger cascade\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- add surface ---\n studies\n .command('add')\n .description('Add elements to the study')\n .command('surface')\n .description(\n 'Add a solar surface to the study.\\n' +\n 'Example: suntropy studies add surface --file study.json --lat 37.39 --lon -5.99 --angle 30 --azimuth 180 --power 5000'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel azimuth degrees (0=N, 180=S)', '180')\n .option('--power <w>', 'Installed power in Watts')\n .option('--panels-count <n>', 'Number of panels')\n .option('--production <file>', 'Production PowerCurve JSON file to attach')\n .option('--identifier <name>', 'Surface name/identifier')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const lat = parseFloat(opts.lat);\n const lng = parseFloat(opts.lon);\n const surface: Record<string, unknown> = {\n surfaceId: v4(),\n name: opts.identifier || `Surface ${((study.surfaces as unknown[])?.length || 0) + 1}`,\n inclination: parseFloat(opts.angle),\n orientation: parseFloat(opts.azimuth),\n panelInclination: parseFloat(opts.angle),\n panelOrientation: parseFloat(opts.azimuth),\n lossesPercentage: 14,\n // polygonPath required by backend metadata constructor\n polygonPath: [{ lat, lng }],\n };\n if (opts.power) surface.installedPower = parseFloat(opts.power);\n if (opts.panelsCount) surface.panelNumber = parseInt(opts.panelsCount);\n if (opts.production) {\n surface.production = JSON.parse(readFileSync(opts.production, 'utf-8'));\n }\n\n // Also set study-level location\n study.location = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n study.mapCenter = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n\n const surfaces = (study.surfaces as unknown[]) || [];\n surfaces.push(surface);\n study.surfaces = surfaces;\n\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- remove surface ---\n studies\n .command('remove')\n .description('Remove elements from the study')\n .command('surface')\n .description('Remove a surface by index')\n .option('--file <path>', 'Study file path')\n .requiredOption('--index <n>', 'Surface index (0-based)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const surfaces = (study.surfaces as unknown[]) || [];\n const idx = parseInt(opts.index);\n if (idx < 0 || idx >= surfaces.length) {\n throw new Error(`Surface index ${idx} out of range (0-${surfaces.length - 1})`);\n }\n surfaces.splice(idx, 1);\n study.surfaces = surfaces.length > 0 ? surfaces : undefined;\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set panel ---\n set\n .command('panel')\n .description(\n 'Set solar panel for the study. Auto-sets peakPowerIntroductionMode to \"solarPanel\".\\n' +\n 'Fetches full panel data from inventory.\\n' +\n '--panels-count is the TOTAL for the study: it is spread over the surfaces keeping\\n' +\n 'their current proportion (use --surface-index to target a single surface).\\n' +\n 'The response lists the resulting panelNumber per surface.\\n' +\n 'Example: suntropy studies set panel --file study.json --panel-id 456 --panels-count 12'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--panel-id <n>', 'Solar panel ID from inventory')\n .option('--panels-count <n>', 'TOTAL number of panels of the study, spread over its surfaces keeping their current proportion')\n .option('--surface-index <n>', 'Apply --panels-count to this surface only (0-based) instead of spreading it')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full panel data\n const panelRes = await solarClient.get(`/solar-panels/${opts.panelId}`);\n const panel = panelRes.data;\n\n let distribution: { surfaceIndex: number; panelNumber: number }[] = [];\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarPanel = panel;\n study.peakPowerIntroductionMode = 'solarPanel';\n // Clear kit when switching to panel mode\n study.solarKit = undefined;\n if (opts.panelsCount) {\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n const total = parseInt(opts.panelsCount);\n if (surfaces?.length) {\n if (opts.surfaceIndex !== undefined) {\n const idx = parseInt(opts.surfaceIndex);\n if (!Number.isInteger(idx) || idx < 0 || idx >= surfaces.length) {\n throw new Error(\n `--surface-index ${opts.surfaceIndex} is out of range: the study has ${surfaces.length} surface(s)`\n );\n }\n surfaces[idx].panelNumber = total;\n } else {\n const counts = distributePanels(surfaces, total);\n surfaces.forEach((surface, i) => { surface.panelNumber = counts[i]; });\n }\n distribution = surfaces.map((surface, i) => ({\n surfaceIndex: i,\n panelNumber: Number(surface.panelNumber) || 0,\n }));\n }\n }\n return undefined;\n });\n // Report what each surface ended up with: a caller that assumes the\n // total landed where it asked would otherwise misreport the peak power.\n output(distribution.length ? { ...result, surfaces: distribution } : result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set kit ---\n set\n .command('kit')\n .description(\n 'Set solar kit for the study. Auto-sets peakPowerIntroductionMode to \"solarKit\".\\n' +\n 'Fetches full kit data from inventory.\\n' +\n 'Example: suntropy studies set kit --file study.json --kit-id 123'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--kit-id <n>', 'Solar kit ID from inventory')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Kits use getViaFilter (no GET /:id)\n const kitsRes = await solarClient.get('/solar-kits', { params: { unactive: true } });\n const allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n const kitId = parseInt(opts.kitId);\n const kit = allKits.find((k: Record<string, unknown>) => k.idSolarKit === kitId);\n if (!kit) {\n outputError(new Error(`Kit ${kitId} not found`));\n return;\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarKit = kit;\n study.peakPowerIntroductionMode = 'solarKit';\n // Clear panel + inverters when switching to kit mode\n study.solarPanel = undefined;\n study.solarInverters = undefined;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set inverter ---\n set\n .command('inverter')\n .description(\n 'Set inverter(s) for the study (when using solarPanel mode).\\n' +\n 'REPLACES the whole list: pass every inverter of the installation, comma-separated,\\n' +\n 'repeating an id as many times as units there are. The response reports how many\\n' +\n 'were there before and how many are there now.\\n' +\n 'Example: suntropy studies set inverter --file study.json --inverter-id 789,789'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--inverter-id <ids>', 'Inverter ID(s), comma-separated for multiple')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n const ids = opts.inverterId.split(',').map((s: string) => parseInt(s.trim()));\n\n const inverters: unknown[] = [];\n for (const id of ids) {\n const res = await solarClient.get(`/solar-inverter/${id}`);\n inverters.push(res.data);\n }\n\n let previousCount = 0;\n const result = updateStudy(resolveFile(opts), (study) => {\n previousCount = (study.solarInverters as unknown[] | undefined)?.length ?? 0;\n study.solarInverters = inverters;\n return undefined;\n });\n // The list is replaced, not appended: say so, because dropping units\n // silently undersizes the installation and its budget.\n output({ ...result, inverters: { before: previousCount, after: inverters.length } }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set phase ---\n set\n .command('phase')\n .description('Manually set installation phase (overrides auto-set from tariff)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--phase <type>', 'Phase: single_phase or three_phase')\n .action(async (opts) => {\n try {\n if (!['single_phase', 'three_phase'].includes(opts.phase)) {\n outputError(new Error('Phase must be single_phase or three_phase'));\n return;\n }\n const result = updateStudy(resolveFile(opts), (study) => {\n study.instalationPhaseNumber = opts.phase;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set economics ---\n set\n .command('economics')\n .description(\n 'Set economic parameters for the study.\\n' +\n 'Example: suntropy studies set economics --file study.json --margin 15 --total-cost 6500 --lifetime 25'\n )\n .option('--file <path>', 'Study file path')\n .option('--margin <n>', 'Margin percentage')\n .option('--total-cost <n>', 'Total installation cost (€)')\n .option('--lifetime <n>', 'Installation lifetime in years')\n .option('--inflation <n>', 'Inflation rate percentage')\n .option('--taxes-pct <n>', 'Tax percentage')\n .option('--include-taxes', 'Include taxes in pricing')\n .option('--commercial-fee <n>', 'Commercial fee percentage')\n .option('--excesses-mode <mode>', 'Excesses compensation: gridSelling, PPA, noInjection, virtualBattery')\n .option('--excesses-buy-price <n>', 'Excesses buy price (€/MWh)')\n .option('--excesses-selling-price <n>', 'Excesses selling price (€/MWh)')\n .option('--peak-power-cost <n>', 'Cost per Wp (€/Wp). If --total-cost is omitted, totalCost is derived as cost × installed peak power (W)')\n .option('--guarantee-production <n>', 'Guarantee production percentage')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const er = (study.economicResults || {}) as Record<string, unknown>;\n if (opts.margin !== undefined) er.margen = parseFloat(opts.margin);\n if (opts.totalCost !== undefined) er.totalCost = parseFloat(opts.totalCost);\n if (opts.lifetime !== undefined) er.instalationLifeTime = parseInt(opts.lifetime);\n if (opts.inflation !== undefined) er.inflation = parseFloat(opts.inflation);\n if (opts.taxesPct !== undefined) er.taxesPercentage = parseFloat(opts.taxesPct);\n if (opts.includeTaxes) er.includeTaxes = true;\n if (opts.commercialFee !== undefined) er.commercialFeePercentage = parseFloat(opts.commercialFee);\n if (opts.excessesMode) er.excessesCompensationMode = opts.excessesMode;\n if (opts.excessesBuyPrice !== undefined) er.excessesBuyPrice = parseFloat(opts.excessesBuyPrice);\n if (opts.excessesSellingPrice !== undefined) er.excessesSellingPrice = parseFloat(opts.excessesSellingPrice);\n if (opts.peakPowerCost !== undefined) er.peakPowerCost = parseFloat(opts.peakPowerCost);\n if (opts.guaranteeProduction !== undefined) er.guaranteeProductionPercentage = parseFloat(opts.guaranteeProduction);\n\n // Auto-derive totalCost from the per-Wp cost when --peak-power-cost is set\n // but --total-cost is not. The economic balance uses economicResults.totalCost\n // as the source of truth; the frontend only derives the €/Wp figure from it\n // (totalCost / installedPeakPowerWp). We invert that here so setting the €/Wp\n // cost alone yields a correct total instead of leaving totalCost untouched\n // (which previously kept the balance at 0). Installed peak power is the sum of\n // the surfaces' resolved installedPower (W); peakPowerCost is €/Wp, so\n // totalCost = cost × watts. If no surface has a resolvable power we warn\n // (non-fatal) instead of writing a wrong total.\n if (opts.peakPowerCost !== undefined && opts.totalCost === undefined) {\n const surfaces = (study.surfaces as Record<string, unknown>[] | undefined) || [];\n let totalWatts = 0;\n let resolvedCount = 0;\n let anyDefault = false;\n for (const surface of surfaces) {\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n anyDefault = true;\n continue;\n }\n totalWatts += installedPower;\n resolvedCount += 1;\n }\n if (resolvedCount > 0 && !anyDefault) {\n er.totalCost = Math.round(parseFloat(opts.peakPowerCost) * totalWatts * 100) / 100;\n } else {\n process.stderr.write(\n JSON.stringify({\n warning:\n 'Set --peak-power-cost but could not derive totalCost: ' +\n (surfaces.length === 0\n ? 'the study has no surfaces.'\n : 'some surfaces have no resolvable installed power (set panels + kit/panel first).') +\n ' Pass --total-cost explicitly to set it.',\n }) + '\\n',\n );\n }\n }\n\n study.economicResults = er;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set custom-assets ---\n set\n .command('custom-assets')\n .description(\n 'Set selected custom assets for the study.\\n' +\n 'Example: suntropy studies set custom-assets --file study.json --asset 100:12 --asset 200:1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--asset <id:qty>', 'Custom asset as id:quantity (repeatable)', collectAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full custom asset data for each\n const assets: unknown[] = [];\n for (const { id, quantity } of opts.asset) {\n const res = await solarClient.get(`/custom-asset/id/${id}`);\n assets.push({ customAsset: res.data, quantity });\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.selectedCustomAssets = assets;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set batteries ---\n set\n .command('batteries')\n .description(\n 'Enable/disable batteries and set configuration.\\n' +\n 'Example: suntropy studies set batteries --file study.json --enable --battery-id 789 --count 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--enable', 'Enable batteries')\n .option('--disable', 'Disable batteries')\n .option('--battery-id <n>', 'Battery ID from inventory')\n .option('--count <n>', 'Number of batteries')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n if (opts.enable) study.activeBatteries = true;\n if (opts.disable) study.activeBatteries = false;\n if (opts.batteryId) {\n // Store battery reference — the full battery object would be fetched when calculating\n const config = (study.batteriesConfiguration || {}) as Record<string, unknown>;\n config.batteryId = parseInt(opts.batteryId);\n if (opts.count) config.batteriesNumber = parseInt(opts.count);\n study.batteriesConfiguration = config;\n }\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set data (generic fallback) ---\n set\n .command('data')\n .description(\n 'Generic JSON merge into the study (fallback for any field).\\n' +\n 'Example: suntropy studies set data --file study.json --data \\'{\"referenceId\":\"REF-001\"}\\''\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--data <json>', 'JSON to merge into the study')\n .action(async (opts) => {\n try {\n const parsed = JSON.parse(opts.data);\n // Detect cascade fields\n const cascadeFields = Object.keys(parsed);\n let cascadeField: string | undefined;\n if (cascadeFields.includes('consumption')) cascadeField = 'consumption';\n if (cascadeFields.includes('surfaces')) cascadeField = 'surfaces';\n\n const result = updateStudy(resolveFile(opts), (study) => {\n deepMerge(study, parsed);\n return cascadeField;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // CALCULATE — commands that call backend APIs\n // ═══════════════════════════════════════════\n\n // --- calculate production ---\n studies\n .command('calculate')\n .description('Calculate derived data for the study')\n .command('production')\n .description(\n 'Calculate production for study surfaces using backend API.\\n' +\n 'Example: suntropy studies calculate production --file study.json [--surface-index 0 | --all-surfaces]'\n )\n .option('--file <path>', 'Study file path')\n .option('--surface-index <n>', 'Calculate for specific surface index')\n .option('--all-surfaces', 'Calculate for all surfaces')\n .option('--losses <n>', 'Losses percentage', '14')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n\n const solarClient = createServiceClient('solar', global);\n const indicesToCalc = opts.surfaceIndex !== undefined\n ? [parseInt(opts.surfaceIndex)]\n : Array.from({ length: surfaces.length }, (_, i) => i);\n\n for (const idx of indicesToCalc) {\n const surface = surfaces[idx];\n if (!surface) continue;\n // Coordinates: surface center → study location → drawn polygon (centroid, else first point)\n const coords = resolveSurfaceCoordinates(surface, study);\n if (!coords) {\n outputError(new Error(`Surface ${idx} has no coordinates. Use: studies add surface --lat N --lon N`));\n continue;\n }\n const { lat, lng } = coords;\n // Installed power: explicit → (panel layout | panelNumber) × panel peak power (frontend parity)\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n outputError(new Error(\n `Surface ${idx} has no resolvable installed power (no installedPower, and no panel layout / panelNumber with a solarPanel/solarKit peak power). `\n + `Using the 5000W default — production will be wrong. Set the panels and kit/panel before calculating.`,\n ));\n }\n const body = {\n lat,\n long: lng,\n instaledPower: installedPower,\n angle: (surface.inclination as number) || (surface.angle as number) || 30,\n azimuth: (surface.orientation as number) || (surface.azimuth as number) || 180,\n lossesPercentage: parseFloat(opts.losses),\n year: new Date().getFullYear(),\n isOptimized: false,\n };\n const res = await solarClient.post('/solar-study/calculateProduction', body);\n surface.production = res.data;\n }\n\n // Write back and validate\n const result = updateStudy(filePath, (s) => {\n s.surfaces = surfaces;\n return undefined; // don't cascade — we're setting production, not changing surfaces\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate results ---\n studies\n .command('calculate-results')\n .description(\n 'Calculate energy results replicating frontend SolarResultCalculator.\\n' +\n 'Computes: net consumption, excesses, spending/savings by period, coverage.\\n' +\n 'Requires: consumption, production, energyPrices, atrTariff.\\n' +\n 'Example: suntropy studies calculate-results --file study.json'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n const consumption = study.consumption as { days?: unknown[]; identifier?: string } | undefined;\n if (!consumption?.days?.length) {\n outputError(new Error('No consumption curve. Use: studies set consumption'));\n return;\n }\n\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces. Use: studies add surface'));\n return;\n }\n\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n if (!energyPrices) {\n outputError(new Error('No energy prices. Use: studies set prices'));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const consCurve = new PowerCurve(consumption.days, false, consumption.identifier || 'consumption', false);\n\n // Aggregate production from all surfaces (replicates SolarResultCalculator.aggregateProductionResults)\n let totalProdCurve: InstanceType<typeof PowerCurve> | null = null;\n for (const surf of surfaces) {\n const prod = surf.production as { days?: unknown[]; identifier?: string } | undefined;\n if (prod?.days?.length) {\n const surfProd = new PowerCurve(prod.days, false, prod.identifier || 'production', false);\n totalProdCurve = totalProdCurve ? totalProdCurve.aggregatePowerCurve(surfProd) : surfProd;\n }\n }\n\n if (!totalProdCurve) {\n outputError(new Error('No production curves found. Use: studies calculate production'));\n return;\n }\n\n const results: Record<string, unknown> = {};\n\n // --- Core energy calculations (always computed) ---\n\n // Net consumption = consumption - production\n const netConsumptionCurve = consCurve.aggregatePowerCurve(totalProdCurve.applyMultiplier(-1));\n results.netConsumption = netConsumptionCurve;\n\n // Total production\n results.totalProduction = totalProdCurve.getTotalAcumulate();\n\n // Consumption coverage percentage\n results.totalConsumptionCoverage =\n ((results.totalProduction as number) / consCurve.getTotalAcumulate()) * 100;\n\n // --- Period-based economic calculations (replicates SolarResultCalculator.calculateResults) ---\n const periodDistribution = await fetchPeriodDistribution(study, global);\n\n if (periodDistribution) {\n const clientDetails = study.clientDetails as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const oneBaseEnergyDiscountFactor = 1 - ((study.energyPricesDiscount as number) || 0) / 100;\n const oneBasePowerDiscountFactor = 1 - ((study.powerPricesDiscount as number) || 0) / 100;\n\n // Positive net consumption (filter out negatives = energy still needed from grid)\n const positiveNetConsumptionCurve = netConsumptionCurve.filterNegativeValues();\n const positiveNetByPeriod = positiveNetConsumptionCurve.aggregateByPeriod(periodDistribution);\n const rawConsumptionByPeriod = consCurve.aggregateByPeriod(periodDistribution);\n\n // Contracted power costs (if useAlternativePrices)\n const contractedPower = (study.contractedPower || {}) as ByPeriodValues;\n const powerPrices = (study.powerPrices || {}) as ByPeriodValues;\n const contractedPowerRawCostByPeriod: ByPeriodValues = {};\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && powerPrices[p]) {\n contractedPowerRawCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n }\n\n // PT market peak cost\n if (market === 'pt') {\n const extraCostPrice = (study.extraCostPrice || {}) as ByPeriodValues;\n let numberOfP1hours = 0;\n periodDistribution.forEach((day: any) => {\n Object.values(day.valuesList).forEach((hour: any) => {\n if (hour === 1) numberOfP1hours++;\n });\n });\n const coefficient =\n (1 / numberOfP1hours) * ((extraCostPrice.p1 as number) || 0) * netConsumptionCurve.days.length;\n results.rawPeakConsumptionCostPt = ((rawConsumptionByPeriod as any)?.p1 || 0) * coefficient;\n results.netPeakConsumptionCostPt = ((positiveNetByPeriod as any)?.p1 || 0) * coefficient;\n }\n\n // Raw spending by period\n const totalRawSpendingByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const rawConsP = (rawConsumptionByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n const priceWithTax = includeTaxes && taxPct ? priceP * (1 + taxPct / 100) : priceP;\n totalRawSpendingByPeriod[p] =\n rawConsP * priceWithTax * oneBaseEnergyDiscountFactor +\n ((contractedPowerRawCostByPeriod[p] as number) || 0);\n }\n results.totalRawSpendingByPeriod = totalRawSpendingByPeriod;\n\n // Total raw spending\n results.totalRawSpending =\n Object.values(totalRawSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.rawPeakConsumptionCostPt as number) || 0);\n\n // Net spending by period + alternative prices\n const alternativeEnergyPrices = (study.alternativeEnergyPrices || {}) as ByPeriodValues;\n const alternativePowerPrices = (study.alternativePowerPrices || {}) as ByPeriodValues;\n const contractedPowerFinalCostByPeriod: ByPeriodValues = {};\n const contractedPowerSavingsByPeriod: ByPeriodValues = {};\n\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && alternativePowerPrices[p]) {\n contractedPowerFinalCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number);\n }\n if (contractedPower[p] && powerPrices[p] && alternativePowerPrices[p]) {\n contractedPowerSavingsByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor -\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n results.contractedPowerSavingsByPeriod = contractedPowerSavingsByPeriod;\n }\n\n const totalNetSpendingByPeriod: ByPeriodValues = {};\n const alternativeTotalNetSpendingByPeriod: ByPeriodValues = {};\n\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const posNetP = (positiveNetByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const altPriceP = (alternativeEnergyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n\n totalNetSpendingByPeriod[p] =\n posNetP * (includeTaxes ? priceP * (1 + taxPct / 100) : priceP) * oneBaseEnergyDiscountFactor;\n\n if (study.alternativeEnergyPrices) {\n alternativeTotalNetSpendingByPeriod[p] =\n posNetP * altPriceP + ((contractedPowerFinalCostByPeriod[p] as number) || 0);\n }\n }\n results.totalNetSpendingByPeriod = totalNetSpendingByPeriod;\n if (study.alternativeEnergyPrices) {\n results.alternativeTotalNetSpendingByPeriod = alternativeTotalNetSpendingByPeriod;\n }\n\n // Total net spending\n results.totalNetSpending =\n Object.values(totalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.netPeakConsumptionCostPt as number) || 0);\n\n // Savings by period = raw - net\n const totalSavingsByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n totalSavingsByPeriod[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) - ((totalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriod = totalSavingsByPeriod;\n\n // Alternative savings by period\n if (study.alternativeEnergyPrices) {\n const altSavings: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n altSavings[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) -\n ((alternativeTotalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriodAlternativeSavings = altSavings;\n }\n\n // Total savings\n results.totalSavings =\n Object.values(totalSavingsByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n\n // Total savings with alternative prices\n if (study.alternativeEnergyPrices) {\n results.totalSavingsAlternativePrices =\n Object.values(alternativeTotalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n }\n\n // Excesses curve = (production - consumption), keep positive\n const excessesCurve = totalProdCurve\n .aggregatePowerCurve(consCurve.applyMultiplier(-1))\n .filterNegativeValues();\n results.excessesCurve = excessesCurve;\n\n // Excesses by period\n results.totalExcessesByPeriod = excessesCurve.aggregateByPeriod(periodDistribution);\n results.totalExcesses = Object.values(results.totalExcessesByPeriod as ByPeriodValues)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0);\n }\n\n const result = updateStudy(filePath, (s) => {\n s.results = results;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // OPTIMIZE PEAK POWER\n // ═══════════════════════════════════════════\n\n studies\n .command('optimize-peakpower')\n .description(\n 'Optimize peak power based on consumption.\\n\\n' +\n 'Supports two modes:\\n' +\n ' - Panel mode (default or when solarPanel is set): iterates peak power\\n' +\n ' - Kit mode (when solarKit is set or --use-kits): evaluates available kits\\n\\n' +\n 'Optimization criteria (pick one):\\n' +\n ' --energy-savings <pct> Target energy savings percentage\\n' +\n ' --raw-consumption <pct> Production as percentage of consumption\\n' +\n ' --max-excesses <pct> Max excesses as percentage of production\\n' +\n ' --max-overproduction-months <n> Max months with overproduction\\n\\n' +\n 'Surface constraints:\\n' +\n ' If surfaces have area + panel dimensions, max panels per surface is calculated.\\n' +\n ' Without area, no surface constraint is applied (unlimited space).\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies optimize-peakpower --file study.json --energy-savings 70\\n' +\n ' suntropy studies optimize-peakpower --file study.json --raw-consumption 100 --use-kits\\n' +\n ' suntropy studies optimize-peakpower --file study.json --max-excesses 15'\n )\n .option('--file <path>', 'Study file path')\n .option('--energy-savings <pct>', 'Target energy savings %')\n .option('--raw-consumption <pct>', 'Target production as % of consumption')\n .option('--max-excesses <pct>', 'Max excesses as % of production')\n .option('--max-overproduction-months <n>', 'Max months with overproduction')\n .option('--use-kits', 'Force kit mode (fetch all active kits and select optimal)')\n .option('--apply', 'Apply the result to the study file (set peakpower/kit, recalculate production)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n // Determine evaluation mode\n const evaluationMode: Record<string, number> = {};\n if (opts.energySavings !== undefined) evaluationMode.energyPercentageSavings = parseFloat(opts.energySavings);\n else if (opts.rawConsumption !== undefined) evaluationMode.rawConsumptionPercentage = parseFloat(opts.rawConsumption);\n else if (opts.maxExcesses !== undefined) evaluationMode.maxExcessesPercentage = parseFloat(opts.maxExcesses);\n else if (opts.maxOverproductionMonths !== undefined) evaluationMode.maxNumberOfOverproductionMonths = parseInt(opts.maxOverproductionMonths);\n else {\n // Default: 100% raw consumption (match consumption)\n evaluationMode.rawConsumptionPercentage = 100;\n }\n\n // Validate study has consumption and production\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n const consumptionData = study.consumption as Record<string, unknown> | undefined;\n if (!consumptionData) {\n outputError(new Error('No consumption in study. Use: studies set consumption'));\n return;\n }\n\n // Check all surfaces have production\n const surfacesWithoutProduction = surfaces.filter((s) => !s.production);\n if (surfacesWithoutProduction.length > 0) {\n outputError(new Error(`${surfacesWithoutProduction.length} surface(s) without production. Use: studies calculate production --all-surfaces`));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const cd = consumptionData as any;\n const consumptionCurve = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || 'consumption', cd.parseDate ?? false);\n const totalConsumption = consumptionCurve.getTotalAcumulate();\n\n // Build base production (1 kWp) for each surface\n const baseProduction: Record<string, any> = {};\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const prodData = surface.production as any;\n const prodCurve = new PowerCurve(prodData.days || prodData, false, sid, false);\n const installedPower = (surface.installedPower as number) || 5000;\n // Normalize to 1kWp base\n baseProduction[sid] = prodCurve.applyMultiplier(1 / (installedPower / 1000));\n }\n\n // Determine mode: kit vs panel\n const useKits = opts.useKits || study.peakPowerIntroductionMode === 'solarKit';\n const solarClient = createServiceClient('solar', global);\n\n if (useKits) {\n // ── KIT MODE ──\n const phaseNumber = (study.phaseNumber as string) || 'single_phase';\n\n // Fetch all active kits\n const kitsRes = await solarClient.get('/solar-kits', { params: { limit: 500 } });\n let allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n\n // Filter by phase\n allKits = allKits.filter((k: any) => k.phaseNumber === phaseNumber && k.active !== false);\n\n // Check coplanar compatibility\n const isCoplanar = surfaces.every((s) => !(s.panelInclination as number));\n allKits = allKits.filter((k: any) =>\n isCoplanar === undefined ? true : isCoplanar === (k.coplanar === null ? true : k.coplanar)\n );\n\n // Sort by peak power ascending (smallest first)\n allKits.sort((a: any, b: any) =>\n (a.panelNumber * (a.kitSolarPanel?.peakPower || 0)) - (b.panelNumber * (b.kitSolarPanel?.peakPower || 0))\n );\n\n if (allKits.length === 0) {\n outputError(new Error('No compatible kits found for current phase/surface configuration'));\n return;\n }\n\n let selectedKit: any = null;\n let bestApproxKit: any = null;\n let bestApproxValue = -Infinity;\n let firstValidKit: any = null;\n const optimizationLog: Record<number, any> = {};\n\n for (const kit of allKits) {\n const kitPanel = kit.kitSolarPanel;\n if (!kitPanel) continue;\n\n // Distribute panels across surfaces\n let remainingPanels = kit.panelNumber || 0;\n const surfPanelCount: Record<string, number> = {};\n let fits = true;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n let maxPanels: number;\n\n if (area && kitPanel.width && kitPanel.heigth) {\n // Calculate max panels from area\n maxPanels = calculateMaxPanels(\n area,\n kitPanel,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n } else {\n // No area constraint — unlimited\n maxPanels = remainingPanels;\n }\n\n const assigned = Math.min(remainingPanels, maxPanels);\n surfPanelCount[sid] = assigned;\n remainingPanels -= assigned;\n }\n\n if (remainingPanels > 0) continue; // Kit doesn't fit\n\n if (!firstValidKit) firstValidKit = kit;\n\n // Calculate production for this kit\n let totalProd: any = null;\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const panelCount = surfPanelCount[sid] || 0;\n const surfPeakPower = (panelCount * kitPanel.peakPower) / 1000;\n const surfProd = baseProduction[sid].applyMultiplier(surfPeakPower);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const kitPeakPower = ((kit.panelNumber || 0) * kitPanel.peakPower) / 1000;\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criteria\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[kit.idSolarKit] = {\n identifier: kit.identifier,\n peakPower: kitPeakPower,\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n panelDistribution: surfPanelCount,\n };\n\n if (criterionValue > bestApproxValue) {\n bestApproxValue = criterionValue;\n bestApproxKit = kit;\n }\n\n if (criterionMet) {\n selectedKit = kit;\n break;\n }\n }\n\n if (!selectedKit) {\n selectedKit = bestApproxKit || firstValidKit;\n }\n\n const resultData: Record<string, unknown> = {\n mode: 'kit',\n evaluationMode,\n selectedKit: selectedKit ? {\n idSolarKit: selectedKit.idSolarKit,\n identifier: selectedKit.identifier,\n peakPower: ((selectedKit.panelNumber || 0) * (selectedKit.kitSolarPanel?.peakPower || 0)) / 1000,\n panelNumber: selectedKit.panelNumber,\n price: selectedKit.price,\n } : null,\n kitsEvaluated: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply && selectedKit) {\n updateStudy(filePath, (s) => {\n s.solarKit = selectedKit;\n s.peakPowerIntroductionMode = 'solarKit';\n s.solarPanel = undefined;\n s.solarInverters = undefined;\n s.peakPowerOptimizationMethod = evaluationMode;\n return undefined;\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n } else {\n // ── PANEL MODE ──\n const panel = study.solarPanel as Record<string, unknown> | undefined;\n if (!panel) {\n outputError(new Error('No solar panel set. Use: studies set panel --panel-id <id>'));\n return;\n }\n\n const panelPeakPower = (panel.peakPower as number) || 450;\n const panelWidth = (panel.width as number) || 1134;\n const panelHeight = (panel.heigth as number) || (panel.height as number) || 1762;\n const panelObj = { peakPower: panelPeakPower, width: panelWidth, heigth: panelHeight };\n\n // Calculate max peak power per surface\n const surfacesMaxPeakPower: Record<string, number> = {};\n let totalMaxPeakPower = 0;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n\n if (area && panelWidth && panelHeight) {\n const maxPanels = calculateMaxPanels(\n area,\n panelObj,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n surfacesMaxPeakPower[sid] = (maxPanels * panelPeakPower) / 1000;\n } else {\n // No area constraint — use large value (500 kWp per surface)\n surfacesMaxPeakPower[sid] = 500;\n }\n totalMaxPeakPower += surfacesMaxPeakPower[sid];\n }\n\n // Determine iteration direction and initial value\n const isAscending = evaluationMode.energyPercentageSavings !== undefined\n || evaluationMode.economicPercentageSavings !== undefined\n || evaluationMode.rawConsumptionPercentage !== undefined;\n\n let peakPower = isAscending ? panelPeakPower / 1000 : totalMaxPeakPower;\n const optimizationLog: Record<number, any> = {};\n let resultPeakPower: Record<string, number> = {};\n let lastResult: number | undefined;\n const MAX_ITERATIONS = 200;\n const TOLERANCE = 0.005;\n let correctionFactor = 1;\n let itersSinceCorrection = 0;\n\n for (let iter = 0; iter < MAX_ITERATIONS && peakPower > 0 && peakPower <= totalMaxPeakPower; iter++) {\n peakPower = parseFloat(peakPower.toFixed(2));\n itersSinceCorrection++;\n\n if (itersSinceCorrection >= 20) {\n correctionFactor += 1.1;\n itersSinceCorrection = 0;\n }\n\n // Calculate change rate\n let changeRate: number;\n if (peakPower < 20) changeRate = (panelPeakPower / 1000) * correctionFactor;\n else if (peakPower < 500) changeRate = 5 * correctionFactor;\n else changeRate = 50 * correctionFactor;\n\n // Distribute peak power across surfaces\n let remaining = peakPower;\n let totalProd: any = null;\n resultPeakPower = {};\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const surfPP = Math.min(remaining, surfacesMaxPeakPower[sid]);\n remaining -= surfPP;\n resultPeakPower[sid] = surfPP;\n const surfProd = baseProduction[sid].applyMultiplier(surfPP);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criterion\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[peakPower] = {\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n surfacesPeakpower: { ...resultPeakPower },\n };\n\n if (criterionMet) break;\n\n // Tolerance check — stop if no meaningful progress\n if (isAscending && lastResult !== undefined && lastResult * (1 + TOLERANCE) >= criterionValue) {\n break;\n }\n lastResult = criterionValue;\n\n peakPower += isAscending ? changeRate : -changeRate;\n }\n\n // Compute final totals\n const totalOptimizedPeakPower = Object.values(resultPeakPower).reduce((a, b) => a + b, 0);\n const totalPanels = Math.round(totalOptimizedPeakPower / (panelPeakPower / 1000));\n\n const resultData: Record<string, unknown> = {\n mode: 'panel',\n evaluationMode,\n optimizedPeakPower: parseFloat(totalOptimizedPeakPower.toFixed(2)),\n estimatedPanels: totalPanels,\n surfacesPeakpower: resultPeakPower,\n iterations: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply) {\n updateStudy(filePath, (s) => {\n const surfs = s.surfaces as Record<string, unknown>[] | undefined;\n if (surfs) {\n for (const surf of surfs) {\n const sid = surf.surfaceId as string;\n if (resultPeakPower[sid] !== undefined) {\n const surfPanels = Math.round(resultPeakPower[sid] / (panelPeakPower / 1000));\n surf.panelNumber = surfPanels;\n surf.installedPower = resultPeakPower[sid] * 1000;\n }\n }\n }\n s.peakPowerOptimizationMethod = evaluationMode;\n return 'surfaces';\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // COMMENTS\n // ═══════════════════════════════════════════\n\n // --- add comment (local study file) ---\n studies\n .command('add-comment')\n .description(\n 'Add a comment to the local study file.\\n' +\n 'Example: suntropy studies add-comment --file study.json --content \"Panel layout reviewed\"'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--content <text>', 'Comment text')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const comments = (study.comments || []) as Record<string, unknown>[];\n comments.push(createComment('commented', opts.content));\n study.comments = comments;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- comment (API — add to existing study in backend) ---\n studies\n .command('comment <studyId>')\n .description(\n 'Add a comment to an existing study via API.\\n' +\n 'Example: suntropy studies comment abc123 --content \"Revisado por agente\"'\n )\n .requiredOption('--content <text>', 'Comment text')\n // Hidden flags for the \"Tag de Alexandria en comentarios\" workflow (sprint\n // Suntropy AI). They are intentionally omitted from --help / docs: the\n // Alexandria agent is instructed to use them in that specific workflow only.\n // - `--as-alexandria` signs the comment as Alexandria.\n // - `--reply-to-user`/`--reply-to-name` prepend a mention `@[name](userUID)`\n // with the markup the backend parses to notify that user.\n .addOption(new Option('--as-alexandria').hideHelp())\n .addOption(new Option('--reply-to-user <userUID>').hideHelp())\n .addOption(new Option('--reply-to-name <name>').hideHelp())\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const comment = createComment('commented', opts.content, {\n asAlexandria: Boolean(opts.asAlexandria),\n replyToUser: opts.replyToUser,\n replyToName: opts.replyToName,\n });\n const res = await client.post(`/solar-study/addSolarStudyComment/${studyId}`, comment);\n // The endpoint returns the FULL updated study (and an EMPTY body when the\n // study isn't found). Keep the guard so we never report a non-saved\n // comment as success, but DON'T dump the whole study: emit a compact\n // confirmation of the comment that was created.\n const saved = assertFound(res.data, 'Solar study', studyId) as {\n comments?: unknown[];\n };\n output(\n {\n success: true,\n message: `Comentario añadido al estudio ${studyId}`,\n studyId,\n commentsCount: Array.isArray(saved.comments)\n ? saved.comments.length\n : undefined,\n comment: {\n type: comment.type,\n creationUserUID: comment.creationUserUID,\n creationTimestamp: comment.creationTimestamp,\n aiGenerated: comment.aiGenerated ?? false,\n content: comment.content,\n },\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\n// ─── Helpers ───\n\n/** Generate consumption curve from REE profile + period/monthly data using energy-types */\nasync function generateFromProfile(\n global: OutputOptions & Record<string, unknown>,\n tariff: string,\n market: string,\n year: number,\n mode: 'CONSUMPTION_BY_PERIOD' | 'MONTH_CONSUMPTION' | 'MONTHLY_BY_PERIOD',\n data: unknown,\n): Promise<unknown> {\n const profilesClient = createServiceClient('profiles', global);\n const periodsClient = createServiceClient('periods', global);\n\n // 1. Fetch REE profile\n const profileRes = await profilesClient.get('/ree-profiles', {\n params: {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n market,\n },\n });\n const profile = profileRes.data?.profile || profileRes.data;\n if (!profile || !Array.isArray(profile) || profile.length === 0) {\n throw new Error('Failed to fetch REE profiles');\n }\n\n // 2. Import energy-types\n const { applyProfileToConsumption, ConsumptionIntroductionModes } =\n await import('energy-types/lib/energy/calculations/applyProfileToConsumption.js');\n\n if (mode === 'CONSUMPTION_BY_PERIOD') {\n // Need period distribution\n const tariffIdMap: Record<string, number> = { '2.0TD': 13, '3.0TD': 14, '6.1TD': 15 };\n const tariffId = tariffIdMap[tariff] || 14;\n const periodsRes = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: 1,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const periodDistribution = periodsRes.data;\n\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.CONSUMPTION_BY_PERIOD,\n profile,\n data,\n periodDistribution,\n );\n return result;\n\n } else if (mode === 'MONTH_CONSUMPTION') {\n // Transform flat {month: value} into {year: {month: value}} expected by energy-types\n const flatData = data as Record<string, number>;\n const yearMonthData: Record<number, Record<number, number>> = { [year]: {} };\n for (const [month, value] of Object.entries(flatData)) {\n yearMonthData[year][parseInt(month)] = value;\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n yearMonthData,\n );\n return result;\n\n } else if (mode === 'MONTHLY_BY_PERIOD') {\n // For monthly by period, we need to process month by month\n // This is more complex — for now, use the MONTH_CONSUMPTION as fallback\n // with aggregated monthly totals\n const monthlyData = data as Record<string, Record<string, number>>;\n const monthTotals: Record<string, number> = {};\n for (const [month, periods] of Object.entries(monthlyData)) {\n monthTotals[month] = Object.values(periods).reduce((a, b) => a + b, 0);\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n monthTotals,\n );\n return result;\n }\n\n throw new Error(`Unknown consumption mode: ${mode}`);\n}\n\n/** Calculate max panels that fit in an area (replicates frontend calculateSolarPanelsInArea) */\nfunction calculateMaxPanels(\n areaM2: number,\n panel: { width: number; heigth: number; peakPower?: number },\n availablePercentage: number,\n panelInclination: number,\n surfaceInclination: number,\n panelPosition: string,\n latitude: number,\n): number {\n const { heigth, width } = panel;\n // Convert m² to mm² and apply available percentage\n let area = areaM2 * 1000000 * (availablePercentage / 100);\n const x = 1 / Math.atan(61 - (latitude - surfaceInclination));\n let totalPanelNumber: number;\n\n if (panelPosition === 'horizontal') {\n const h = width * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (heigth + 20) * (width + minimumDistance);\n totalPanelNumber = area / panelArea;\n } else {\n const h = heigth * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (width + 20) * (heigth + minimumDistance);\n totalPanelNumber = area / panelArea;\n }\n\n return isNaN(totalPanelNumber) ? 0 : Math.floor(totalPanelNumber);\n}\n\n/** Collector for repeatable --asset <id:qty> */\nfunction collectAssets(value: string, previous: { id: number; quantity: number }[]): { id: number; quantity: number }[] {\n const [idStr, qtyStr] = value.split(':');\n const id = parseInt(idStr);\n const quantity = qtyStr ? parseInt(qtyStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid asset format: \"${value}\". Use <id>:<quantity>`);\n return [...previous, { id, quantity }];\n}\n\n/** Fetch period distribution from periods service (needed for economic calculations) */\nasync function fetchPeriodDistribution(\n study: Study,\n global: OutputOptions & Record<string, unknown>,\n): Promise<unknown[] | null> {\n const atrTariff = study.atrTariff as Record<string, unknown> | undefined;\n const geoZone = study.geographicalZone as Record<string, unknown> | undefined;\n if (!atrTariff) return null;\n\n const tariffId = atrTariff.idTarifaATR as number;\n const zoneId = (geoZone?.idZona as number) || 1;\n const market = (study.market as string) || 'es';\n const year = new Date().getFullYear();\n\n try {\n const periodsClient = createServiceClient('periods', global);\n const res = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: zoneId,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const data = res.data;\n if (Array.isArray(data) && data.length > 0) return data;\n return null;\n } catch {\n return null;\n }\n}\n\ninterface CreateCommentExtra {\n /** Sign the comment as Alexandria (AI assistant) instead of the active user. */\n asAlexandria?: boolean;\n /** userUID to mention at the start of the comment so the backend notifies them. */\n replyToUser?: string;\n /** Display name for the mentioned user (defaults to the userUID). */\n replyToName?: string;\n}\n\n/** Create a study comment (replicates frontend createNewComment) */\nfunction createComment(\n type: string,\n content?: string,\n extra?: CreateCommentExtra\n): Record<string, unknown> {\n const config = loadConfig();\n const profile = getActiveProfile(config);\n const autoContent: Record<string, string> = {\n created: 'Estudio creado via CLI',\n modified: 'Estudio actualizado via CLI',\n };\n\n let body = content || autoContent[type] || '';\n // Prepend a mention so the backend parses it and notifies the user. The\n // markup must match react-mentions / the backend regex: @[name](userUID).\n if (extra?.replyToUser) {\n const name = extra.replyToName || extra.replyToUser;\n body = `@[${name}](${extra.replyToUser}) ${body}`.trim();\n }\n\n const comment: Record<string, unknown> = {\n content: body,\n type,\n creationTimestamp: new Date().toISOString(),\n creationUserUID: extra?.asAlexandria\n ? 'alexandria'\n : profile.userUID || 'cli-agent',\n };\n // Mark AI-authored comments so the frontend renders them as Alexandria.\n if (extra?.asAlexandria) {\n comment.aiGenerated = true;\n }\n return comment;\n}\n","import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","import { Command } from 'commander';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\nimport { registerStudyBuilderCommands } from './builder.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Replace PowerCurve objects with lightweight summaries to save tokens */\nfunction compactCurves(obj: unknown): unknown {\n if (obj === null || obj === undefined || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(compactCurves);\n\n const record = obj as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects containing 'valuesList'\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n // Detect inline DayCurve arrays (consumption, production fields that are PowerCurve-like)\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactCurves(val);\n }\n return result;\n}\n\n/** Expand sections: pick which parts of study to include */\nconst EXPAND_SECTIONS: Record<string, string[]> = {\n surfaces: ['surfaces'],\n results: ['results'],\n economics: ['economicResults'],\n batteries: ['activeBatteries', 'batteriesConfiguration', 'batteriesEnergyBalance', 'batteriesResults', 'bateries'],\n consumption: ['consumption', 'consumptionIntroductionMode', 'monthConsumptionDictionary', 'monthPeriodConsumptionDictionary', 'periodConsumptionDictionary'],\n equipment: ['solarPanel', 'solarKit', 'solarInverters', 'selectedChargers', 'selectedCustomAssets'],\n client: ['clientDetails', 'clientsDetails'],\n location: ['location', 'mapCenter', 'geographicalZone', 'atrTariff'],\n};\n\n/**\n * Fields that users often ask for on the study but actually live on the\n * metadata entity (MySQL) — surfaced via `studies list` or `studies metadata`.\n */\nconst METADATA_ONLY_FIELDS: Record<string, string> = {\n peakPower: 'metadata',\n sellingPrice: 'metadata',\n totalCost: 'metadata',\n anualProduction: 'metadata',\n anualConsumption: 'metadata',\n currentState: 'metadata',\n clientName: 'metadata',\n idSolarStudyMetadata: 'metadata',\n solarStudyId: 'metadata',\n};\n\n/**\n * Fields that don't exist on either the study document or its metadata —\n * they are computed client-side (builder) or simply don't exist in this API.\n */\nconst COMPUTED_OR_UNKNOWN_FIELDS: Record<string, string> = {\n completionPercentage: 'computed by `studies validate` / `studies save` from stepsProgress',\n isCompleted: 'not a persisted field; derive from solarStudyProgress or completionPercentage',\n stepsProgress: 'computed by `studies validate` / `studies save`',\n};\n\nfunction explainMissingStudyFields(missing: string[], studyId: string): void {\n const metadataFields = missing.filter(f => f in METADATA_ONLY_FIELDS);\n const computedFields = missing.filter(f => f in COMPUTED_OR_UNKNOWN_FIELDS);\n const unknownFields = missing.filter(f => !(f in METADATA_ONLY_FIELDS) && !(f in COMPUTED_OR_UNKNOWN_FIELDS));\n\n const lines: string[] = [];\n lines.push(`warning: ${missing.length} requested field(s) are not present on the study document returned by findById.`);\n\n if (metadataFields.length > 0) {\n lines.push('');\n lines.push(` These fields live on the STUDY METADATA (MySQL), not on the study document:`);\n for (const f of metadataFields) lines.push(` - ${f}`);\n lines.push(` Use: suntropy studies metadata ${studyId} --by-study-id --fields ${metadataFields.join(',')}`);\n lines.push(` Or: suntropy studies list --client-name <name> (list already projects these fields)`);\n }\n\n if (computedFields.length > 0) {\n lines.push('');\n lines.push(` These fields are not persisted on the study:`);\n for (const f of computedFields) lines.push(` - ${f}: ${COMPUTED_OR_UNKNOWN_FIELDS[f]}`);\n lines.push(` Use: suntropy studies validate ${studyId} (returns stepsProgress + completionPercentage)`);\n }\n\n if (unknownFields.length > 0) {\n lines.push('');\n lines.push(` These fields were not found on the study document:`);\n for (const f of unknownFields) lines.push(` - ${f}`);\n lines.push(` If you expected them, try: suntropy studies get ${studyId} --expand all --format json`);\n lines.push(` and inspect the full payload to locate the correct field path.`);\n }\n\n process.stderr.write(lines.join('\\n') + '\\n');\n}\n\n/** Core identity fields always included in get */\nconst CORE_FIELDS = [\n '_id', 'id', 'name', 'identifier', 'clientUID',\n 'creationTimestamp', 'lastEditTimestamp',\n 'assignedUserUID', 'creationUserUID',\n 'selectedSolarStudyMode', 'solarStudyProgress',\n 'market', 'layout',\n 'peakPowerIntroductionMode', 'instalationPhaseNumber',\n];\n\nfunction filterStudy(study: Record<string, unknown>, expand?: string): Record<string, unknown> {\n if (expand === 'all') return study;\n\n const sections = expand ? expand.split(',').map(s => s.trim()) : [];\n const allowedFields = new Set(CORE_FIELDS);\n\n for (const section of sections) {\n const fields = EXPAND_SECTIONS[section];\n if (fields) fields.forEach(f => allowedFields.add(f));\n }\n\n // If no expand, include summary numeric fields\n if (sections.length === 0) {\n ['peakPowerIntroductionMode', 'instalationPhaseNumber', 'location', 'atrTariff'].forEach(f => allowedFields.add(f));\n }\n\n const result: Record<string, unknown> = {};\n for (const key of allowedFields) {\n if (key in study) result[key] = study[key];\n }\n\n return compactCurves(result) as Record<string, unknown>;\n}\n\nexport function registerStudiesCommands(program: Command): void {\n const studies = program.command('studies').description(\n 'Explore and manage solar studies. Progressive exploration: list → metadata → get → get --expand → curves'\n );\n\n // --- list ---\n studies\n .command('list')\n .description('List solar studies metadata. Fields: idSolarStudyMetadata, solarStudyId, clientName, peakPower, currentState, creationTimestamp')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--state <state>', 'Filter by state name')\n .option('--client-name <name>', 'Filter by client name')\n .option('--from <date>', 'Filter from date (YYYY-MM-DD)')\n .option('--to <date>', 'Filter to date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (opts.state) body.state = opts.state;\n if (opts.clientName) body.clientName = opts.clientName;\n if (opts.from) body.fromDate = opts.from;\n if (opts.to) body.toDate = opts.to;\n\n const res = await client.post('/solar-study/findWithPaginationAndFilters', body);\n // Response: [items[], totalCount, ...] tuple or {data, total}\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || res.data?.solarStudiesMetadata || [];\n total = res.data?.total ?? res.data?.count ?? (Array.isArray(data) ? data.length : 0);\n }\n\n const outOpts: OutputOptions = { ...global };\n if (!global.fields) {\n outOpts.fields = 'idSolarStudyMetadata,solarStudyId,clientName,peakPower,anualProduction,anualConsumption,totalCost,sellingPrice,currentState,creationTimestamp';\n }\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- metadata ---\n studies\n .command('metadata <id>')\n .description('Get solar study metadata by metadata ID (relational). Full MySQL record with state, costs, versions.')\n .option('--by-study-id', 'Interpret <id> as MongoDB solarStudyId instead of metadata ID')\n .action(async (id, opts) => {\n try {\n // --by-study-id resolves against the MongoDB solarStudyId, so guard it\n // the same way as `get`; the default path uses a numeric metadata id.\n if (opts.byStudyId) assertStudyObjectId(id);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const path = opts.byStudyId\n ? `/solar-study/metadata/solar-study-id/${id}`\n : `/solar-study/findSolarStudyMetadataById/${id}`;\n const res = await client.get(path);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n studies\n .command('get <studyId>')\n .description(\n 'Get solar study by MongoDB ID. By default returns summary (no heavy curves).\\n' +\n 'Expand sections: surfaces, results, economics, batteries, consumption, equipment, client, location\\n' +\n 'Examples:\\n' +\n ' suntropy studies get abc123\\n' +\n ' suntropy studies get abc123 --expand surfaces,results\\n' +\n ' suntropy studies get abc123 --expand all\\n' +\n ' suntropy studies get abc123 --fields name,market (bypasses expand filter)'\n )\n .option('--expand <sections>', 'Comma-separated sections to expand (or \"all\")')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n // If the user passes --fields, they have already expressed exactly what\n // they want — don't pre-filter the study, let output() select from the\n // full object. Otherwise apply the expand-based summary filter.\n const filtered = global.fields ? study : filterStudy(study, opts.expand);\n\n if (global.fields) {\n const requested = global.fields.split(',').map(f => f.trim());\n const topLevel = requested.map(f => f.split('.')[0]);\n const missing = topLevel.filter(f => !(f in study));\n if (missing.length > 0) {\n explainMissingStudyFields(missing, studyId);\n }\n }\n\n output(filtered, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- curves ---\n studies\n .command('curves <studyId> <curveName>')\n .description(\n 'Extract and analyze a PowerCurve from a study.\\n' +\n 'Curve names: consumption, production, net-consumption, excesses\\n' +\n 'Default: --stats. Use --raw for full hourly data (8760 values).\\n' +\n 'Use --monthly for monthly aggregates, --daily for daily totals.'\n )\n .option('--stats', 'Show statistics (default if no other flag)')\n .option('--monthly', 'Monthly accumulated values')\n .option('--daily', 'Daily accumulated values')\n .option('--raw', 'Full hourly DayCurve[] data')\n .option('--total', 'Just the total accumulated value')\n .option('--surface-index <n>', 'Surface index for production curve', '0')\n .option('--save <file>', 'Save curve data to file')\n .action(async (studyId, curveName, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n\n // Extract the requested curve\n let curveData: unknown;\n switch (curveName) {\n case 'consumption':\n curveData = study.consumption;\n break;\n case 'production': {\n const surfaces = study.surfaces as any[];\n const idx = parseInt(opts.surfaceIndex);\n if (surfaces && surfaces[idx]?.production) {\n curveData = surfaces[idx].production;\n } else {\n outputError(new Error(`No production curve at surface index ${idx}. Study has ${surfaces?.length || 0} surfaces.`));\n return;\n }\n break;\n }\n case 'net-consumption':\n curveData = (study.results as any)?.netConsumption;\n break;\n case 'excesses':\n curveData = (study.results as any)?.excessesCurve;\n break;\n default:\n outputError(new Error(`Unknown curve: ${curveName}. Available: consumption, production, net-consumption, excesses`));\n return;\n }\n\n if (!curveData) {\n outputError(new Error(`Curve \"${curveName}\" not found or empty in this study.`));\n return;\n }\n\n // Import PowerCurve from energy-types\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n const cd = curveData as any;\n const pc = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || curveName, cd.parseDate ?? false);\n\n // Determine output mode\n const showRaw = opts.raw;\n const showMonthly = opts.monthly;\n const showDaily = opts.daily;\n const showTotal = opts.total;\n const showStats = opts.stats || (!showRaw && !showMonthly && !showDaily && !showTotal);\n\n let result: unknown;\n\n if (showRaw) {\n result = pc.days;\n } else if (showTotal) {\n result = { total: pc.getTotalAcumulate(), identifier: curveName, days: pc.days.length };\n } else if (showStats) {\n const raw = pc.calculateStatistics();\n result = raw.statistics || raw;\n } else if (showMonthly) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { anualMonthAccumulate: s.anualMonthAccumulate, anualMonthCount: s.anualMonthCount, anualMonthlyAverage: s.anualMonthlyAverage };\n } else if (showDaily) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { dailyAccumulate: s.dailyAccumulate };\n }\n\n const outOpts = { ...global, save: opts.save || global.save };\n output(result, outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate-production ---\n studies\n .command('calculate-production')\n .description('Calculate solar production curve for given coordinates and configuration')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .requiredOption('--power <w>', 'Installed power in Watts')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel orientation degrees (0=north, 180=south)', '180')\n .option('--losses <n>', 'Losses percentage', '14')\n .option('--year <n>', 'Year for calculation', String(new Date().getFullYear()))\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body = {\n lat: parseFloat(opts.lat),\n long: parseFloat(opts.lon),\n instaledPower: parseFloat(opts.power),\n angle: parseFloat(opts.angle),\n azimuth: parseFloat(opts.azimuth),\n lossesPercentage: parseFloat(opts.losses),\n year: parseInt(opts.year),\n isOptimized: false,\n };\n const res = await client.post('/solar-study/calculateProduction', body);\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- optimize-surfaces ---\n studies\n .command('optimize-surfaces')\n .description('Calculate optimal panel angle and azimuth for coordinates')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/optimizeSurfaces', {\n params: { lat: parseFloat(opts.lat), lon: parseFloat(opts.lon) },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // Register study builder commands (init, validate, save, pull, set, add, remove, calculate)\n registerStudyBuilderCommands(studies);\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read curve data from file, stdin, or --input flag */\nasync function readCurveInput(inputPath?: string): Promise<any> {\n let raw: string;\n if (inputPath && inputPath !== '-') {\n raw = readFileSync(inputPath, 'utf-8');\n } else {\n raw = await readStdin();\n }\n return JSON.parse(raw);\n}\n\n/** Build a PowerCurve from parsed JSON data */\nasync function buildCurve(data: any, identifier = 'curve') {\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n // Data might be: { days: [...], identifier } or just a DayCurve[]\n if (Array.isArray(data)) {\n return new PowerCurve(data, false, identifier, false);\n }\n return new PowerCurve(data.days || data, data.ignore0 ?? false, data.identifier || identifier, data.parseDate ?? false);\n}\n\n/** Serialize PowerCurve back to JSON-friendly format */\nfunction serializeCurve(pc: any): any {\n return { days: pc.days, identifier: pc.identifier, ignore0: pc.ignore0 };\n}\n\nexport function registerCurvesCommands(program: Command): void {\n const curves = program.command('curves').description(\n 'PowerCurve operations (pipe-friendly). Accept input via --input <file> or stdin.\\n' +\n 'Curve-returning commands output serialized PowerCurve JSON for chaining.\\n' +\n 'Use --save <file> to persist and still output to stdout.'\n );\n\n // --- stats ---\n curves\n .command('stats')\n .description('Calculate comprehensive statistics: monthly/daily/hourly averages, max, min, period aggregation')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'stats');\n const raw = pc.calculateStatistics();\n output(raw.statistics || raw, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- total ---\n curves\n .command('total')\n .description('Calculate total accumulated value across all hours')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'total');\n output({ total: pc.getTotalAcumulate(), days: pc.days.length }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- multiply ---\n curves\n .command('multiply <factor>')\n .description('Multiply all hourly values by a factor. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (factor, opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'multiplied');\n const result = pc.applyMultiplier(parseFloat(factor));\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- aggregate ---\n curves\n .command('aggregate')\n .description('Sum two PowerCurves (A + B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file')\n .requiredOption('--b <file>', 'Second curve file')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const result = pcA.aggregatePowerCurve(pcB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- subtract ---\n curves\n .command('subtract')\n .description('Subtract two PowerCurves (A - B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file (minuend)')\n .requiredOption('--b <file>', 'Second curve file (subtrahend)')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const negB = pcB.applyMultiplier(-1);\n const result = pcA.aggregatePowerCurve(negB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-positive ---\n curves\n .command('filter-positive')\n .description('Keep only non-negative hourly values (zero out negatives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'positive');\n const result = pc.filterNegativeValues(); // filterNegativeValues returns curve with negatives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-negative ---\n curves\n .command('filter-negative')\n .description('Keep only non-positive hourly values (zero out positives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'negative');\n const result = pc.filterPositiveValues(); // filterPositiveValues returns curve with positives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- sort ---\n curves\n .command('sort')\n .description('Sort curve days by date ascending. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'sorted');\n const sortedDays = pc.sortByDate();\n output({ days: sortedDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-dates ---\n curves\n .command('filter-dates')\n .description('Filter curve to a date range. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .option('--start <date>', 'Start date (YYYY-MM-DD)')\n .option('--end <date>', 'End date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'filtered');\n const start = opts.start ? new Date(opts.start) : undefined;\n const end = opts.end ? new Date(opts.end) : undefined;\n const filteredDays = pc.filterByDates(start, end);\n output({ days: filteredDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- to-serie ---\n curves\n .command('to-serie')\n .description('Convert curve to chart-ready series format (x/y arrays)')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'serie');\n const serie = pc.convertoToSerie();\n output(serie, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- by-period ---\n curves\n .command('by-period')\n .description(\n 'Aggregate a PowerCurve by tariff periods (P1-P6) using a period distribution.\\n' +\n 'Returns { p1, p2, p3, p4, p5, p6 } with accumulated kWh per period.\\n\\n' +\n 'The period distribution maps each hour of each day to a tariff period.\\n' +\n 'Get it with: suntropy consumption periods --save /tmp/periods.json\\n\\n' +\n 'Examples:\\n' +\n ' suntropy curves by-period --input /tmp/production.json --periods /tmp/periods.json\\n' +\n ' suntropy curves by-period --input /tmp/consumption.json --periods /tmp/periods.json'\n )\n .requiredOption('--periods <file>', 'Period distribution file (DayCurve[] from consumption periods)')\n .option('--input <file>', 'Input PowerCurve file (or stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'by-period');\n const periodsData = JSON.parse(readFileSync(opts.periods, 'utf-8'));\n const result = pc.aggregateByPeriod(periodsData);\n output(result, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerConsumptionCommands(program: Command): void {\n const consumption = program.command('consumption').description(\n 'Generate consumption curves using the profiles service.\\n' +\n 'Supports multiple estimation methods: standard patterns, custom profiles, monthly data.\\n' +\n 'Returns PowerCurve JSON compatible with `suntropy curves` for further processing.'\n );\n\n // --- estimate ---\n consumption\n .command('estimate')\n .description(\n 'Generate a consumption PowerCurve from patterns and annual consumption.\\n' +\n 'Patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Examples:\\n' +\n ' suntropy consumption estimate --annual 5000 --pattern Balance\\n' +\n ' suntropy consumption estimate --annual 8000 --pattern Domestic --tariff 3.0TD --market es\\n' +\n ' suntropy consumption estimate --annual 3500 --monthly-data \\'{\"1\":300,\"2\":280,...}\\'\\n' +\n ' suntropy consumption estimate --annual 5000 --custom-profile-id abc123'\n )\n .requiredOption('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--start-date <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end-date <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--tariff <code>', 'Electricity tariff code (e.g. 3.0TD)', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market: es, pt, it', 'es')\n .option('--custom-profile-id <id>', 'Use a custom consumption profile by ID')\n .option('--monthly-data <json>', 'Monthly consumption JSON: {\"1\":val,\"2\":val,...,\"12\":val}')\n .option('--daily-curve <json>', 'Custom daily curve JSON (DayCurve format)')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n const year = new Date().getFullYear();\n const startDate = opts.startDate || `${year}-01-01`;\n const endDate = opts.endDate || `${year}-12-31`;\n\n // Build query params\n const params: Record<string, string> = {\n startDate,\n endDate,\n tariff: opts.tariff,\n type: opts.type,\n anualConsumption: opts.annual,\n market: opts.market,\n };\n\n if (opts.pattern) params.consumptionType = opts.pattern;\n if (opts.customProfileId) params.customProfileId = opts.customProfileId;\n\n // Build optional body\n let body: Record<string, unknown> | undefined;\n if (opts.monthlyData || opts.dailyCurve) {\n body = {};\n if (opts.monthlyData) body.consumptionByMonth = JSON.parse(opts.monthlyData);\n if (opts.dailyCurve) body.dailyCurve = JSON.parse(opts.dailyCurve);\n }\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const res = await client.post(`/consumption-estimation?${queryString}`, body || {});\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ree-profiles ---\n consumption\n .command('ree-profiles')\n .description(\n 'Fetch REE (Red Eléctrica) hourly profiles for a date range and tariff.\\n' +\n 'Returns the raw profile data used as basis for consumption estimation.\\n' +\n 'Example: suntropy consumption ree-profiles --start 2024-01-01 --end 2024-12-31 --tariff 3.0TD'\n )\n .requiredOption('--start <YYYY-MM-DD>', 'Start date')\n .requiredOption('--end <YYYY-MM-DD>', 'End date')\n .option('--tariff <code>', 'Tariff code', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market code: es, pt, it', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/ree-profiles', {\n params: {\n startDate: opts.start,\n endDate: opts.end,\n tariff: opts.tariff,\n type: opts.type,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-tags ---\n consumption\n .command('custom-tags')\n .description('List available custom consumption profile tags for the authenticated client')\n .action(async () => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getTags');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-profile-info ---\n consumption\n .command('custom-profile-info')\n .description('Get details of a custom consumption profile by ID')\n .requiredOption('--id <profileId>', 'Custom profile ID')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getInfo', {\n params: { id: opts.id },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- periods ---\n consumption\n .command('periods')\n .description(\n 'Fetch period distribution (hour→P1-P6 mapping) from the periods service.\\n' +\n 'Returns DayCurve[] where each hour\\'s value is the period number (1-6).\\n' +\n 'Use with `suntropy curves by-period` to aggregate any curve by tariff period.\\n\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD, 14=3.0TD\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n\\n' +\n 'Examples:\\n' +\n ' suntropy consumption periods --tariff-id 14 --zone-id 1 --save /tmp/periods.json\\n' +\n ' suntropy consumption periods --tariff-id 13 --start 2025-01-01 --end 2025-12-31'\n )\n .option('--tariff-id <n>', 'ATR tariff ID (13=2.0TD, 14=3.0TD)', '14')\n .option('--zone-id <n>', 'Geographical zone ID (1=Peninsula)', '1')\n .option('--start <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--market <code>', 'Market: es, pt, it, fr', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('periods', global);\n const year = new Date().getFullYear();\n const res = await client.get('/periodos', {\n params: {\n idTarifa: parseInt(opts.tariffId),\n idZona: parseInt(opts.zoneId),\n fechaInicio: opts.start || `${year}-01-01`,\n fechaFin: opts.end || `${year}-12-31`,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- from-file ---\n consumption\n .command('from-file')\n .description(\n 'Generate consumption curve from an uploaded file.\\n' +\n 'Supported formats: Portuguese EREDES ZIP files.\\n' +\n 'Example: suntropy consumption from-file --eredes-zip /path/to/file.zip'\n )\n .option('--eredes-zip <path>', 'Path to Portuguese EREDES ZIP file')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n if (opts.eredesZip) {\n const FormData = (await import('form-data')).default;\n const form = new FormData();\n form.append('file', readFileSync(opts.eredesZip), {\n filename: opts.eredesZip.split('/').pop(),\n contentType: 'application/zip',\n });\n const res = await client.post('/consumption-files-processor/portugal/eredes-zip', form, {\n headers: form.getHeaders(),\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } else {\n outputError(new Error('Specify a file format: --eredes-zip <path>'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Unwrap PublicApiResponse: { code, data, error } → data or throw */\nfunction unwrapPublicApiResponse(resData: unknown): unknown {\n if (resData && typeof resData === 'object' && !Array.isArray(resData)) {\n const r = resData as Record<string, unknown>;\n // Detect PublicApiResponse shape: has 'code' field (number)\n if ('code' in r && typeof r.code === 'number') {\n // Prefer data if present (API may return both error and data)\n if (r.data !== undefined) return r.data;\n // No data — check for error\n if (r.error) {\n const err = r.error as Record<string, unknown>;\n throw new Error(`API error (${err.code || r.code}): ${err.message || JSON.stringify(err)}`);\n }\n // code present but no data and no error — return as-is\n return resData;\n }\n }\n return resData;\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerSolarformCommands(program: Command): void {\n const solarform = program.command('solarform').description(\n 'Create solar studies via the Solar Form API.\\n' +\n 'Two modes: \"simple\" (minimal params, auto-optimized) and \"calculate\" (full control).\\n' +\n 'Use --save flag to persist the study to the database.'\n );\n\n // --- simple ---\n solarform\n .command('simple')\n .description(\n 'Create a solar study with minimal parameters (simplified mode).\\n' +\n 'Automatically resolves location from region/subregion, applies consumption patterns,\\n' +\n 'and optimizes kit selection.\\n\\n' +\n 'Consumption patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Consumption mode: monthlyConsumption (kWh) or monthlySpending (EUR)\\n' +\n 'Excesses modes: PPA, gridSelling, noInjection, virtualBattery\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform simple --region \"Andalucía\" --sub-region \"Sevilla\" --consumption 5000\\n' +\n ' suntropy solarform simple --region \"Cataluña\" --sub-region \"Barcelona\" --consumption 300 --consumption-mode monthlySpending --save\\n' +\n ' suntropy solarform simple --region \"Madrid\" --sub-region \"Madrid\" --consumption 8000 --pattern Domestic --kit-id abc123 --save'\n )\n .requiredOption('--region <name>', 'Region name (must exist in database)')\n .requiredOption('--sub-region <name>', 'Sub-region name')\n .requiredOption('--consumption <value>', 'Consumption value (kWh or EUR depending on --consumption-mode)')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial', 'Balance')\n .option('--consumption-mode <mode>', 'monthlyConsumption (kWh) or monthlySpending (EUR)', 'monthlyConsumption')\n .option('--kit-id <id>', 'Use a specific solar kit instead of auto-optimization')\n .option('--excesses-mode <mode>', 'Excesses compensation: PPA, gridSelling, noInjection, virtualBattery')\n .option('--assigned-user <uid>', 'Assign study to a user UID')\n .option('--email <email>', 'Send results to this email')\n .option('--save', 'Save study to database')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body: Record<string, unknown> = {\n region: opts.region,\n subRegion: opts.subRegion,\n selectedConsumptionPattern: opts.pattern,\n consumptionQuantity: parseFloat(opts.consumption),\n consumptionQuantityIntroductionMode: opts.consumptionMode,\n };\n\n if (opts.assignedUser) body.assignedUserUID = opts.assignedUser;\n\n // Build query params\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n if (opts.kitId) params.solarKitId = opts.kitId;\n if (opts.excessesMode) params.excessesCompensationMode = opts.excessesMode;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form/simple${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate ---\n solarform\n .command('calculate')\n .description(\n 'Create a solar study with full control over all parameters.\\n' +\n 'Pass the complete SimplifiedSolarStudy body as JSON.\\n\\n' +\n 'Required body fields:\\n' +\n ' center: { lat, lng } — Installation coordinates\\n' +\n ' surfaces: [{ path, inclination, orientation }] — Panel surfaces\\n' +\n ' consumptionMode: \"cups\" | \"consumptionPatterns\"\\n' +\n ' clientDetails: { name, email, phone }\\n\\n' +\n 'Optional: atrTariff, geographicalZone, location, contractedPower,\\n' +\n ' monthPeriodConsumptionDictionary, selectedConsumptionPattern,\\n' +\n ' consumptionQuantity, consumptionQuantityIntroductionMode\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform calculate --data \\'{\"center\":{\"lat\":37.39,\"lng\":-5.99},...}\\' --save\\n' +\n ' cat study-input.json | suntropy solarform calculate --data - --save --email client@co.com'\n )\n .requiredOption('--data <json>', 'Full SimplifiedSolarStudy JSON body (or - for stdin)')\n .option('--save', 'Save study to database')\n .option('--email <email>', 'Send results to this email')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body = await parseData(opts.data);\n if (!body) {\n outputError(new Error('--data is required. Pass JSON or - for stdin.'));\n return;\n }\n\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n if (!study || (typeof study === 'object' && !Array.isArray(study) && !('selectedSolarStudyMode' in (study as Record<string, unknown>)))) {\n outputError(new Error('API returned no study data. The /api/solar-form endpoint requires a complete body with: center, surfaces, consumptionMode, and typically locationMode. Use \"solarform simple\" for minimal-parameter study creation.'));\n return;\n }\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- config ---\n solarform\n .command('config')\n .description(\n 'Get the solar form configuration for the authenticated client.\\n' +\n 'Returns form settings, appearance, enabled steps, custom fields, etc.'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-form/solar-form-config');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- statistics ---\n solarform\n .command('statistics')\n .description(\n 'List or create solar form submission statistics.\\n' +\n 'Used for tracking form analytics and conversion data.'\n )\n .option('--create', 'Create a new statistics entry')\n .option('--update', 'Update an existing statistics entry')\n .option('--data <json>', 'Statistics data as JSON')\n .option('--stats-id <id>', 'Statistics ID (for update or linking)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n if (opts.update) {\n const body = await parseData(opts.data);\n const res = await client.put('/solar-form/solar-form-statistics', body);\n output(res.data, global);\n } else if (opts.create) {\n const body = (await parseData(opts.data)) || {};\n const params: Record<string, string> = {};\n if (opts.statsId) params.statsId = opts.statsId;\n const res = await client.post('/solar-form/solar-form-statistics', body, { params });\n output(res.data, global);\n } else {\n outputError(new Error('Specify --create or --update'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerPPACommands(program: Command): void {\n const ppa = program.command('ppa').description(\n 'PPA (Power Purchase Agreement) analysis.\\n' +\n 'Read PPA templates and run PPA simulations on a solar study.'\n );\n\n // --- ppa templates (read-only sub-group) ---\n const templates = ppa\n .command('templates')\n .description('Read-only access to the client PPA templates.');\n\n templates\n .command('list')\n .description(\n 'List all PPA templates for the authenticated client.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates list --fields _id,name,mode,ppaPrice,useInSolarForm'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/ppa-templates');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n templates\n .command('get <id>')\n .description(\n 'Get a single PPA template by its Mongo _id.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates get 665f0a1b2c3d4e5f60718293'\n )\n .action(async (id: string) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/ppa-templates/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ppa calculate ---\n ppa\n .command('calculate')\n .description(\n 'Run PPA simulations on a solar study (read-only, does not persist).\\n\\n' +\n 'Provide the study via --study <id> (downloaded from the API) or --data <json>|- (full SolarStudy).\\n' +\n 'With --template <ppaTemplateId> the simulation uses that single PPA template;\\n' +\n 'without it, the backend uses the client templates flagged useInSolarForm.\\n\\n' +\n 'Note: the study must include consumption and economicResults (a study fetched\\n' +\n 'by --study already does). The response is the study with economicResults.ppaAnalysis populated.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy ppa calculate --study 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy ppa calculate --study 665f... --template 6700aa11bb22cc33dd44ee55\\n' +\n ' cat study.json | suntropy ppa calculate --data -'\n )\n .option('--study <id>', 'Solar study Mongo id to download and analyze')\n .option('--data <json>', 'Full SolarStudy JSON body (or - for stdin)')\n .option('--template <ppaTemplateId>', 'PPA template id to apply (defaults to client useInSolarForm templates)')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n\n let study: unknown;\n if (opts.study) {\n const res = await client.get(`/solar-study/findById/${opts.study}`);\n study = res.data;\n } else if (opts.data) {\n study = await parseData(opts.data);\n } else {\n outputError(new Error('Provide --study <id> or --data <json>|- (full SolarStudy).'));\n return;\n }\n\n const body: Record<string, unknown> = { data: study };\n if (opts.template) body.ppaTemplateId = opts.template;\n\n const res = await client.post('/solar-study/calculate-ppa-on-study', body);\n const result = opts.raw ? res.data : compactStudyOutput(res.data);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function registerShareableCommands(program: Command): void {\n const shareables = program.command('shareables').description(\n 'Create shareable links for studies (sharing service, exposed under /templates).'\n );\n\n // --- create ---\n shareables\n .command('create')\n .description(\n 'Create a shareable link for a study (POST /shareable).\\n' +\n 'The backend fills uid, url, clientUID and idShareable from the token.\\n\\n' +\n 'elementType: solarStudy (default), colectiveSolarStudy, veChargerStudy, heatpumpStudy, billing\\n' +\n 'shareableType: TEMPLATE (default), CONTRACT\\n' +\n 'privacy: PUBLIC (default), PRIVATE (use --password)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy shareables create --element-id 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy shareables create --element-id 665f... --template-id 6700aa... --name \"Estudio Juan\"\\n' +\n ' suntropy shareables create --element-id 665f... --privacy PRIVATE --password secret --email-list \"a@x.com;b@y.com\"\\n' +\n ' suntropy shareables create --element-id 665f... --expiration-date 2026-12-31 --link-params \"utm_source=cli\"'\n )\n .requiredOption('--element-id <id>', 'Id of the element (study) to share')\n .option('--element-type <type>', 'solarStudy | colectiveSolarStudy | veChargerStudy | heatpumpStudy | billing', 'solarStudy')\n .option('--shareable-type <type>', 'TEMPLATE | CONTRACT', 'TEMPLATE')\n .option('--privacy <privacy>', 'PUBLIC | PRIVATE', 'PUBLIC')\n .option('--template-id <id>', 'Template id to apply to the shareable')\n .option('--name <name>', 'Descriptive name for the shareable')\n .option('--password <pwd>', 'Protect the link with a password (implies PRIVATE)')\n .option('--expiration-date <date>', 'Expiration date (e.g. 2026-12-31)')\n .option('--activation-date <date>', 'Activation date (e.g. 2026-01-01)')\n .option('--email-list <emails>', 'Semicolon-separated list of recipient emails')\n .option('--reply-to <email>', 'Reply-to email for notifications')\n .option('--custom-layout', 'Enable custom layout')\n .option('--read-only', 'Mark the shareable as read-only')\n .option('--link-params <qs>', 'Extra query params appended to the shareable link (k=v&k2=v2)')\n .option('--data <json>', 'Extra ShareableDto fields as JSON (or - for stdin), merged last')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(shareables);\n const client = createServiceClient('templates', global);\n\n const extra = (await parseData(opts.data)) || {};\n const body: Record<string, unknown> = {\n elementId: opts.elementId,\n elementType: opts.elementType,\n shareableType: opts.shareableType,\n privacy: opts.password ? 'PRIVATE' : opts.privacy,\n ...(opts.templateId ? { templateId: opts.templateId } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n ...(opts.password ? { password: opts.password, passwordConfirm: opts.password } : {}),\n ...(opts.expirationDate ? { expirationDate: opts.expirationDate } : {}),\n ...(opts.activationDate ? { activationDate: opts.activationDate } : {}),\n ...(opts.emailList ? { emailList: opts.emailList } : {}),\n ...(opts.replyTo ? { replyTo: opts.replyTo } : {}),\n ...(opts.customLayout ? { customLayout: true } : {}),\n ...(opts.readOnly ? { readOnly: true } : {}),\n ...extra,\n };\n\n const url = opts.linkParams ? `/shareable?${opts.linkParams}` : '/shareable';\n const res = await client.post(url, body);\n output(res.data, { ...global, save: global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerTemplatesCommands(program: Command): void {\n const templates = program.command('templates').description(\n 'Read client document templates (id + name), proxied via solar from the sharing service.'\n );\n\n // --- list ---\n templates\n .command('list')\n .description(\n 'List templates returning only _id and templateName (GET /api/templates).\\n' +\n 'Defaults to the solar study templates (--type solarStudy).\\n\\n' +\n 'Types: solarStudy (default) | colectiveSolarStudy | veChargerStudy.\\n' +\n 'Use --type generic for the generic (untyped) templates.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy templates list\\n' +\n ' suntropy templates list --type colectiveSolarStudy\\n' +\n ' suntropy templates list --type generic --fields _id,templateName --format csv'\n )\n .option(\n '--type <identifier>',\n 'solarStudy (default) | colectiveSolarStudy | veChargerStudy | generic',\n 'solarStudy',\n )\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(templates);\n const client = createServiceClient('solar', global);\n\n const params: Record<string, string> = {};\n // 'generic' means the untyped templates -> omit the identifier so the\n // backend forwards no filter (sharing returns templateIdentifier: null).\n if (opts.type && opts.type !== 'generic') {\n params.templateIdentifier = opts.type;\n }\n\n const res = await client.get('/api/templates', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\ninterface GeocodeResult {\n formattedAddress: string;\n lat: number;\n lng: number;\n locationType: string;\n placeId: string;\n types: string[];\n addressComponents: { longName: string; shortName: string; types: string[] }[];\n}\n\ninterface GeocodeResponse {\n status: 'OK' | 'ZERO_RESULTS';\n count: number;\n results: GeocodeResult[];\n}\n\n/** Envelope returned by the solar public API (/api/*). */\ninterface PublicApiResponse<T> {\n code?: number;\n error?: { code?: string; message?: string };\n warning?: { code?: string; message?: string };\n data?: T;\n}\n\n/**\n * Unwrap the PublicApiResponse envelope, print the best match by default (or the\n * full candidate list with --all), and surface API-level errors consistently.\n */\nfunction emit(\n envelope: PublicApiResponse<GeocodeResponse>,\n all: boolean | undefined,\n query: Record<string, unknown>,\n global: OutputOptions,\n): void {\n if (envelope.error) {\n outputError({\n error: true,\n status: envelope.code,\n message: envelope.error.message || envelope.error.code || 'Geocoding error',\n details: envelope.error,\n });\n return;\n }\n\n const data = envelope.data;\n if (!data) {\n output({ found: false, ...query }, global);\n return;\n }\n if (all) {\n output(data.results, global);\n return;\n }\n if (data.count === 0) {\n output({ found: false, ...query }, global);\n return;\n }\n output(data.results[0], global);\n}\n\nexport function registerGeocodeCommands(program: Command): void {\n const geocode = program.command('geocode').description(\n 'Geocoding via the solar service (proxy to Google Geocoding API).\\n' +\n 'Resolve an address into coordinates and vice versa.',\n );\n\n // --- geocode resolve (address -> coordinates) ---\n geocode\n .command('resolve')\n .description(\n 'Resolve an address into coordinates (lat/lng + formatted address).\\n' +\n 'Examples:\\n' +\n ' suntropy geocode resolve --address \"Calle Mayor 1, Madrid\"\\n' +\n ' suntropy geocode resolve --address \"Gran Vía, Madrid\" --country es --all',\n )\n .requiredOption('--address <string>', 'Address to geocode (quote it)')\n .option('--country <code>', 'Bias results to a country (ISO code, e.g. es, pt, it)')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/geocode',\n { params: { address: opts.address, country: opts.country } },\n );\n emit(res.data, opts.all, { address: opts.address }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- geocode reverse (coordinates -> address) ---\n geocode\n .command('reverse')\n .description(\n 'Resolve coordinates into an address (reverse geocoding).\\n' +\n 'Example:\\n' +\n ' suntropy geocode reverse --lat 40.4168 --lng -3.7038',\n )\n .requiredOption('--lat <number>', 'Latitude')\n .requiredOption('--lng <number>', 'Longitude')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/reverse-geocode',\n { params: { lat: opts.lat, lng: opts.lng } },\n );\n emit(res.data, opts.all, { lat: opts.lat, lng: opts.lng }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command, Option } from 'commander';\nimport { createServiceClient, handleApiError, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/**\n * Well-known Suntropy user identity for the Alexandria agent. The front resolves\n * this uid to Alexandria's name/avatar (see `isAlexandriaComment`), so a\n * notification whose `fromUserUid` is this value is rendered as coming FROM\n * Alexandria — not as a self-notification from the acting user whose token the\n * CLI runs with.\n */\nconst ALEXANDRIA_USER_UID = 'alexandria';\n\nconst SEVERITIES = ['info', 'warning', 'urgent'] as const;\ntype Severity = (typeof SEVERITIES)[number];\n\nexport function registerNotificationsCommands(program: Command): void {\n const notifications = program\n .command('notifications')\n .description(\n 'Send in-app (and email) notifications to Suntropy users.\\n' +\n 'Useful for Alexandria to proactively tell a user a task is done, since a\\n' +\n 'direct/email execution leaves no study comment (and thus no auto-notification).',\n );\n\n // --- send ---\n notifications\n .command('send')\n .description(\n 'Send a notification to a user. It appears in the recipient\\'s notification\\n' +\n 'bell and, if enabled in their config, is also emailed. Sent FROM Alexandria\\n' +\n 'by default so it is not shown as a self-notification.\\n' +\n 'Examples:\\n' +\n ' suntropy notifications send --to-user <userUID> --message \"He terminado el estudio.\"\\n' +\n ' suntropy notifications send --to-user <userUID> --title \"Estudio listo\" \\\\\\n' +\n ' --message \"Revisa los resultados.\" --study <solarStudyId> --mention',\n )\n .requiredOption('--to-user <userUID>', 'Recipient userUID (who gets notified)')\n .requiredOption('--message <text>', 'Notification body (supports Markdown)')\n .option('--title <text>', 'Notification title', 'Alexandria')\n .option('--severity <severity>', `Severity: ${SEVERITIES.join(' | ')}`, 'info')\n .option(\n '--mention',\n 'Send as a mention (type new_mention) instead of an update (new_comment). ' +\n 'Mentions are gated by the user\\'s \"mention\" notification setting.',\n )\n .option(\n '--study <solarStudyId>',\n 'Link the notification to a solar study: makes it click-through to that study',\n )\n .option('--link <url>', 'Custom link for the email call-to-action')\n .option(\n '--from-user <userUID>',\n 'Sender userUID shown as the author (default: the authenticated user)',\n )\n // Hidden flag mirroring `studies comment --as-alexandria`: signs the\n // notification as Alexandria (fromUserUid = \"alexandria\", which the front\n // resolves to Alexandria's name/avatar). Omitted from --help; the agent is\n // instructed to use it. `--from-user` still takes precedence if provided.\n .addOption(new Option('--as-alexandria').hideHelp())\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(notifications);\n\n const severity = opts.severity as Severity;\n if (!SEVERITIES.includes(severity)) {\n throw new Error(\n `Invalid --severity \"${opts.severity}\". Use one of: ${SEVERITIES.join(', ')}.`,\n );\n }\n // A linked study must be an actual study _id (24-hex ObjectId), or the\n // click-through would point nowhere.\n if (opts.study) assertStudyObjectId(opts.study);\n\n const client = createServiceClient('notifications', global);\n\n // Sender identity: explicit --from-user wins; else --as-alexandria signs\n // it as Alexandria; else fall back to the authenticated user (a plain\n // user-to-user notification).\n const profile = getActiveProfile(loadConfig());\n const fromUserUid = opts.fromUser\n ? opts.fromUser\n : opts.asAlexandria\n ? ALEXANDRIA_USER_UID\n : profile.userUID;\n\n const notification = {\n notificationType: opts.mention ? 'new_mention' : 'new_comment',\n severity,\n origin: opts.asAlexandria ? 'ALEXANDRIA' : 'CLI',\n fromUserUid,\n toUserUid: opts.toUser,\n notificationContent: {\n contentType: 'COMMENT',\n name: opts.title,\n description: opts.message,\n ...(opts.study ? { externalId: opts.study } : {}),\n ...(opts.link ? { link: opts.link } : {}),\n // The notifications backend only persists notificationContent when a\n // `data` payload is present (the OneToOne isn't cascaded), so without\n // this the notification renders blank in the bell. Always send a\n // small data object; harmless once the backend also persists content\n // without it. Not read by the front for these types.\n data: {\n source: opts.asAlexandria ? 'alexandria' : 'cli',\n ...(opts.study ? { studyId: opts.study } : {}),\n },\n },\n };\n\n // `@Controller('notifications')` behind the `/notifications` gateway\n // prefix → the create route is `/notifications`. clientUID/creator come\n // from the JWT; `toUserUid` in the body is the recipient.\n const res = await client.post('/notifications', notification);\n\n // The service returns the created Notification, or a string reason when\n // the client/type has notifications disabled — surface both clearly.\n if (typeof res.data === 'string') {\n output(\n { sent: false, reason: res.data, toUser: opts.toUser },\n global,\n );\n return;\n }\n output(\n {\n sent: true,\n notificationId: res.data?.idNotification,\n toUser: opts.toUser,\n type: notification.notificationType,\n severity,\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import type { Command } from 'commander';\nimport { loadConfig, saveConfig } from './config.js';\n\n/**\n * Command access profiles (\"permission tiers\").\n *\n * The CLI can be locked to a permission tier so that only a subset of commands\n * is registered. Tiers are CUMULATIVE:\n *\n * read ⊂ write (read + write) ⊂ delete (read + write + delete = full)\n *\n * Commands above the active tier are pruned from the command tree before\n * parsing, so they (a) never appear in `--help` and (b) when invoked, Commander\n * reports them natively as `error: unknown command 'X'` — i.e. \"the command\n * does not exist\". This is an admin/automation control (e.g. to constrain the\n * Alexandria agent's sandbox to read-only). It is intentionally not advertised\n * in the user-facing help; it is driven by the hidden `command-profile` command\n * or the SUNTROPY_COMMAND_PROFILE environment variable.\n */\nexport type CommandTier = 'read' | 'write' | 'delete';\n\nexport const COMMAND_TIERS: CommandTier[] = ['read', 'write', 'delete'];\n\nconst TIER_VALUE: Record<CommandTier, number> = { read: 0, write: 1, delete: 2 };\n\n/** Default when nothing is configured: full access (legacy behavior). */\nexport const DEFAULT_TIER: CommandTier = 'delete';\n\nexport const ENV_VAR = 'SUNTROPY_COMMAND_PROFILE';\n\nexport function tierValue(t: CommandTier): number {\n return TIER_VALUE[t];\n}\n\nexport function isValidTier(value: unknown): value is CommandTier {\n return typeof value === 'string' && (COMMAND_TIERS as string[]).includes(value);\n}\n\nexport interface ResolvedCommandProfile {\n tier: CommandTier;\n source: 'env' | 'config' | 'default';\n /** Raw env value when present but invalid (for diagnostics). */\n invalidEnv?: string;\n}\n\n/**\n * Resolve the active tier. Precedence: env var > config file > default.\n * Pure (no side effects) so it can be called from both the gating step and the\n * `command-profile` status command.\n */\nexport function getActiveCommandProfile(): ResolvedCommandProfile {\n const envRaw = process.env[ENV_VAR]?.trim();\n if (envRaw) {\n const envNorm = envRaw.toLowerCase();\n if (isValidTier(envNorm)) return { tier: envNorm, source: 'env' };\n // Invalid env value: fall through to config/default but report it.\n const fallback = resolveFromConfig();\n return { ...fallback, invalidEnv: envRaw };\n }\n return resolveFromConfig();\n}\n\nfunction resolveFromConfig(): ResolvedCommandProfile {\n try {\n const cfg = loadConfig();\n if (isValidTier(cfg.commandProfile)) return { tier: cfg.commandProfile, source: 'config' };\n } catch {\n // ignore: fall back to default\n }\n return { tier: DEFAULT_TIER, source: 'default' };\n}\n\n/** Persist (or clear, when null) the stored command profile. */\nexport function setStoredCommandProfile(tier: CommandTier | null): void {\n const cfg = loadConfig();\n if (tier === null) delete cfg.commandProfile;\n else cfg.commandProfile = tier;\n saveConfig(cfg);\n}\n\n// ─── Classification ───────────────────────────────────────────────────────\n//\n// A command's tier is the MAX tier over the verbs in its path. Verbs are the\n// command/group names, so e.g. `studies set name` inherits `write` from `set`,\n// and `inventory kits panels delete` inherits `delete` from `delete`.\n\nconst DELETE_VERBS = new Set(['delete', 'delete-batch', 'archive']);\n\nconst WRITE_VERBS = new Set([\n 'create', 'update', 'edit', 'set', 'add', 'remove', 'assemble', 'featured',\n 'save', 'init', 'init-default', 'add-comment', 'comment', 'send',\n 'calculate-results', 'optimize-peakpower',\n]);\n\n/**\n * Explicit overrides for paths whose verbs are ambiguous. `studies calculate\n * production` writes to the local draft (write), but the bare verb `calculate`\n * is also used by pure-compute commands (`ppa calculate`, `solarform calculate`,\n * `studies calculate-production`) that are read-only — so `calculate` is NOT a\n * global write verb; this path is pinned instead.\n */\nconst PATH_OVERRIDES: Record<string, CommandTier> = {\n 'studies calculate production': 'write',\n};\n\nexport function classifyPath(segs: string[]): CommandTier {\n const key = segs.join(' ');\n if (PATH_OVERRIDES[key]) return PATH_OVERRIDES[key];\n let tier: CommandTier = 'read';\n for (const seg of segs) {\n if (DELETE_VERBS.has(seg)) return 'delete';\n if (WRITE_VERBS.has(seg)) tier = 'write';\n }\n return tier;\n}\n\n// ─── Exemptions ───────────────────────────────────────────────────────────\n//\n// CLI plumbing that must always work regardless of the active tier: you always\n// need to authenticate, configure the CLI, and manage the command profile\n// itself. NOTE: only the *local* `config` leaves are exempt — the tenant\n// configuration subtrees (`config theme`, `config solarform …`) hit the backend\n// and are gated like any other business command.\n\nconst EXEMPT_CONFIG_LEAVES = new Set(['set', 'get', 'list', 'create-profile', 'use']);\n\nexport function isExemptPath(segs: string[]): boolean {\n if (segs[0] === 'auth') return true;\n if (segs[0] === 'command-profile') return true;\n if (segs[0] === 'config' && segs.length === 2 && EXEMPT_CONFIG_LEAVES.has(segs[1])) return true;\n return false;\n}\n\n// ─── Pruning ──────────────────────────────────────────────────────────────\n\n/**\n * Prune the command tree in place according to the active command profile.\n * Returns the resolved tier so the caller can surface it if needed.\n */\nexport function applyCommandProfile(program: Command): ResolvedCommandProfile {\n const resolved = getActiveCommandProfile();\n pruneChildren(program, [], tierValue(resolved.tier));\n return resolved;\n}\n\nfunction pruneChildren(parent: Command, parentSegs: string[], max: number): void {\n const kept = parent.commands.filter((child) => {\n const segs = [...parentSegs, child.name()];\n return keepCommand(child, segs, max);\n });\n // Commander types `commands` as readonly, but pruning must replace its\n // contents. Mutate the array in place (rather than reassigning the property)\n // so Commander keeps using the same reference for help and dispatch.\n const mutable = parent.commands as Command[];\n mutable.length = 0;\n mutable.push(...kept);\n}\n\nfunction keepCommand(cmd: Command, segs: string[], max: number): boolean {\n if (cmd.commands.length > 0) {\n // Group: prune its descendants first, then keep it only if something\n // survived (or it's an exempt subtree).\n pruneChildren(cmd, segs, max);\n if (cmd.commands.length > 0) return true;\n return isExemptPath(segs);\n }\n // Leaf:\n if (isExemptPath(segs)) return true;\n return tierValue(classifyPath(segs)) <= max;\n}\n","import { Command } from 'commander';\nimport { output, outputError, type OutputOptions } from '../output.js';\nimport {\n COMMAND_TIERS,\n DEFAULT_TIER,\n ENV_VAR,\n getActiveCommandProfile,\n isValidTier,\n setStoredCommandProfile,\n} from '../access.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as OutputOptions;\n}\n\n/**\n * Hidden admin command to manage the CLI command access profile (permission\n * tier). Registered with `{ hidden: true }` so it never shows in `--help`, but\n * remains invocable in any tier (it is exempt from gating). Changes take effect\n * on the next invocation, since gating happens at startup.\n *\n * suntropy command-profile show the active tier + source\n * suntropy command-profile read lock the CLI to read-only\n * suntropy command-profile write allow read + write\n * suntropy command-profile delete allow everything (default)\n * suntropy command-profile reset clear the stored value (back to default)\n */\nexport function registerCommandProfileCommand(program: Command): void {\n program\n .command('command-profile [tier]', { hidden: true })\n .description('Admin: get/set the command access profile (read | write | delete | reset)')\n .action((tier?: string) => {\n try {\n const global = getGlobalOpts(program);\n\n // No argument → report current state.\n if (!tier) {\n const resolved = getActiveCommandProfile();\n output(\n {\n commandProfile: resolved.tier,\n source: resolved.source,\n ...(resolved.invalidEnv\n ? { warning: `Ignoring invalid ${ENV_VAR}=\"${resolved.invalidEnv}\" (expected: ${COMMAND_TIERS.join(' | ')})` }\n : {}),\n available: COMMAND_TIERS,\n envVar: ENV_VAR,\n },\n global,\n );\n return;\n }\n\n const value = tier.trim().toLowerCase();\n\n if (value === 'reset') {\n setStoredCommandProfile(null);\n const resolved = getActiveCommandProfile();\n output(\n {\n success: true,\n message: `Stored command profile cleared. Effective tier: ${resolved.tier} (${resolved.source}).`,\n commandProfile: resolved.tier,\n source: resolved.source,\n },\n global,\n );\n return;\n }\n\n if (!isValidTier(value)) {\n outputError(new Error(`Invalid tier \"${tier}\". Expected one of: ${COMMAND_TIERS.join(', ')}, or \"reset\".`));\n return;\n }\n\n setStoredCommandProfile(value);\n const envOverride = getActiveCommandProfile();\n const message =\n envOverride.source === 'env'\n ? `Stored command profile set to \"${value}\", but ${ENV_VAR}=\"${process.env[ENV_VAR]}\" overrides it (effective: ${envOverride.tier}). Unset the env var for the stored value to apply.`\n : `Command profile set to \"${value}\". Takes effect on the next command.`;\n output(\n {\n success: true,\n commandProfile: value,\n effectiveTier: envOverride.tier,\n effectiveSource: envOverride.source,\n default: DEFAULT_TIER,\n message,\n },\n global,\n );\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { createProgram } from '../src/index.js';\n\nconst program = createProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n process.stderr.write(JSON.stringify({ error: true, message: err.message }) + '\\n');\n process.exit(1);\n});\n"],"mappings":"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","names":["Command","writeFileSync","program","hadToken","readFileSync","writeFileSync","join","getGlobalOpts","getGlobalOpts","getGlobalOpts","getGlobalOpts","program","getGlobalOpts","readFileSync","getGlobalOpts","parseData","readFileSync","res","getGlobalOpts","getGlobalOpts","parseData","program","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","getGlobalOpts","getGlobalOpts","program","readFileSync","getGlobalOpts","readFileSync","program","readFileSync","getGlobalOpts","program","readFileSync","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","readStdin","parseData","compactStudyOutput","program","res","getGlobalOpts","readStdin","parseData","program","getGlobalOpts","program","getGlobalOpts","program","Option","getGlobalOpts","program","Option","program","getGlobalOpts","program","program","Command"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/config.ts","../../src/client.ts","../../src/output.ts","../../src/commands/auth.ts","../../src/commands/config/shared.ts","../../src/commands/config/theme.ts","../../src/commands/config/advanced.ts","../../src/commands/config/solarform.ts","../../src/commands/config.ts","../../src/commands/inventory/factory.ts","../../src/commands/inventory/kits.ts","../../src/commands/inventory/manufacturers.ts","../../src/commands/inventory/custom-fields.ts","../../src/commands/inventory/index.ts","../../src/commands/studies/builder.ts","../../../suntropy-cli/node_modules/uuid/dist/esm-node/rng.js","../../../suntropy-cli/node_modules/uuid/dist/esm-node/regex.js","../../../suntropy-cli/node_modules/uuid/dist/esm-node/validate.js","../../../suntropy-cli/node_modules/uuid/dist/esm-node/stringify.js","../../../suntropy-cli/node_modules/uuid/dist/esm-node/v4.js","../../src/commands/studies/index.ts","../../src/commands/curves/index.ts","../../src/commands/consumption/index.ts","../../src/commands/solarform/index.ts","../../src/commands/ppa/index.ts","../../src/commands/shareables/index.ts","../../src/commands/templates/index.ts","../../src/commands/geocode/index.ts","../../src/commands/notifications/index.ts","../../src/commands/satvolt/api.ts","../../src/commands/satvolt/campaigns.ts","../../src/commands/satvolt/pipeline.ts","../../src/commands/satvolt/fields.ts","../../src/commands/satvolt/leads.ts","../../src/commands/satvolt/export-tables.ts","../../src/commands/satvolt/templates.ts","../../src/commands/satvolt/index.ts","../../src/access.ts","../../src/commands/command-profile.ts","../../bin/suntropy.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerAuthCommands } from './commands/auth.js';\nimport { registerConfigCommands } from './commands/config.js';\nimport { registerInventoryCommands } from './commands/inventory/index.js';\nimport { registerStudiesCommands } from './commands/studies/index.js';\nimport { registerCurvesCommands } from './commands/curves/index.js';\nimport { registerConsumptionCommands } from './commands/consumption/index.js';\nimport { registerSolarformCommands } from './commands/solarform/index.js';\nimport { registerPPACommands } from './commands/ppa/index.js';\nimport { registerShareableCommands } from './commands/shareables/index.js';\nimport { registerTemplatesCommands } from './commands/templates/index.js';\nimport { registerGeocodeCommands } from './commands/geocode/index.js';\nimport { registerNotificationsCommands } from './commands/notifications/index.js';\nimport { registerSatvoltCommands } from './commands/satvolt/index.js';\nimport { registerCommandProfileCommand } from './commands/command-profile.js';\nimport { applyCommandProfile } from './access.js';\n\n// Injected at build time by tsup (define) from package.json. In dev (tsx, no\n// define) the identifier is undefined, so we fall back without throwing.\ndeclare const __CLI_VERSION__: string;\nconst CLI_VERSION = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : '0.0.0-dev';\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name('suntropy')\n .description('Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.')\n .version(CLI_VERSION)\n .option('--format <format>', 'Output format: json (default), human, csv', 'json')\n .option('--fields <fields>', 'Comma-separated fields to include in output')\n .option('--server <url>', 'Override API server URL')\n .option('--token <jwt>', 'Override authentication token')\n .option('--profile <name>', 'Use a specific config profile')\n .option('--verbose', 'Show HTTP request/response details on stderr')\n .option('--quiet', 'Suppress non-data output')\n .option('--save <file>', 'Save output to file (also writes to stdout)');\n\n registerAuthCommands(program);\n registerConfigCommands(program);\n registerInventoryCommands(program);\n registerStudiesCommands(program);\n registerCurvesCommands(program);\n registerConsumptionCommands(program);\n registerSolarformCommands(program);\n registerPPACommands(program);\n registerShareableCommands(program);\n registerTemplatesCommands(program);\n registerGeocodeCommands(program);\n registerNotificationsCommands(program);\n registerSatvoltCommands(program);\n\n // Hidden admin command to manage the command access profile. Registered last\n // and always exempt from gating, so it can raise/lower the tier from any tier.\n registerCommandProfileCommand(program);\n\n // Gate the command tree by the active permission tier (env > config > default\n // 'delete'). Commands above the tier are pruned: absent from --help and\n // reported as \"unknown command\" when invoked.\n applyCommandProfile(program);\n\n return program;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport interface SuntropyProfile {\n server: string;\n token?: string;\n authMethod?: 'api-key' | 'login';\n email?: string;\n clientUID?: string;\n userUID?: string;\n}\n\nexport interface SuntropyConfig {\n activeProfile: string;\n profiles: Record<string, SuntropyProfile>;\n /**\n * Command access profile (permission tier). Gates which commands are\n * registered/visible. Cumulative: read ⊂ write ⊂ delete. Absent → 'delete'\n * (full access, preserves legacy behavior). Managed via the hidden\n * `command-profile` admin command or the SUNTROPY_COMMAND_PROFILE env var.\n */\n commandProfile?: 'read' | 'write' | 'delete';\n}\n\nconst CONFIG_DIR = join(homedir(), '.suntropy');\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\nconst DEFAULT_CONFIG: SuntropyConfig = {\n activeProfile: 'default',\n profiles: {\n default: {\n server: 'https://api.enerlence.com',\n },\n },\n};\n\nfunction ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): SuntropyConfig {\n ensureConfigDir();\n if (!existsSync(CONFIG_FILE)) {\n writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));\n return { ...DEFAULT_CONFIG };\n }\n return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));\n}\n\nexport function saveConfig(config: SuntropyConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n}\n\nexport function getActiveProfile(config: SuntropyConfig, profileOverride?: string): SuntropyProfile {\n const name = profileOverride || config.activeProfile;\n const profile = config.profiles[name];\n if (!profile) {\n throw new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`);\n }\n return profile;\n}\n\nexport function setConfigValue(key: string, value: string, profileName?: string): void {\n const config = loadConfig();\n const name = profileName || config.activeProfile;\n if (!config.profiles[name]) {\n config.profiles[name] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[name] as Record<string, unknown>;\n profile[key] = value;\n saveConfig(config);\n}\n\nexport function getConfigValue(key: string, profileName?: string): unknown {\n const config = loadConfig();\n const profile = getActiveProfile(config, profileName);\n return (profile as Record<string, unknown>)[key];\n}\n\n/** Service path mapping */\nconst SERVICE_PATHS: Record<string, string> = {\n security: '/security',\n solar: '/solar',\n templates: '/templates',\n profiles: '/profiles',\n periods: '/periods',\n notifications: '/notifications',\n satvolt: '/satvolt',\n};\n\nconst LOCAL_PORTS: Record<string, number> = {\n security: 8080,\n solar: 8086,\n templates: 8090,\n profiles: 8085,\n periods: 8084,\n notifications: 8093,\n satvolt: 8099,\n};\n\nexport function getServiceUrl(baseServer: string, service: keyof typeof SERVICE_PATHS): string {\n // If baseServer looks like localhost without path, use port-based routing\n if (baseServer.includes('localhost') || baseServer.match(/:\\d+$/)) {\n const port = LOCAL_PORTS[service];\n const host = baseServer.replace(/:\\d+$/, '').replace(/\\/$/, '');\n return `${host}:${port}`;\n }\n // Production: path-based routing\n return `${baseServer.replace(/\\/$/, '')}${SERVICE_PATHS[service]}`;\n}\n","import axios, { AxiosInstance, AxiosError } from 'axios';\nimport { loadConfig, getActiveProfile, getServiceUrl, type SuntropyProfile } from './config.js';\n\nexport interface ClientOptions {\n server?: string;\n token?: string;\n profile?: string;\n verbose?: boolean;\n}\n\nexport interface ApiError {\n error: true;\n status: number;\n message: string;\n details?: unknown;\n}\n\nfunction resolveAuth(opts: ClientOptions): { server: string; token: string } {\n const config = loadConfig();\n const profile = getActiveProfile(config, opts.profile);\n const server = opts.server || profile.server;\n // Auth token resolution order: explicit --token flag > SUNTROPY_API_KEY env var > stored profile token.\n // The env var fallback lets host runtimes (e.g. ShellPilot) inject a just-in-time credential\n // without requiring a prior `auth login` / `auth set-key` to write the config file.\n const token = opts.token || process.env.SUNTROPY_API_KEY || profile.token;\n if (!token) {\n throw new Error('Not authenticated. Run: suntropy auth set-key --key <jwt> or suntropy auth login, or set the SUNTROPY_API_KEY env var.');\n }\n return { server, token };\n}\n\nexport function createServiceClient(service: 'security' | 'solar' | 'templates' | 'profiles' | 'periods' | 'notifications' | 'satvolt', opts: ClientOptions): AxiosInstance {\n const { server, token } = resolveAuth(opts);\n const baseURL = getServiceUrl(server, service);\n\n const client = axios.create({\n baseURL,\n timeout: 30000,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (opts.verbose) {\n client.interceptors.request.use((req) => {\n process.stderr.write(`→ ${req.method?.toUpperCase()} ${req.baseURL}${req.url}\\n`);\n if (req.data) process.stderr.write(` Body: ${JSON.stringify(req.data).slice(0, 200)}\\n`);\n return req;\n });\n client.interceptors.response.use(\n (res) => {\n process.stderr.write(`← ${res.status} (${JSON.stringify(res.data).length} bytes)\\n`);\n return res;\n },\n (err: AxiosError) => {\n process.stderr.write(`← ERROR ${err.response?.status || 'NETWORK'}: ${err.message}\\n`);\n return Promise.reject(err);\n },\n );\n }\n\n return client;\n}\n\n/** Unauthenticated client for login */\nexport function createUnauthClient(baseURL: string): AxiosInstance {\n return axios.create({\n baseURL,\n timeout: 15000,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\n/** A MongoDB ObjectId serializes to exactly 24 hexadecimal characters. */\nconst OBJECT_ID_RE = /^[a-f0-9]{24}$/i;\n\n/**\n * Guards a solar-study `_id` argument before it reaches the backend.\n *\n * `GET /solar-study/findById/:_id` runs `solarStudyModel.findOne({ _id })`,\n * which makes Mongoose cast the value to an ObjectId. A non-ObjectId string\n * (e.g. a UUID like a chat/shareable uid) throws a `CastError` server-side and\n * surfaces as an opaque **HTTP 500**, so the caller gets no hint about what\n * went wrong. Every real study `_id` is a 24-hex ObjectId, so we can reject\n * bad ids client-side with an actionable message instead.\n *\n * Throws so the caller's try/catch surfaces it via `outputError` (exit != 0).\n */\nexport function assertStudyObjectId(id: string): string {\n if (OBJECT_ID_RE.test(id)) return id;\n const looksLikeUuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id);\n const hint = looksLikeUuid\n ? `It looks like a UUID (e.g. a chat or shareable uid), not a study _id.`\n : `A study _id is a 24-character hex MongoDB ObjectId.`;\n throw new Error(\n `Invalid study id: \"${id}\". ${hint} ` +\n `Get the correct id from \\`suntropy studies list\\` (the \\`solarStudyId\\` field).`,\n );\n}\n\n/**\n * Validates that an API response body actually contains an entity.\n *\n * The solar backend returns `200` with an EMPTY body when `findById` /\n * `addSolarStudyComment` don't match a document (wrong id, or the id belongs to\n * a different clientUID / environment). Without this guard the CLI either\n * crashes downstream (`'_id' in data`, `data.solarStudyProgress = ...` on `\"\"`)\n * or — worse, for writes — reports `success` even though nothing was saved.\n *\n * Throws a clear, actionable error so the caller's try/catch surfaces it via\n * `outputError` with a non-zero exit code.\n */\nexport function assertFound<T>(data: T, entity: string, id: string): T {\n const isEmptyObject =\n data != null &&\n typeof data === 'object' &&\n !Array.isArray(data) &&\n Object.keys(data as Record<string, unknown>).length === 0;\n if (data == null || typeof data !== 'object' || Array.isArray(data) || isEmptyObject) {\n throw new Error(\n `${entity} not found: ${id}. The backend returned an empty response — ` +\n `verify the id is correct and belongs to your account and environment ` +\n `(the CLI and the app must point to the same backend).`,\n );\n }\n return data;\n}\n\nexport function handleApiError(err: unknown): ApiError {\n if (axios.isAxiosError(err)) {\n const ae = err as AxiosError;\n return {\n error: true,\n status: ae.response?.status || 0,\n message: ae.response?.statusText || ae.message,\n details: ae.response?.data,\n };\n }\n return {\n error: true,\n status: 0,\n message: err instanceof Error ? err.message : String(err),\n };\n}\n","import chalk from 'chalk';\nimport { writeFileSync } from 'fs';\n\nexport type OutputFormat = 'json' | 'human' | 'csv';\n\nexport interface OutputOptions {\n format?: OutputFormat;\n fields?: string;\n quiet?: boolean;\n save?: string;\n}\n\n/** Pick only specified fields from an object */\nfunction pickFields(obj: Record<string, unknown>, fields: string[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const f of fields) {\n if (f.includes('.')) {\n const parts = f.split('.');\n let val: unknown = obj;\n for (const p of parts) {\n val = val && typeof val === 'object' ? (val as Record<string, unknown>)[p] : undefined;\n }\n result[f] = val;\n } else {\n result[f] = obj[f];\n }\n }\n return result;\n}\n\nfunction applyFieldSelection(data: unknown, fields?: string): unknown {\n if (!fields) return data;\n const fieldList = fields.split(',').map((f) => f.trim());\n if (Array.isArray(data)) {\n return data.map((item) => pickFields(item as Record<string, unknown>, fieldList));\n }\n if (typeof data === 'object' && data !== null) {\n return pickFields(data as Record<string, unknown>, fieldList);\n }\n return data;\n}\n\nfunction formatHumanValue(val: unknown): string {\n if (val === null || val === undefined) return '-';\n if (typeof val === 'object') return JSON.stringify(val);\n return String(val);\n}\n\nfunction formatHuman(data: unknown): string {\n if (Array.isArray(data)) {\n if (data.length === 0) return chalk.dim('(empty)');\n const keys = Object.keys(data[0] as Record<string, unknown>);\n const widths = keys.map((k) => Math.max(k.length, ...data.map((r) => formatHumanValue((r as Record<string, unknown>)[k]).length)));\n const header = keys.map((k, i) => chalk.bold(k.padEnd(widths[i]))).join(' ');\n const rows = data.map((row) =>\n keys.map((k, i) => formatHumanValue((row as Record<string, unknown>)[k]).padEnd(widths[i])).join(' '),\n );\n return [header, keys.map((_, i) => '─'.repeat(widths[i])).join(' '), ...rows].join('\\n');\n }\n if (typeof data === 'object' && data !== null) {\n const entries = Object.entries(data as Record<string, unknown>);\n const maxKey = Math.max(...entries.map(([k]) => k.length));\n return entries.map(([k, v]) => `${chalk.bold(k.padEnd(maxKey))} ${formatHumanValue(v)}`).join('\\n');\n }\n return String(data);\n}\n\nfunction formatCsv(data: unknown): string {\n if (!Array.isArray(data)) {\n if (typeof data === 'object' && data !== null) data = [data];\n else return String(data);\n }\n const arr = data as Record<string, unknown>[];\n if (arr.length === 0) return '';\n const keys = Object.keys(arr[0]);\n const escape = (v: unknown) => {\n const s = v === null || v === undefined ? '' : String(v);\n return s.includes(',') || s.includes('\"') || s.includes('\\n') ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n return [keys.join(','), ...arr.map((r) => keys.map((k) => escape(r[k])).join(','))].join('\\n');\n}\n\nexport function output(data: unknown, opts: OutputOptions = {}): void {\n const filtered = applyFieldSelection(data, opts.fields);\n let text: string;\n\n switch (opts.format) {\n case 'human':\n text = formatHuman(filtered);\n break;\n case 'csv':\n text = formatCsv(filtered);\n break;\n default:\n text = JSON.stringify(filtered, null, 2);\n }\n\n process.stdout.write(text + '\\n');\n\n if (opts.save) {\n writeFileSync(opts.save, JSON.stringify(filtered, null, 2));\n }\n}\n\nexport function outputError(err: unknown): void {\n if (err && typeof err === 'object' && 'error' in err) {\n // ApiError object — include details\n const apiErr = err as { error: boolean; status?: number; code?: string; message?: string; details?: unknown };\n const out: Record<string, unknown> = { error: true, message: apiErr.message || 'Unknown error' };\n if (apiErr.status) out.status = apiErr.status;\n if (apiErr.code) out.code = apiErr.code;\n if (apiErr.details) out.details = apiErr.details;\n process.stderr.write(JSON.stringify(out) + '\\n');\n } else {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(JSON.stringify({ error: true, message: msg }) + '\\n');\n }\n process.exitCode = 1;\n}\n\n/** Wrap paginated response */\nexport function outputPaginated(data: unknown[], total: number, limit: number, offset: number, opts: OutputOptions = {}): void {\n if (opts.format === 'human') {\n const filtered = applyFieldSelection(data, opts.fields);\n const end = Math.min(offset + limit, total);\n process.stdout.write(chalk.dim(`Showing ${offset + 1}-${end} of ${total}\\n\\n`));\n process.stdout.write(formatHuman(filtered) + '\\n');\n } else {\n output({ data: applyFieldSelection(data, opts.fields), total, limit, offset, hasMore: offset + limit < total }, { ...opts, fields: undefined });\n }\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, getActiveProfile, getServiceUrl } from '../config.js';\nimport { createUnauthClient, createServiceClient, handleApiError } from '../client.js';\nimport { output, outputError, type OutputOptions } from '../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command('auth').description('Authentication management');\n\n // --- set-key (preferred for agents) ---\n auth\n .command('set-key')\n .description('Set an API key (JWT) for authentication. Preferred method for agents.')\n .requiredOption('--key <jwt>', 'JWT API key')\n .action(async (opts) => {\n try {\n // --server / --profile are global root options (see createProgram);\n // read them from there instead of redefining them locally, otherwise\n // Commander assigns them to the root and they never reach this action.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n profile.token = opts.key;\n profile.authMethod = 'api-key';\n if (global.server) profile.server = global.server as string;\n\n // Decode JWT to extract clientUID\n try {\n const payload = JSON.parse(Buffer.from(opts.key.split('.')[1], 'base64').toString());\n profile.clientUID = payload.clientUID;\n profile.userUID = payload.userUID;\n } catch {\n // If JWT decode fails, just save the key\n }\n\n saveConfig(config);\n output({ success: true, method: 'api-key', profile: profileName, clientUID: profile.clientUID, server: profile.server }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- login ---\n auth\n .command('login')\n .description('Login with email and password')\n .requiredOption('--email <email>', 'User email')\n .requiredOption('--password <password>', 'User password')\n .action(async (opts) => {\n try {\n // --server / --profile come from the global root options.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n config.profiles[profileName] = { server: 'https://api.enerlence.com' };\n }\n const profile = config.profiles[profileName];\n if (global.server) profile.server = global.server as string;\n\n const securityUrl = getServiceUrl(profile.server, 'security');\n const client = createUnauthClient(securityUrl);\n const res = await client.post('/auth/login', { email: opts.email, password: opts.password });\n\n if (res.data?.token?.access_token) {\n profile.token = res.data.token.access_token;\n profile.authMethod = 'login';\n profile.email = opts.email;\n profile.clientUID = res.data.user?.clientUID;\n profile.userUID = res.data.user?.userUID;\n saveConfig(config);\n output({\n success: true,\n method: 'login',\n profile: profileName,\n user: {\n email: res.data.user?.email,\n clientUID: res.data.user?.clientUID,\n userUID: res.data.user?.userUID,\n },\n }, getGlobalOpts(auth));\n } else {\n outputError(new Error(res.data?.errors?.[0]?.message || 'Login failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- status ---\n auth\n .command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n const profile = getActiveProfile(config, global.profile as string);\n if (!profile.token) {\n output({ authenticated: false, message: 'No token configured' }, getGlobalOpts(auth));\n return;\n }\n\n // Decode JWT to check expiry\n let expiresAt: string | undefined;\n let expired = false;\n try {\n const payload = JSON.parse(Buffer.from(profile.token.split('.')[1], 'base64').toString());\n if (payload.exp) {\n const expDate = new Date(payload.exp * 1000);\n expiresAt = expDate.toISOString();\n expired = expDate < new Date();\n }\n } catch {\n // ignore decode errors\n }\n\n output({\n authenticated: !expired,\n method: profile.authMethod || 'unknown',\n server: profile.server,\n email: profile.email,\n clientUID: profile.clientUID,\n userUID: profile.userUID,\n expiresAt,\n expired,\n }, getGlobalOpts(auth));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- refresh ---\n auth\n .command('refresh')\n .description('Refresh the current JWT token')\n .action(async () => {\n try {\n // --profile is a global root option.\n const globalOpts = getGlobalOpts(auth);\n const config = loadConfig();\n const profileName = (globalOpts.profile as string) || config.activeProfile;\n const client = createServiceClient('security', { ...globalOpts, profile: profileName });\n const res = await client.get('/auth/jwt/refreshToken');\n\n if (res.data?.access_token || res.data?.token?.access_token) {\n const newToken = res.data.access_token || res.data.token.access_token;\n config.profiles[profileName].token = newToken;\n saveConfig(config);\n output({ success: true, message: 'Token refreshed' }, getGlobalOpts(auth));\n } else {\n outputError(new Error('Refresh failed'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- logout ---\n auth\n .command('logout')\n .description(\n 'Clear stored credentials for the active profile (or --profile). Removes the\\n' +\n 'token and account identity but keeps the profile and its server URL.\\n' +\n 'Use --all to log out of every profile.'\n )\n .option('--all', 'Clear credentials for ALL profiles')\n .action(async (opts) => {\n try {\n // --profile is a global root option.\n const global = getGlobalOpts(auth);\n const config = loadConfig();\n\n // Strip credentials/identity from a profile, keep server. Returns\n // whether the profile actually had a token before clearing.\n const clearProfile = (name: string): boolean => {\n const profile = config.profiles[name];\n if (!profile) return false;\n const hadToken = !!profile.token;\n delete profile.token;\n delete profile.authMethod;\n delete profile.email;\n delete profile.clientUID;\n delete profile.userUID;\n return hadToken;\n };\n\n if (opts.all) {\n const names = Object.keys(config.profiles);\n const clearedWithToken = names.filter(clearProfile);\n saveConfig(config);\n output({\n success: true,\n message: `Logged out of ${names.length} profile(s).`,\n profiles: names,\n hadCredentials: clearedWithToken,\n }, global);\n return;\n }\n\n const profileName = (global.profile as string) || config.activeProfile;\n if (!config.profiles[profileName]) {\n outputError(new Error(`Profile \"${profileName}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n const hadToken = clearProfile(profileName);\n saveConfig(config);\n output({\n success: true,\n profile: profileName,\n message: hadToken\n ? `Logged out of profile \"${profileName}\". Credentials cleared (server kept).`\n : `Profile \"${profileName}\" had no stored credentials.`,\n }, global);\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync, writeFileSync, unlinkSync } from 'fs';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { spawnSync } from 'child_process';\nimport type { OutputOptions } from '../../output.js';\n\nexport type GlobalOpts = OutputOptions & Record<string, unknown>;\n\n/** Walk up to the root program and return its options. */\nexport function getGlobalOpts(cmd: Command): GlobalOpts {\n let root: Command = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as GlobalOpts;\n}\n\n/** Coerce a string value into boolean / number / JSON when it makes sense. */\nexport function coerceValue(raw: string): unknown {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n if (raw === 'null') return null;\n if (/^-?\\d+$/.test(raw)) return parseInt(raw, 10);\n if (/^-?\\d*\\.\\d+$/.test(raw)) return parseFloat(raw);\n if ((raw.startsWith('{') && raw.endsWith('}')) || (raw.startsWith('[') && raw.endsWith(']'))) {\n try { return JSON.parse(raw); } catch { /* fall through to string */ }\n }\n return raw;\n}\n\n/** Parse an array of `--set key=value` entries into a flat object. */\nexport function parseSetFlags(entries: string[] | undefined): Record<string, unknown> {\n if (!entries || entries.length === 0) return {};\n const out: Record<string, unknown> = {};\n for (const entry of entries) {\n const eq = entry.indexOf('=');\n if (eq < 0) throw new Error(`Invalid --set value \"${entry}\" (expected key=value)`);\n const key = entry.slice(0, eq).trim();\n const rawVal = entry.slice(eq + 1);\n if (!key) throw new Error(`Invalid --set value \"${entry}\" (empty key)`);\n out[key] = coerceValue(rawVal);\n }\n return out;\n}\n\n/** Load a JSON file (absolute or relative path). */\nexport function loadFromFile(path: string): Record<string, unknown> {\n const raw = readFileSync(path, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`File ${path} must contain a JSON object at the top level`);\n }\n return parsed as Record<string, unknown>;\n}\n\n/** Pick a subset of keys from an object (shallow). */\nexport function pickKeys<T extends Record<string, unknown>>(obj: T | undefined | null, keys: readonly string[]): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (!obj) return out;\n for (const k of keys) {\n if (k in obj) out[k] = (obj as Record<string, unknown>)[k];\n }\n return out;\n}\n\n/** Build a merge payload from: --from-file, --set key=value, and direct flag mappings. */\nexport function buildPayload(\n flagValues: Record<string, unknown>,\n setEntries: string[] | undefined,\n fromFile: string | undefined,\n allowedKeys?: readonly string[],\n): Record<string, unknown> {\n const payload: Record<string, unknown> = {};\n if (fromFile) Object.assign(payload, loadFromFile(fromFile));\n if (setEntries) Object.assign(payload, parseSetFlags(setEntries));\n for (const [k, v] of Object.entries(flagValues)) {\n if (v !== undefined) payload[k] = v;\n }\n if (allowedKeys) {\n for (const k of Object.keys(payload)) {\n if (!allowedKeys.includes(k)) {\n throw new Error(`Field \"${k}\" does not belong to this section. Allowed: ${allowedKeys.join(', ')}`);\n }\n }\n }\n return payload;\n}\n\n/** Open $EDITOR (or vi) on a JSON blob and return the parsed result. */\nexport function editJson(initial: unknown, filenameHint = 'config'): Record<string, unknown> {\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi';\n const tmp = join(tmpdir(), `suntropy-${filenameHint}-${Date.now()}.json`);\n writeFileSync(tmp, JSON.stringify(initial ?? {}, null, 2));\n try {\n const res = spawnSync(editor, [tmp], { stdio: 'inherit' });\n if (res.status !== 0) throw new Error(`Editor \"${editor}\" exited with status ${res.status}`);\n const updated = readFileSync(tmp, 'utf-8');\n const parsed = JSON.parse(updated);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('Edited content must be a JSON object at the top level');\n }\n return parsed as Record<string, unknown>;\n } finally {\n try { unlinkSync(tmp); } catch { /* ignore */ }\n }\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\n\n/**\n * Keys accepted by POST /clients/config/updateTheme.\n * Mirrors ClientThemeConfig in backend/security.\n */\nconst THEME_KEYS = [\n 'idClientThemeConfig',\n 'primary',\n 'btnPrimary',\n 'btnSecondary',\n 'background',\n 'navbarBackgroundColor',\n 'graph1', 'graph2', 'graph3', 'graph4', 'graph5', 'graph6',\n 'logoUrl',\n 'faviconUrl',\n 'clientAppTitle',\n 'carouselLinks',\n 'enableCustomTheme',\n] as const;\n\nexport function registerThemeCommands(configRoot: Command): void {\n const theme = configRoot\n .command('theme')\n .description(\n 'Client branding & theme (security service).\\n' +\n 'Colours, logo, favicon and app title applied across Suntropy.\\n' +\n 'Endpoints: GET /clients/config/clientThemeByClientUID/:uid (public)\\n' +\n ' POST /clients/config/updateTheme (requires admin role)\\n\\n' +\n 'Fields:\\n' +\n ' primary, btnPrimary, btnSecondary Core palette (hex).\\n' +\n ' background, navbarBackgroundColor Surface colours.\\n' +\n ' graph1..graph6 Chart palette (6 slots).\\n' +\n ' logoUrl, faviconUrl Asset URLs.\\n' +\n ' clientAppTitle Visible app title.\\n' +\n ' carouselLinks JSON-serialised carousel config.\\n' +\n ' enableCustomTheme Toggles the custom theme on/off.'\n );\n\n theme\n .command('get')\n .description('Fetch the theme of a client (public endpoint, no auth required for reads).')\n .requiredOption('--client-uid <uid>', 'Client UID whose theme should be fetched')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const res = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('set')\n .description(\n 'Update the theme of the authenticated client (requires admin role).\\n' +\n 'Combine individual flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Example:\\n' +\n ' suntropy config theme set --primary \"#0066ff\" --logo-url https://cdn/logo.svg\\n' +\n ' suntropy config theme set --set graph1=#ff0000 --set graph2=#00ff00\\n' +\n ' suntropy config theme set --from-file theme.json'\n )\n .option('--primary <hex>', 'Primary colour')\n .option('--btn-primary <hex>', 'Primary button colour')\n .option('--btn-secondary <hex>', 'Secondary button colour')\n .option('--background <hex>', 'Background colour')\n .option('--navbar-background-color <hex>', 'Navbar background colour')\n .option('--logo-url <url>', 'Logo URL')\n .option('--favicon-url <url>', 'Favicon URL')\n .option('--client-app-title <title>', 'Visible app title')\n .option('--enable-custom-theme [bool]', 'Toggle the custom theme (true/false)')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n\n const flagValues: Record<string, unknown> = {\n primary: opts.primary,\n btnPrimary: opts.btnPrimary,\n btnSecondary: opts.btnSecondary,\n background: opts.background,\n navbarBackgroundColor: opts.navbarBackgroundColor,\n logoUrl: opts.logoUrl,\n faviconUrl: opts.faviconUrl,\n clientAppTitle: opts.clientAppTitle,\n enableCustomTheme: opts.enableCustomTheme === undefined ? undefined : opts.enableCustomTheme === true || opts.enableCustomTheme === 'true',\n };\n\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, THEME_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const res = await client.post('/clients/config/updateTheme', payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n theme\n .command('edit')\n .description('Open $EDITOR with the theme JSON and PUT the edited result.')\n .requiredOption('--client-uid <uid>', 'Client UID to fetch the current theme from')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(theme);\n const client = createServiceClient('security', global);\n const current = await client.get(`/clients/config/clientThemeByClientUID/${opts.clientUid}`);\n const subset = pickKeys(current.data as Record<string, unknown>, THEME_KEYS);\n const edited = editJson(subset, 'theme');\n const res = await client.post('/clients/config/updateTheme', edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { AxiosInstance } from 'axios';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys, coerceValue } from './shared.js';\n\n/** camelCase → kebab-case (\"logoUrl\" → \"logo-url\"). */\nfunction kebab(key: string): string {\n return key.replace(/[A-Z0-9]+/g, (m, i) => (i === 0 ? m.toLowerCase() : '-' + m.toLowerCase()));\n}\n\n/** One category of the advanced panel. */\ninterface Section {\n name: string;\n title: string;\n summary: string;\n fields: readonly string[];\n fieldDocs: Record<string, string>;\n}\n\nconst GENERAL: Section = {\n name: 'general',\n title: 'General configuration (branding, language, tracking, base aesthetics).',\n summary:\n 'Applies to the entire widget: navbar, favicon, global theme, analytics/pixels\\n' +\n 'and page-wide injected scripts. Equivalent to the \"General Configuration\"\\n' +\n 'panel in the Suntropy admin.',\n fields: [\n 'logoUrl', 'faviconUrl', 'tabTitle',\n 'onAddressButtonClick', 'onSendButtonClick',\n 'googleConversionId', 'googleConversionLabelOnAddress', 'googleConversionLabelOnSend',\n 'metaConversionId', 'customTrackingHTML',\n 'defaultLanguage', 'enableLanguageMenu',\n 'customColorOfElements', 'steticVariant', 'themeColor', 'navbarColor',\n 'addNumberToSteps', 'showFooter',\n ],\n fieldDocs: {\n logoUrl: 'Logo displayed in the navbar (and on the cover if includeLogoInCover=true). Empty = no logo.',\n faviconUrl: 'Browser tab favicon.',\n tabTitle: 'Browser tab title (HTML <title>).',\n onAddressButtonClick: 'JavaScript evaluated (eval) when the user hits \"Continue\" on the address step. ⚠ XSS risk; never accept untrusted input.',\n onSendButtonClick: 'JavaScript evaluated (eval) when the final form is submitted. Same XSS risk as above.',\n googleConversionId: 'Google Ads ID; injects gtag.js in <head>.',\n googleConversionLabelOnAddress: 'Google conversion label fired after the address step.',\n googleConversionLabelOnSend: 'Google conversion label fired on submit.',\n metaConversionId: 'Meta/Facebook pixel ID; fires a \"Lead\" event on submit.',\n customTrackingHTML: 'Arbitrary HTML/JS injected in <head> (Hotjar, Mixpanel, GTM…).',\n defaultLanguage: 'Initial language: en|es|fr|it|pt|cat. Falls back to browser pref, then \"en\".',\n enableLanguageMenu: 'Shows the language picker in the navbar. false pins the user to defaultLanguage.',\n customColorOfElements: 'Accent colour for buttons / active borders.',\n steticVariant: 'Visual variant: default (rounded) | sharped (hard corners) | simple (minimalist, no shadows).',\n themeColor: 'Primary colour (navbar, buttons, focus ring). Default #575757.',\n navbarColor: 'Overrides themeColor for the navbar only.',\n addNumberToSteps: 'Prefix step names with their number (\"1. Address\", …).',\n showFooter: 'Pins the footer to the bottom instead of inlining it in the flow.',\n },\n};\n\nconst COVER: Section = {\n name: 'cover',\n title: 'Cover / hero screen shown before the address step.',\n summary: 'Configures the first screen the user sees: title, subtitle, carousel background, colours and logo placement.',\n fields: [\n 'coverTitle', 'coverSubtitle',\n 'coverBackgroundImageUrl1', 'coverBackgroundImageUrl2', 'coverBackgroundImageUrl3', 'coverBackgroundImageUrl4',\n 'staticCoverImages',\n 'coverTextColor', 'coverFilterColor',\n 'includeLogoInCover',\n ],\n fieldDocs: {\n coverTitle: 'Hero title.',\n coverSubtitle: 'Hero subtitle below the title.',\n coverBackgroundImageUrl1: 'Background image #1 (also first frame of the carousel).',\n coverBackgroundImageUrl2: 'Background image #2.',\n coverBackgroundImageUrl3: 'Background image #3.',\n coverBackgroundImageUrl4: 'Background image #4.',\n staticCoverImages: 'true = no rotation (always shows the first image). false = carousel auto-rotates.',\n coverTextColor: 'Colour applied to coverTitle and coverSubtitle.',\n coverFilterColor: 'Overlay colour on top of the image. Default rgba(75,55,30,0.7); improves text contrast.',\n includeLogoInCover: 'true repeats the navbar logo on the cover. false keeps it only in the navbar.',\n },\n};\n\nconst SURFACES: Section = {\n name: 'surfaces',\n title: 'Surfaces step: the map where the user draws the roof polygon(s).',\n summary: 'Controls whether the step runs, how many surfaces are allowed, and the per-device help messages.',\n fields: ['surfaceStepEnabled', 'multipleSurfaces', 'enableMapMarker', 'messageOnDesktopDevices', 'messageOnMobileDevices'],\n fieldDocs: {\n surfaceStepEnabled: 'Enables/disables the whole step. false = the lead is sized without any polygon input.',\n multipleSurfaces: 'Allows drawing more than one roof surface per lead.',\n enableMapMarker: 'Drops a pin on the installation location over the satellite view.',\n messageOnDesktopDevices: 'Instruction text shown on desktop during the step.',\n messageOnMobileDevices: 'Instruction text shown on mobile (e.g. \"Tap to draw\").',\n },\n};\n\nconst CONSUMER: Section = {\n name: 'consumer',\n title: 'Consumer step: residential / commercial / community picker.',\n summary: 'Each subtype has its own visibility flag, image and label. defaultConsumptionPattern feeds the calculation engine.',\n fields: [\n 'consumerStepEnabled',\n 'residentialConsumerTypeEnabled', 'residentialConsumerImageUrl', 'residentialConsumerTitle',\n 'commercialConsumerTypeEnabled', 'commercialConsumerImageUrl', 'commercialConsumerTitle',\n 'communityConsumerTypeEnabled', 'communityConsumerImageUrl', 'communityConsumerTitle',\n 'defaultConsumptionPattern',\n ],\n fieldDocs: {\n consumerStepEnabled: 'Shows/hides the whole step.',\n residentialConsumerTypeEnabled: 'Makes the \"Residential\" option visible.',\n residentialConsumerImageUrl: 'Icon/photo for the Residential option.',\n residentialConsumerTitle: 'Residential label (e.g. \"Home\").',\n commercialConsumerTypeEnabled: 'Makes the \"Commercial\" option visible.',\n commercialConsumerImageUrl: 'Icon/photo for the Commercial option.',\n commercialConsumerTitle: 'Commercial label (e.g. \"Business\").',\n communityConsumerTypeEnabled: 'Makes the \"Community\" option visible.',\n communityConsumerImageUrl: 'Icon/photo for the Community option.',\n communityConsumerTitle: 'Community label.',\n defaultConsumptionPattern: 'Preselected pattern: Balance | Nightly | Morning | Afternoon | Domestic | Commercial | Community. Feeds the hourly curve used by the engine.',\n },\n};\n\nconst INCLINATION: Section = {\n name: 'inclination',\n title: 'Roof inclination step (flat / inclined / very inclined).',\n summary: 'Each variant carries its own image and label. defaultInclination is also used when the step is disabled.',\n fields: [\n 'inclinationStepEnabled',\n 'flatRoofImageUrl', 'textFlatRoof',\n 'inclinedRoofImageUrl', 'textInclinedRoof',\n 'veryInclinedRoofImageUrl', 'textVeryInclinedRoof',\n 'defaultInclination', 'inclinationStepTitle',\n ],\n fieldDocs: {\n inclinationStepEnabled: 'Shows/hides the step. When false, defaultInclination is fed directly into the calculation.',\n flatRoofImageUrl: 'Image for the flat-roof option (0-15°).',\n textFlatRoof: 'Label for flat roof. Default \"0-15°\".',\n inclinedRoofImageUrl: 'Image for the inclined-roof option (15-30°).',\n textInclinedRoof: 'Label for inclined roof. Default \"15-30°\".',\n veryInclinedRoofImageUrl: 'Image for the very-inclined option (>30°).',\n textVeryInclinedRoof: 'Label for very inclined roof. Default \">30°\".',\n defaultInclination: 'Degrees (0-90). Preselected value and fallback when the step is disabled.',\n inclinationStepTitle: 'Title for the step.',\n },\n};\n\nconst ORIENTATION: Section = {\n name: 'orientation',\n title: 'Roof orientation (azimuth) step.',\n summary: 'Directly impacts yield estimates.',\n fields: ['orientationStepEnabled', 'defaultOrientation'],\n fieldDocs: {\n orientationStepEnabled: 'Shows/hides the step. When false, defaultOrientation is fed to the engine.',\n defaultOrientation: 'Degrees 0-360 (0=N, 90=E, 180=S, 270=W).',\n },\n};\n\nconst PANELS: Section = {\n name: 'panels',\n title: 'Solar panel & kit-category selection step.',\n summary: 'Drives which panel + kit category the lead is sized with.',\n fields: ['panelStepEnabled', 'defaultSolarPanel', 'kitCategories', 'defaultKitCategoryId', 'panelSectionTitle', 'panelTitle'],\n fieldDocs: {\n panelStepEnabled: 'Shows/hides the step. When false, the backend uses defaultSolarPanel + defaultKitCategoryId unattended.',\n defaultSolarPanel: 'ID of the preselected SolarPanel (reference to the client inventory).',\n kitCategories: 'Array of kit categories offered to the lead. Each item: { id, name, description, priority }. Use --from-file for multi-item payloads.',\n defaultKitCategoryId: 'ID of the preselected kit category.',\n panelSectionTitle: 'Navbar/breadcrumb label for the panel section.',\n panelTitle: 'Step title.',\n },\n};\n\nconst CONSUMPTION: Section = {\n name: 'consumption',\n title: 'Electric-consumption input step.',\n summary: 'Controls the input mode and display density of the consumption step.',\n fields: ['showOnlyOneConsumptionFieldAtATime', 'defaultConsumptionIntroductionMode'],\n fieldDocs: {\n showOnlyOneConsumptionFieldAtATime: 'true = guided mode (one field per screen). false = all fields visible at once.',\n defaultConsumptionIntroductionMode: 'monthlyConsumption (kWh/month) | monthlySpending (EUR/month). User can toggle if both are enabled.',\n },\n};\n\nconst RESULTS: Section = {\n name: 'results',\n title: 'Results screen, contact form and calculation-engine hooks.',\n summary: 'Largest section: visual layout, form fields for lead capture, confirmation modal, and engine toggles (batteries, PPA, alternative endpoint).',\n fields: [\n 'resultsMode', 'resultsBackgroundImageUrl', 'hideBackgroundImageInResults', 'colorOfBackgroundInResults',\n 'includeLogoInResults', 'includeMapInResults', 'hideResults', 'hideROI', 'formTitle', 'formSubtitle',\n 'resultsWhenSent', 'colorOfResultsPanelBackground',\n 'showDniFieldOnResults', 'showPhonePrefixFieldOnResults', 'showTypeOfDocumentFieldOnResults',\n 'showDniValidationFieldOnResults', 'showPhoneNumberValidationFieldOnResults',\n 'showIdentifierValidationFieldOnResults', 'showSurnameValidationFieldOnResults', 'showTypeOfClientSelectorOnResults',\n 'titleModalOfConfirm', 'textModalOfConfirm',\n 'businessName', 'enablePeakPowerLimitation', 'includeBatteries', 'enabledPPACalculation',\n 'hideCommentField', 'alternativeCalculationEndpoint', 'alternativeCalculationLoadingMessage', 'redirectToShareable',\n ],\n fieldDocs: {\n resultsMode: 'Default (ROI, payback, savings) | SolarResource (irradiance map + technical data).',\n resultsBackgroundImageUrl: 'Background image behind the results panel.',\n hideBackgroundImageInResults: 'Hides the background image even when set.',\n colorOfBackgroundInResults: 'Overlay colour on top of the background image. Default rgba(75,55,30,0.7).',\n colorOfResultsPanelBackground: 'Background of the metrics card. Default rgba(0,0,0,0.5).',\n includeLogoInResults: 'Shows the logo on the results screen.',\n includeMapInResults: 'Shows the interactive map with the drawn panels.',\n hideResults: 'true = no metrics shown, only the contact form.',\n hideROI: 'Hides the payback/ROI widget.',\n formTitle: 'Contact form title.',\n formSubtitle: 'Contact form subtitle.',\n resultsWhenSent: 'true = results shown before submit. false = form must be filled first.',\n showDniFieldOnResults: 'Adds a DNI/CIF input to the form.',\n showPhonePrefixFieldOnResults: 'Adds a phone-prefix selector.',\n showTypeOfDocumentFieldOnResults: 'Adds a document-type selector.',\n showDniValidationFieldOnResults: 'Visual DNI validation (green check).',\n showPhoneNumberValidationFieldOnResults: 'Visual phone validation.',\n showIdentifierValidationFieldOnResults: 'Visual identifier validation.',\n showSurnameValidationFieldOnResults: 'Visual surname validation.',\n showTypeOfClientSelectorOnResults: 'Selector for Individual / Company / Community.',\n titleModalOfConfirm: 'Title of the confirmation modal shown before submit.',\n textModalOfConfirm: 'Body of the confirmation modal.',\n businessName: 'Adds a \"Business name\" field to the form.',\n enablePeakPowerLimitation: 'Adds a peak-power limiter to the consumption section. Affects engine sizing.',\n includeBatteries: 'Includes battery sizing in the results.',\n enabledPPACalculation: 'Enables PPA (Power Purchase Agreement) modelling.',\n hideCommentField: 'Hides the free-text comment field.',\n alternativeCalculationEndpoint: 'URL to which calculation data is POSTed instead of the default engine endpoint. For white-label integrations.',\n alternativeCalculationLoadingMessage: 'Loading text while awaiting the alternative endpoint response.',\n redirectToShareable: 'After calculation, redirect to the shareable-study URL instead of rendering results in-place.',\n },\n};\n\nconst CUSTOM_FIELDS: Section = {\n name: 'custom-fields',\n title: 'Extra lead fields persisted on the SolarStudy (plugin-gated).',\n summary: 'Only available when the client has the \"studyCustomFields\" plugin active.',\n fields: ['solarStudyCustomFields'],\n fieldDocs: {\n solarStudyCustomFields: 'Array of custom-field definitions, serialised. Each item: { id, label, type, required, options? }. Types: text|number|select|boolean. Use --from-file to avoid quoting headaches.',\n },\n};\n\nconst SECTIONS: readonly Section[] = [\n GENERAL, COVER, SURFACES, CONSUMER, INCLINATION, ORIENTATION, PANELS, CONSUMPTION, RESULTS, CUSTOM_FIELDS,\n];\n\nfunction getAdvanced(client: AxiosInstance): Promise<Record<string, unknown>> {\n return client.get('/solar-form/config/advanced').then((r) => r.data as Record<string, unknown>);\n}\n\nfunction putAdvanced(client: AxiosInstance, payload: Record<string, unknown>): Promise<unknown> {\n return client.put('/solar-form/config/advanced', payload).then((r) => r.data);\n}\n\n/** Build a \"Fields:\" help block for a section. */\nfunction formatFieldsHelp(section: Section): string {\n const longest = Math.max(...section.fields.map((f) => f.length));\n return [\n section.title,\n '',\n section.summary,\n '',\n 'Fields:',\n ...section.fields.map((f) => ` ${f.padEnd(longest)} ${section.fieldDocs[f] ?? ''}`),\n '',\n 'Operations: get | set [--set key=value] [--from-file] [--<field> <value>] | edit',\n ].join('\\n');\n}\n\nfunction attachSectionCommand(advanced: Command, section: Section): void {\n const sec = advanced\n .command(section.name)\n .description(formatFieldsHelp(section));\n\n sec\n .command('get')\n .description(`Fetch only the ${section.name} fields of the advanced config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const doc = await getAdvanced(client);\n output(pickKeys(doc, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n const setCmd = sec\n .command('set')\n .description(\n `Update the ${section.name} fields of the advanced config.\\n` +\n 'Combine per-field flags, repeatable --set key=value, and/or --from-file.\\n' +\n 'Internally GETs the current config, merges this section, and PUTs the whole thing.'\n )\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file');\n\n for (const field of section.fields) {\n setCmd.option(`--${kebab(field)} <value>`, section.fieldDocs[field] ?? field);\n }\n\n setCmd.action(async (opts) => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {};\n for (const field of section.fields) {\n const val = opts[field];\n if (val !== undefined) flagValues[field] = coerceValue(String(val));\n }\n const partial = buildPayload(flagValues, opts.set, opts.fromFile, section.fields);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use flags, --set, or --from-file.'));\n return;\n }\n\n const current = await getAdvanced(client);\n const merged = { ...current, ...partial };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n sec\n .command('edit')\n .description(`Open $EDITOR on the ${section.name} subset of the advanced config, then PUT the whole config.`)\n .action(async () => {\n try {\n const global = getGlobalOpts(sec);\n const client = createServiceClient('solar', global);\n const current = await getAdvanced(client);\n const subset = pickKeys(current, section.fields);\n const edited = editJson(subset, `advanced-${section.name}`);\n const merged = { ...current, ...edited };\n const res = await putAdvanced(client, merged);\n output(pickKeys(res as Record<string, unknown>, section.fields), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\nexport function registerAdvancedCommands(solarform: Command): void {\n const advanced = solarform\n .command('advanced')\n .description(\n 'SolarForm Advanced configuration (white-label microsite).\\n' +\n 'Each subcommand maps 1:1 with a section of the admin accordion and with a\\n' +\n 'subset of fields in the AdvancedSolarFormConfig DTO.\\n\\n' +\n 'Whole-payload operations:\\n' +\n ' get Fetch the full advanced config.\\n' +\n ' update Merge a partial payload (--set / --from-file).\\n' +\n ' delete Delete the authenticated client\\'s advanced config.\\n' +\n ' init-default Create the default config for a clientUID (superadmin / localhost).\\n\\n' +\n 'Sections (each: get / set / edit):\\n' +\n SECTIONS.map((s) => ` ${s.name.padEnd(14)} ${s.title}`).join('\\n') + '\\n\\n' +\n 'Conventions:\\n' +\n ' --set <field>=<value> Assign a single field (repeatable).\\n' +\n ' --from-file <path> Load a partial payload from JSON.\\n' +\n ' edit Open $EDITOR on the section\\'s current state.'\n );\n\n advanced\n .command('get')\n .description('Fetch the full AdvancedSolarFormConfig for the authenticated client.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const data = await getAdvanced(client);\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('update')\n .description('Merge a partial AdvancedSolarFormConfig from --set / --from-file and PUT.')\n .option('--set <entries...>', 'Field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a partial payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const partial = buildPayload({}, opts.set, opts.fromFile);\n if (Object.keys(partial).length === 0) {\n outputError(new Error('No fields provided. Use --set or --from-file.'));\n return;\n }\n const current = await getAdvanced(client);\n const res = await putAdvanced(client, { ...current, ...partial });\n output(res, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('delete')\n .description('Delete the authenticated client\\'s advanced config.')\n .action(async () => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const res = await client.delete('/solar-form/config/advanced');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n advanced\n .command('init-default')\n .description(\n 'Create the default advanced config for a clientUID.\\n' +\n 'Restricted: requires the \"suntropy-auth: <clientUID>\" header or localhost execution.'\n )\n .requiredOption('--client-uid <uid>', 'Client UID to initialise')\n .option('--email <email>', 'Operator email (optional)')\n .option('--url <url>', 'Site URL (optional)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(advanced);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.email) params.email = opts.email;\n if (opts.url) params.url = opts.url;\n const res = await client.post(\n `/solar-form/config/default/advanced/${opts.clientUid}`,\n {},\n { params, headers: { 'suntropy-auth': opts.clientUid } },\n );\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n for (const section of SECTIONS) attachSectionCommand(advanced, section);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError } from '../../output.js';\nimport { getGlobalOpts, buildPayload, editJson, pickKeys } from './shared.js';\nimport { registerAdvancedCommands } from './advanced.js';\n\n/** Fields accepted on SolarFormConfig (solar backend). */\nconst SOLARFORM_KEYS = [\n 'idSolarFormConfig',\n 'clientUID',\n 'solarFormUrl',\n 'enabled',\n 'notificationEmailAddress',\n 'confirmationReplytoEmailAdress',\n 'notificationEmailSubject',\n 'enableNotificationEmail',\n 'enableSendConfirmationEmailToClient',\n 'confirmationEmailSubject',\n 'confirmationEmailBody',\n 'enableConfirmationEmailBody',\n 'formTitle',\n 'formSubtitle',\n 'formBackgroundColor',\n 'formBackgroundImageURL',\n 'formFaviconUrl',\n 'locationMode',\n 'hideFinalProjectPrice',\n 'enableRequiredPhoneNumberField',\n 'enableRequiredNameField',\n 'callToActionButtonText',\n 'renderPDF',\n 'defaultSolarStudyTemplateId',\n 'redirectUrl',\n 'privacyPolicy',\n 'advertisingPolicy',\n 'generateShareable',\n 'incentiveTemplateGroup',\n 'disabledSolarForm',\n 'redirectOnClose',\n] as const;\n\nexport function registerSolarformConfigCommands(configRoot: Command): void {\n const solarform = configRoot\n .command('solarform')\n .description(\n 'SolarForm (basic) and SolarForm Advanced configuration (solar service).\\n' +\n 'The basic config controls the public lead-capture form (URL, notifications,\\n' +\n 'appearance, mandatory fields). The advanced subtree configures the modern\\n' +\n 'white-label widget rendered by the \"advanced-solar-form\" microsite.\\n\\n' +\n 'Endpoints:\\n' +\n ' GET /solar-form/get-solar-form-config?getParameters=\\n' +\n ' GET /solar-form/solar-form-config (public, resolved by Origin)\\n' +\n ' POST /solar-form/solar-form-config?getParameters=\\n' +\n ' PUT /solar-form/solar-form-config/:id'\n );\n\n solarform\n .command('get')\n .description('Fetch the current SolarForm configuration for the authenticated client.')\n .option('--with-parameters', 'Include the associated SolarFormParameters in the response')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.get('/solar-form/get-solar-form-config', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('create')\n .description(\n 'Create a new SolarFormConfig for the authenticated client.\\n' +\n '--url is the public slug/URL of the form. Other fields may come from flags,\\n' +\n '--set key=value, or --from-file. Accepted keys:\\n' +\n ' ' + SOLARFORM_KEYS.join(', ')\n )\n .requiredOption('--url <slug>', 'Public URL/slug of the form (solarFormUrl)')\n .option('--enabled [bool]', 'Whether the form is publicly enabled', 'true')\n .option('--form-title <text>', 'Form title displayed to the end user')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--form-background-color <color>', 'Background colour of the form container')\n .option('--form-background-image-url <url>', 'Background image URL')\n .option('--form-favicon-url <url>', 'Favicon URL')\n .option('--call-to-action-button-text <text>', 'Primary CTA button label')\n .option('--notification-email-address <email>', 'Where new lead notifications go')\n .option('--location-mode <mode>', 'fullSurface | locationOnly')\n .option('--with-parameters', 'Include SolarFormParameters in the response')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n solarFormUrl: opts.url,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n formBackgroundColor: opts.formBackgroundColor,\n formBackgroundImageURL: opts.formBackgroundImageUrl,\n formFaviconUrl: opts.formFaviconUrl,\n callToActionButtonText: opts.callToActionButtonText,\n notificationEmailAddress: opts.notificationEmailAddress,\n locationMode: opts.locationMode,\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n\n const params: Record<string, string> = {};\n if (opts.withParameters) params.getParameters = 'true';\n const res = await client.post('/solar-form/solar-form-config', payload, { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('update <idSolarFormConfig>')\n .description('Update an existing SolarFormConfig by numeric ID.')\n .option('--set <entries...>', 'Additional field assignments as key=value (repeatable)')\n .option('--from-file <path>', 'Load a payload from a JSON file')\n .option('--form-title <text>', 'Form title')\n .option('--form-subtitle <text>', 'Form subtitle')\n .option('--enabled [bool]', 'Whether the form is publicly enabled')\n .option('--disabled-solar-form [bool]', 'Explicit disable flag')\n .action(async (idSolarFormConfig, opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const flagValues: Record<string, unknown> = {\n formTitle: opts.formTitle,\n formSubtitle: opts.formSubtitle,\n enabled: opts.enabled === undefined ? undefined : opts.enabled === true || opts.enabled === 'true',\n disabledSolarForm: opts.disabledSolarForm === undefined ? undefined : opts.disabledSolarForm === true || opts.disabledSolarForm === 'true',\n };\n const payload = buildPayload(flagValues, opts.set, opts.fromFile, SOLARFORM_KEYS);\n if (Object.keys(payload).length === 0) {\n outputError(new Error('No fields to update.'));\n return;\n }\n\n const res = await client.put(`/solar-form/solar-form-config/${idSolarFormConfig}`, payload);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n solarform\n .command('edit')\n .description('Fetch the current SolarForm config, open $EDITOR, and PUT the edited result.')\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const current = await client.get('/solar-form/get-solar-form-config');\n const doc = current.data as Record<string, unknown>;\n const id = doc?.idSolarFormConfig;\n if (!id) {\n outputError(new Error('No existing SolarFormConfig found to edit. Use \"create\" first.'));\n return;\n }\n const subset = pickKeys(doc, SOLARFORM_KEYS);\n const edited = editJson(subset, 'solarform');\n const res = await client.put(`/solar-form/solar-form-config/${id}`, edited);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n registerAdvancedCommands(solarform);\n}\n","import { Command } from 'commander';\nimport { loadConfig, saveConfig, setConfigValue, getConfigValue } from '../config.js';\nimport { output, outputError } from '../output.js';\nimport { registerThemeCommands } from './config/theme.js';\nimport { registerSolarformConfigCommands } from './config/solarform.js';\n\nexport function registerConfigCommands(program: Command): void {\n const cfg = program\n .command('config')\n .description(\n 'CLI configuration (profiles, server, token) plus tenant configuration\\n' +\n '(theme & SolarForm / SolarForm Advanced) served by the security and solar backends.'\n );\n\n cfg\n .command('set <key> <value>')\n .description('Set a configuration value. Keys: server, token, activeProfile')\n .option('--profile <name>', 'Profile to modify')\n .action((key, value, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n config.activeProfile = value;\n saveConfig(config);\n } else {\n setConfigValue(key, value, opts.profile);\n }\n output({ success: true, key, value });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('get <key>')\n .description('Get a configuration value')\n .option('--profile <name>', 'Profile to read from')\n .action((key, opts) => {\n try {\n if (key === 'activeProfile') {\n const config = loadConfig();\n output({ activeProfile: config.activeProfile });\n } else {\n output({ [key]: getConfigValue(key, opts.profile) });\n }\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('list')\n .description('Show all configuration')\n .action(() => {\n try {\n const config = loadConfig();\n // Redact tokens for display\n const safe = JSON.parse(JSON.stringify(config));\n for (const [name, profile] of Object.entries(safe.profiles)) {\n const p = profile as Record<string, unknown>;\n if (p.token) p.token = (p.token as string).slice(0, 20) + '...';\n }\n output(safe);\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('create-profile <name>')\n .description('Create a new profile')\n .option('--server <url>', 'API server URL', 'https://api.enerlence.com')\n .action((name, opts) => {\n try {\n const config = loadConfig();\n if (config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" already exists`));\n return;\n }\n config.profiles[name] = { server: opts.server };\n saveConfig(config);\n output({ success: true, profile: name, server: opts.server });\n } catch (err) {\n outputError(err);\n }\n });\n\n cfg\n .command('use <name>')\n .description('Switch to a profile')\n .action((name) => {\n try {\n const config = loadConfig();\n if (!config.profiles[name]) {\n outputError(new Error(`Profile \"${name}\" not found. Available: ${Object.keys(config.profiles).join(', ')}`));\n return;\n }\n config.activeProfile = name;\n saveConfig(config);\n output({ success: true, activeProfile: name });\n } catch (err) {\n outputError(err);\n }\n });\n\n registerThemeCommands(cfg);\n registerSolarformConfigCommands(cfg);\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\n\nexport interface ResourceConfig {\n /** Command name (e.g. 'panels') */\n name: string;\n /** Singular display name (e.g. 'solar panel') */\n singular: string;\n /** API base path (e.g. '/solar-panels') */\n basePath: string;\n /** ID field name in the entity (e.g. 'solarPanelId') */\n idField: string;\n /** Fields to show in list view (summary) */\n listFields: string[];\n /** POST path for advanced filter, if different from basePath + '/filter' */\n filterPath?: string;\n /** Batch delete path suffix */\n batchDeletePath?: string;\n /** PUT uses body without ID in URL (some endpoints use PUT / with body containing id) */\n putBodyOnly?: boolean;\n /** Backend service */\n service?: 'solar' | 'templates' | 'security';\n /** Custom GET path pattern. Use ':id' as placeholder (e.g. '/custom-asset/id/:id') */\n getPath?: string;\n /** Use POST filter to get by ID (when no GET :id endpoint exists) */\n getViaFilter?: boolean;\n}\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & { server?: string; token?: string; profile?: string; verbose?: boolean } {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n if (data === '-') {\n // Read from stdin - synchronous for simplicity\n const { readFileSync } = require('fs');\n const input = readFileSync(0, 'utf-8');\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function createResourceCommands(cfg: ResourceConfig): Command {\n const cmd = new Command(cfg.name).description(`Manage ${cfg.singular}s`);\n const service = cfg.service || 'solar';\n\n // --- list ---\n cmd\n .command('list')\n .description(`List ${cfg.singular}s with pagination. Fields: ${cfg.listFields.join(', ')}`)\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--active-only', 'Only active items (exclude inactive)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const params: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (!opts.activeOnly) params.unactive = true;\n\n const res = await client.get(cfg.basePath, { params });\n // API may return: [items[], totalCount] tuple, {data: [], total} object, or plain array\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n // Tuple format: [items[], totalCount]\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || [];\n total = res.data?.total ?? data.length;\n }\n\n // Apply list field summary unless user specified --fields\n const outOpts: OutputOptions = { ...global };\n if (!global.fields && cfg.listFields.length > 0) {\n outOpts.fields = [cfg.idField, ...cfg.listFields].join(',');\n }\n\n if (Array.isArray(data)) {\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } else {\n output(data, outOpts);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n cmd\n .command('get <id>')\n .description(`Get a ${cfg.singular} by ID. All fields returned by default.`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n if (cfg.getViaFilter) {\n // No GET :id endpoint — fetch all and filter client-side\n const res = await client.get(cfg.basePath, { params: { unactive: true } });\n const all = Array.isArray(res.data) ? res.data : (Array.isArray(res.data?.[0]) ? res.data[0] : res.data?.data || []);\n const idNum = parseInt(id);\n const item = all.find((r: Record<string, unknown>) => r[cfg.idField] === idNum || r[cfg.idField] === id);\n if (!item) { outputError(new Error(`${cfg.singular} with ${cfg.idField}=${id} not found`)); return; }\n output(item, global);\n } else {\n const url = cfg.getPath ? cfg.getPath.replace(':id', id) : `${cfg.basePath}/${id}`;\n const res = await client.get(url);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n cmd\n .command('create')\n .description(`Create a new ${cfg.singular}. Pass JSON via --data or stdin (--data -)`)\n .requiredOption('--data <json>', 'JSON data (or - for stdin)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n const res = await client.post(cfg.basePath, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n cmd\n .command('update <id>')\n .description(`Update a ${cfg.singular}`)\n .requiredOption('--data <json>', 'JSON data with fields to update (or - for stdin)')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const body = parseData(opts.data);\n if (cfg.putBodyOnly) {\n // The id goes in the body for these resources; send it as a number so\n // TypeORM matches the integer primary key on the other side.\n const numericId = Number(id);\n const res = await client.put(cfg.basePath, {\n ...body,\n [cfg.idField]: Number.isFinite(numericId) ? numericId : id,\n });\n output(res.data, global);\n } else {\n const res = await client.put(`${cfg.basePath}/${id}`, body);\n output(res.data, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n cmd\n .command('delete <id>')\n .description(`Delete a ${cfg.singular}`)\n .action(async (id) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const res = await client.delete(`${cfg.basePath}/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete-batch ---\n if (cfg.batchDeletePath) {\n cmd\n .command('delete-batch')\n .description(`Batch delete ${cfg.singular}s`)\n .requiredOption('--ids <ids>', 'Comma-separated IDs')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const ids = opts.ids.split(',').map((s: string) => s.trim());\n const res = await client.post(`${cfg.basePath}/${cfg.batchDeletePath}`, ids);\n output(res.data ?? { success: true, deleted: ids.length }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n }\n\n // --- filter ---\n cmd\n .command('filter')\n .description(`Advanced filter for ${cfg.singular}s. Pass filter query as JSON.`)\n .requiredOption('--query <json>', 'Filter query JSON (or - for stdin)')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(cmd);\n const client = createServiceClient(service, global);\n const query = parseData(opts.query);\n const filterUrl = cfg.filterPath || `${cfg.basePath}/filter`;\n const res = await client.post(filterUrl, {\n ...query,\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || res.data;\n const total = res.data?.total ?? (Array.isArray(data) ? data.length : 0);\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { createResourceCommands } from './factory.js';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string): Record<string, unknown> {\n if (data === '-') {\n const { readFileSync } = require('fs');\n return JSON.parse(readFileSync(0, 'utf-8'));\n }\n return JSON.parse(data);\n}\n\nexport function registerKitsCommands(inventory: Command): void {\n // Base kit CRUD via factory\n const kits = createResourceCommands({\n name: 'kits',\n singular: 'solar kit',\n basePath: '/solar-kits',\n idField: 'idSolarKit',\n listFields: ['identifier', 'peakPower', 'panelNumber', 'inverterNumber', 'price', 'totalPrice', 'phaseNumber', 'active'],\n filterPath: '/solar-kits/filters',\n batchDeletePath: 'delete-batch-solar-kits',\n getViaFilter: true,\n });\n\n // Remove factory-generated 'create' — use 'assemble' instead for safe kit creation\n const kitsCreateIdx = kits.commands.findIndex((c: Command) => c.name() === 'create');\n if (kitsCreateIdx !== -1) kits.commands.splice(kitsCreateIdx, 1);\n\n // --- archive ---\n kits\n .command('archive <kitId>')\n .description('Archive a solar kit (soft-disable)')\n .action(async (kitId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/archive/${kitId}`);\n output(res.data ?? { success: true, archived: kitId }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit panels sub-commands ---\n const kitPanels = kits.command('panels').description('Manage kit solar panels');\n\n kitPanels\n .command('list')\n .description('List all kit solar panels. Fields: idKitSolarPanel, name, manufacturer, peakPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/solar-panels', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('get <id>')\n .description('Get a kit solar panel by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n // Use filter to get by ID since there's no direct GET by ID\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: id });\n const data = Array.isArray(res.data) ? res.data[0] : res.data?.data?.[0] || res.data;\n output(data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('create')\n .description('Create a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/solar-panels', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('update <id>')\n .description('Update a kit solar panel')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/solar-panels/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('delete <id>')\n .description('Delete a kit solar panel')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/solar-panels/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitPanels\n .command('featured <kitPanelId>')\n .description('List solar kits that feature this kit panel')\n .action(async (kitPanelId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/solar-panels/findFeaturedSolarKits/${kitPanelId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit inverters sub-commands ---\n const kitInverters = kits.command('inverters').description('Manage kit inverters');\n\n kitInverters\n .command('list')\n .description('List all kit inverters. Fields: idKitInverter, name, manufacturer, nominalPower, efficiency, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/inverters', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('create')\n .description('Create a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/inverters', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('update <id>')\n .description('Update a kit inverter')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.put(`/solar-kits/inverters/${id}`, parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('delete <id>')\n .description('Delete a kit inverter')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/inverters/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitInverters\n .command('featured <kitInverterId>')\n .description('List solar kits that feature this kit inverter')\n .action(async (kitInverterId) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-kits/inverters/findFeaturedSolarKits/${kitInverterId}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- Kit batteries sub-commands ---\n const kitBatteries = kits.command('batteries').description('Manage kit batteries');\n\n kitBatteries\n .command('list')\n .description('List all kit batteries. Fields: idKitBattery, name, manufacturer, capacity, costPerUnit')\n .option('--limit <n>', 'Max results', '50')\n .option('--offset <n>', 'Skip results', '0')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-kits/batteries', { params: { limit: opts.limit, offset: opts.offset } });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('create')\n .description('Create a kit battery')\n .requiredOption('--data <json>', 'JSON data')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.post('/solar-kits/batteries', parseData(opts.data));\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n kitBatteries\n .command('delete <id>')\n .description('Delete a kit battery')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/solar-kits/batteries/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- assemble: create kit from existing components by ID ---\n kits\n .command('assemble')\n .description(\n 'Assemble a solar kit from existing components by ID.\\n' +\n 'References kit panels, inverters, batteries, and custom assets by their IDs.\\n\\n' +\n 'Custom assets format: --custom-asset <assetId>:<units> (repeatable)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy inventory kits assemble --name \"Kit 5kW\" --panel 123 --inverter 456 --panels-count 12 --price 6500\\n' +\n ' suntropy inventory kits assemble --name \"Kit Premium\" --panel 123 --inverter 456 --battery 789 \\\\\\n' +\n ' --panels-count 12 --inverters-count 1 --batteries-count 1 --peak-power 5.4 --price 8500 \\\\\\n' +\n ' --custom-asset 100:12 --custom-asset 200:1 --phase single_phase'\n )\n .requiredOption('--name <identifier>', 'Kit name/identifier')\n .option('--panel <kitPanelId>', 'Kit panel ID (idKitSolarPanel)')\n .option('--inverter <kitInverterId>', 'Kit inverter ID (idKitInverter)')\n .option('--battery <batteryId>', 'Battery ID from inventory (batteryId)')\n .option('--panels-count <n>', 'Number of panels', '12')\n .option('--inverters-count <n>', 'Number of inverters', '1')\n .option('--batteries-count <n>', 'Number of batteries', '0')\n .option('--peak-power <kW>', 'Total peak power in kW')\n .requiredOption('--price <eur>', 'Kit price in EUR (required)')\n .option('--phase <type>', 'Phase: single_phase or three_phase', 'single_phase')\n .option('--coplanar', 'Coplanar mounting')\n .option('--taxes <pct>', 'Default tax percentage', '21')\n .option('--custom-asset <id:units>', 'Custom asset as id:units (repeatable)', collectCustomAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(kits);\n const client = createServiceClient('solar', global);\n\n // Validate component IDs exist as kit entities before assembling\n const validationErrors: string[] = [];\n\n if (opts.panel) {\n try {\n const res = await client.post('/solar-kits/solar-panels/filter', { idKitSolarPanel: parseInt(opts.panel) });\n const data = Array.isArray(res.data) ? res.data : res.data?.data || [];\n if (data.length === 0) {\n validationErrors.push(\n `Panel ID ${opts.panel} is not a KitSolarPanel. ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels, ` +\n `or \"suntropy inventory kits panels create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate panel ID ${opts.panel}. ` +\n `Make sure it is a KitSolarPanel ID (not a regular inventory panel). ` +\n `Use \"suntropy inventory kits panels list\" to see available kit panels.`\n );\n }\n }\n\n if (opts.inverter) {\n try {\n const res = await client.get('/solar-kits/inverters', { params: { limit: 200 } });\n const inverters = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = inverters.find((inv: Record<string, unknown>) =>\n String(inv.idKitInverter) === String(opts.inverter)\n );\n if (!found) {\n validationErrors.push(\n `Inverter ID ${opts.inverter} is not a KitInverter. ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters, ` +\n `or \"suntropy inventory kits inverters create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate inverter ID ${opts.inverter}. ` +\n `Make sure it is a KitInverter ID (not a regular inventory inverter). ` +\n `Use \"suntropy inventory kits inverters list\" to see available kit inverters.`\n );\n }\n }\n\n if (opts.battery) {\n try {\n const res = await client.get('/solar-kits/batteries', { params: { limit: 200 } });\n const batteries = Array.isArray(res.data) ? res.data : res.data?.data || [];\n const found = batteries.find((bat: Record<string, unknown>) =>\n String(bat.idKitBattery) === String(opts.battery)\n );\n if (!found) {\n validationErrors.push(\n `Battery ID ${opts.battery} is not a KitBattery. ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries, ` +\n `or \"suntropy inventory kits batteries create --data '{...}'\" to create one first.`\n );\n }\n } catch {\n validationErrors.push(\n `Could not validate battery ID ${opts.battery}. ` +\n `Make sure it is a KitBattery ID (not a regular inventory battery). ` +\n `Use \"suntropy inventory kits batteries list\" to see available kit batteries.`\n );\n }\n }\n\n if (validationErrors.length > 0) {\n outputError({\n error: true,\n message: 'Kit assembly validation failed',\n issues: validationErrors,\n hint: 'The assemble command requires KitSolarPanel, KitInverter, and KitBattery IDs — these are kit-specific entities, not regular inventory items.',\n });\n return;\n }\n\n const body: Record<string, unknown> = {\n identifier: opts.name,\n panelNumber: parseInt(opts.panelsCount),\n inverterNumber: parseInt(opts.invertersCount),\n batteriesNumber: parseInt(opts.batteriesCount),\n phaseNumber: opts.phase,\n defaultTaxesPercentage: parseFloat(opts.taxes),\n active: true,\n };\n\n if (opts.panel) body.kitSolarPanel = { idKitSolarPanel: parseInt(opts.panel) };\n if (opts.inverter) body.kitInverter = { idKitInverter: parseInt(opts.inverter) };\n if (opts.battery) body.battery = { batteryId: parseInt(opts.battery) };\n if (opts.peakPower) body.peakPower = parseFloat(opts.peakPower);\n body.price = parseFloat(opts.price);\n if (opts.coplanar) body.coplanar = true;\n\n if (opts.customAsset && opts.customAsset.length > 0) {\n body.solarKitCustomAssets = opts.customAsset.map((ca: { id: number; units: number }) => ({\n customAsset: { idCustomAsset: ca.id },\n units: ca.units,\n }));\n }\n\n const res = await client.post('/solar-kits', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n inventory.addCommand(kits);\n}\n\n/** Collector for repeatable --custom-asset <id:units> option */\nfunction collectCustomAssets(value: string, previous: { id: number; units: number }[]): { id: number; units: number }[] {\n const [idStr, unitsStr] = value.split(':');\n const id = parseInt(idStr);\n const units = unitsStr ? parseInt(unitsStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid custom asset format: \"${value}\". Use <id>:<units> (e.g. 100:12)`);\n return [...previous, { id, units }];\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerManufacturersCommands(inventory: Command): void {\n const mfr = inventory.command('manufacturers').description('Manage manufacturers (referenced by all inventory devices)');\n\n mfr\n .command('list')\n .description('List all manufacturers. Fields: idManufacturer, name, imageUrl')\n .action(async () => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const res = await client.get('/manufacturers');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n mfr\n .command('create')\n .description('Create a new manufacturer')\n .requiredOption('--data <json>', 'JSON: { \"name\": \"Manufacturer Name\", \"imageUrl\": \"...\" }')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(mfr);\n const client = createServiceClient('solar', global);\n const body = JSON.parse(opts.data);\n const res = await client.post('/manufacturers', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction parseData(data: string | undefined): Record<string, unknown> | undefined {\n if (!data) return undefined;\n return JSON.parse(data);\n}\n\nexport function registerCustomFieldsCommands(inventory: Command): void {\n const fields = inventory.command('custom-fields').description(\n 'Manage custom fields for custom asset types.\\n' +\n 'Fields define the schema of a custom asset type (e.g. text, number, options).\\n' +\n 'Types: text, number, date, datetime, time, email, phonenumber, website, options, labels, currency, large_text, user'\n );\n\n // --- list ---\n fields\n .command('list')\n .description('List all custom fields')\n .action(async () => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get('/custom-asset/custom-field/all');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n fields\n .command('get <id>')\n .description('Get a custom field by ID')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/custom-asset/custom-field/id/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- create ---\n fields\n .command('create')\n .description(\n 'Create a custom field for a custom asset type.\\n' +\n 'Required: label, type, customAssetTypeId\\n' +\n 'For options/labels type, include customFieldOptions array.\\n\\n' +\n 'Example:\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Power\",\"type\":\"number\",\"customAssetTypeId\":1}\\'\\n' +\n ' suntropy inventory custom-fields create --data \\'{\"label\":\"Size\",\"type\":\"options\",\"customAssetTypeId\":1,\"customFieldOptions\":[{\"label\":\"S\",\"value\":\"s\"},{\"label\":\"M\",\"value\":\"m\"},{\"label\":\"L\",\"value\":\"l\"}]}\\''\n )\n .requiredOption('--data <json>', 'Field definition as JSON')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.post('/custom-asset/custom-field', body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- update ---\n fields\n .command('update <id>')\n .description('Update a custom field')\n .requiredOption('--data <json>', 'Updated field data as JSON')\n .action(async (id, opts) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const body = parseData(opts.data);\n const res = await client.put(`/custom-asset/custom-field/${id}`, body);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- delete ---\n fields\n .command('delete <id>')\n .description('Delete a custom field')\n .action(async (id) => {\n try {\n const global = getGlobalOpts(fields);\n const client = createServiceClient('solar', global);\n const res = await client.delete(`/custom-asset/custom-field/${id}`);\n output(res.data ?? { success: true, deleted: id }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createResourceCommands, type ResourceConfig } from './factory.js';\nimport { registerKitsCommands } from './kits.js';\nimport { registerManufacturersCommands } from './manufacturers.js';\nimport { registerCustomFieldsCommands } from './custom-fields.js';\n\nconst RESOURCES: ResourceConfig[] = [\n {\n name: 'panels',\n singular: 'solar panel',\n basePath: '/solar-panels',\n idField: 'solarPanelId',\n listFields: ['name', 'manufacturer', 'peakPower', 'efficiency', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-panels',\n },\n {\n name: 'inverters',\n singular: 'solar inverter',\n basePath: '/solar-inverter',\n idField: 'idInverter',\n listFields: ['name', 'manufacturer', 'nominalPower', 'efficiency', 'phaseNumber', 'isMicroinverter', 'isHybrid', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-inverters',\n putBodyOnly: true,\n },\n {\n name: 'batteries',\n singular: 'battery',\n basePath: '/solar-battery',\n idField: 'batteryId',\n listFields: ['name', 'manufacturer', 'capacity', 'isModular', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-solar-batteries',\n },\n {\n name: 'chargers',\n singular: 'VE charger',\n basePath: '/charger',\n idField: 'idCharger',\n listFields: ['name', 'manufacturer', 'maxPower', 'connectorType', 'phaseNumber', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-chargers',\n putBodyOnly: true,\n },\n {\n name: 'heatpumps',\n singular: 'heat pump',\n basePath: '/heat-pump',\n idField: 'idHeatpump',\n listFields: ['name', 'manufacturer', 'lowerPower', 'upperPower', 'scop', 'costPerUnit', 'active'],\n batchDeletePath: 'delete-batch-heatpumps',\n putBodyOnly: true,\n },\n {\n name: 'custom-assets',\n singular: 'custom asset',\n basePath: '/custom-asset',\n idField: 'idCustomAsset',\n listFields: ['label', 'customAssetType', 'identifier', 'isMaterial', 'costPerUnit', 'active'],\n getPath: '/custom-asset/id/:id',\n },\n {\n name: 'custom-asset-types',\n singular: 'custom asset type',\n basePath: '/custom-asset/type',\n idField: 'idCustomAssetType',\n listFields: ['label', 'isMaterialConcept', 'panelsQuantity'],\n getPath: '/custom-asset/type/id/:id',\n },\n {\n name: 'charger-kits',\n singular: 'VE charger kit',\n basePath: '/charger/ve-charger-kits',\n idField: 'idVEChargerKit',\n listFields: ['identifier', 'charger', 'price', 'phaseNumber', 'active'],\n filterPath: '/charger/ve-charger-kits/filter',\n batchDeletePath: 'delete-batch-ve-charger-kits',\n putBodyOnly: true,\n },\n {\n name: 'heatpump-kits',\n singular: 'heat pump kit',\n basePath: '/heat-pump/heatpump-kits',\n idField: 'idHeatpumpKit',\n listFields: ['identifier', 'heatpump', 'price', 'phaseNumber', 'active'],\n filterPath: '/heat-pump/heatpump-kits/filter',\n batchDeletePath: 'delete-batch-heatpump-kits',\n putBodyOnly: true,\n },\n];\n\nexport function registerInventoryCommands(program: Command): void {\n const inventory = program.command('inventory').description('Manage inventory: panels, inverters, batteries, chargers, heatpumps, custom-assets, kits');\n\n // Register manufacturer commands (special - simpler CRUD)\n registerManufacturersCommands(inventory);\n\n // Register all standard CRUD resources\n for (const resource of RESOURCES) {\n inventory.addCommand(createResourceCommands(resource));\n }\n\n // Register custom fields (separate CRUD)\n registerCustomFieldsCommands(inventory);\n\n // Register kits (complex - has sub-resources)\n registerKitsCommands(inventory);\n}\n","import { Command, Option } from 'commander';\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { v4 } from 'uuid';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\n// ─── Types ───\n\ninterface StepsProgress {\n clientDetails: boolean | undefined;\n consumption: boolean | undefined;\n surfacesSelector: boolean | undefined;\n production: boolean | undefined;\n results: boolean | undefined;\n economicBalance: boolean | undefined;\n}\n\ninterface SolarStudyProgress {\n stepsProgress: StepsProgress;\n stepsUpdates: Record<string, boolean | undefined>;\n editingSolarStudy: boolean;\n lastStateUpdateMomentMS: number;\n}\n\ninterface ByPeriodValues {\n p1?: number;\n p2?: number;\n p3?: number;\n p4?: number;\n p5?: number;\n p6?: number;\n [key: string]: number | undefined;\n}\n\ntype Study = Record<string, unknown>;\n\n// ─── Study defaults (replicates SolarStudy constructor) ───\n\nfunction createDefaultStudy(name?: string): Study {\n const now = new Date();\n const dateStr = now.toISOString().split('T')[0];\n return {\n id: v4(),\n surfaces: undefined,\n clientDetails: {\n identifier: undefined,\n sector: undefined,\n email: undefined,\n cups: undefined,\n phoneNumber: undefined,\n address: undefined,\n instalationLocation: undefined,\n region: undefined,\n subregion: undefined,\n addressCode: undefined,\n dniOrCif: undefined,\n includeTaxes: false,\n taxesPercentage: 0,\n },\n location: undefined,\n atrTariff: undefined,\n geographicalZone: undefined,\n energyPrices: { units: '€/kWh' },\n contractedPower: {},\n powerPrices: { units: '€/kW · dia' },\n results: undefined,\n consumptionIntroductionMode: 'periods',\n peakPowerIntroductionMode: 'solarKit',\n instalationPhaseNumber: 'single_phase',\n peakPowerOptimizationMethod: {\n maxNumberOfOverproductionMonths: 3,\n },\n useAlternativePrices: false,\n economicResults: {\n guaranteeProductionPercentage: 85,\n inflation: 3,\n instalationLifeTime: 25,\n commercialFeePercentage: 85,\n instalationFinancingPercentage: 0,\n taxesPercentage: 21,\n includeTaxes: false,\n margen: 0,\n },\n creationTimestamp: dateStr,\n solarStudyProgress: {\n stepsProgress: {\n clientDetails: undefined,\n consumption: undefined,\n economicBalance: undefined,\n production: undefined,\n results: undefined,\n surfacesSelector: undefined,\n },\n stepsUpdates: {\n clientDetails: false,\n consumption: false,\n economicBalance: false,\n production: false,\n results: false,\n surfacesSelector: false,\n },\n editingSolarStudy: false,\n lastStateUpdateMomentMS: now.getTime(),\n } as SolarStudyProgress,\n activeBatteries: false,\n batteriesConfiguration: {\n initialCapacityPercentage: 100,\n maxCapacityPercentage: 100,\n minCapacityPercentage: 0,\n },\n layout: 'v2',\n lastStateUpdateMomentMS: now.getTime(),\n name: name || `Estudio Solar ${dateStr}`,\n notes: undefined,\n market: 'es',\n };\n}\n\n// ─── Auto-validation engine (replicates frontend step conditions) ───\n\nfunction checkByPeriodCompletion(periodNumber: number, element: ByPeriodValues | undefined): boolean {\n if (!element) return false;\n let assigned = 0;\n for (let i = 1; i <= 6; i++) {\n const val = element['p' + i];\n if (val !== undefined && val !== null && !isNaN(val)) {\n assigned++;\n }\n }\n return assigned >= periodNumber;\n}\n\nfunction evaluateSteps(study: Study): { stepsProgress: StepsProgress; missing: Record<string, string> } {\n const missing: Record<string, string> = {};\n\n // --- clientDetails ---\n const atrTariff = study.atrTariff as { periods?: number } | undefined;\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n const geographicalZone = study.geographicalZone as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const extraCostPrice = study.extraCostPrice as ByPeriodValues | undefined;\n\n let clientDetailsComplete = true;\n if (!atrTariff) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs atrTariff (use: studies set tariff)';\n } else if (!checkByPeriodCompletion(atrTariff.periods || 3, energyPrices)) {\n clientDetailsComplete = false;\n missing.clientDetails = `Needs energyPrices with ${atrTariff.periods || 3} periods filled (use: studies set prices)`;\n } else if (!geographicalZone) {\n clientDetailsComplete = false;\n missing.clientDetails = 'Needs geographicalZone (use: studies set tariff --zone-id N)';\n } else if (market === 'pt' && !checkByPeriodCompletion(1, extraCostPrice)) {\n clientDetailsComplete = false;\n missing.clientDetails = 'PT market needs extraCostPrice with 1 period (use: studies set prices --extra-cost-p1 N)';\n }\n\n // --- consumption ---\n const consumption = study.consumption as { days?: unknown[] } | undefined;\n const consumptionComplete = !!consumption?.days?.length;\n if (!consumptionComplete) {\n missing.consumption = 'Needs consumption curve (use: studies set consumption)';\n }\n\n // --- surfacesSelector ---\n const surfaces = study.surfaces as unknown[] | undefined;\n const surfacesComplete = !!surfaces?.length;\n if (!surfacesComplete) {\n missing.surfacesSelector = 'Needs at least one surface (use: studies add surface)';\n }\n\n // --- production ---\n // Requires: at least one surface with production curve AND equipment (panel or kit) selected\n const solarPanel = study.solarPanel as Record<string, unknown> | undefined;\n const solarKit = study.solarKit as Record<string, unknown> | undefined;\n const hasEquipment = !!solarPanel || !!solarKit;\n let hasProductionCurve = false;\n if (surfaces && surfaces.length > 0) {\n for (const s of surfaces) {\n const surf = s as { production?: { days?: unknown[] } };\n if (surf.production?.days?.length) {\n hasProductionCurve = true;\n break;\n }\n }\n }\n const productionComplete = hasProductionCurve && hasEquipment;\n if (!productionComplete) {\n const reasons: string[] = [];\n if (!hasEquipment) reasons.push('no panel or kit selected (use: studies set panel or studies set kit)');\n if (!hasProductionCurve) reasons.push('no surface has a production curve (use: studies calculate production)');\n missing.production = reasons.join('; ');\n }\n\n // --- results ---\n const results = study.results as Record<string, unknown> | undefined;\n const resultsComplete = results !== undefined;\n if (!resultsComplete) {\n missing.results = 'Results not calculated (use: studies calculate results)';\n }\n\n // --- economicBalance ---\n const economicResults = study.economicResults as Record<string, unknown> | undefined;\n const economicBalanceComplete =\n economicResults?.margen !== undefined &&\n economicResults?.totalCost !== undefined &&\n results !== undefined;\n if (!economicBalanceComplete) {\n const reasons: string[] = [];\n if (economicResults?.margen === undefined) reasons.push('margen');\n if (economicResults?.totalCost === undefined) reasons.push('totalCost');\n if (!results) reasons.push('results');\n missing.economicBalance = `Needs: ${reasons.join(', ')} (use: studies set economics)`;\n }\n\n return {\n stepsProgress: {\n clientDetails: clientDetailsComplete,\n consumption: consumptionComplete,\n surfacesSelector: surfacesComplete,\n production: productionComplete,\n results: resultsComplete,\n economicBalance: economicBalanceComplete,\n },\n missing,\n };\n}\n\nfunction calculateCompletionPercentage(stepsProgress: StepsProgress): number {\n const completed = Object.values(stepsProgress).filter(Boolean).length;\n return Math.round((completed / 6) * 100);\n}\n\n// ─── Cascade resets ───\n\ntype StepName = keyof StepsProgress;\n\nconst CASCADE_RESETS: Record<string, StepName[]> = {\n consumption: ['production', 'results', 'economicBalance'],\n surfaces: ['production', 'results', 'economicBalance'],\n};\n\nfunction applyCascadeResets(study: Study, changedField: string): string[] {\n const resetSteps = CASCADE_RESETS[changedField];\n if (!resetSteps) return [];\n\n const progress = (study.solarStudyProgress as SolarStudyProgress);\n const resets: string[] = [];\n for (const step of resetSteps) {\n if (progress.stepsProgress[step] !== undefined) {\n progress.stepsProgress[step] = undefined;\n resets.push(step);\n }\n }\n\n // Also clear dependent data for full resets\n if (changedField === 'consumption') {\n // Don't clear surfaces production, only results\n study.results = undefined;\n }\n if (changedField === 'surfaces') {\n study.results = undefined;\n }\n\n return resets;\n}\n\n// ─── File I/O helpers ───\n\nfunction readStudy(filePath: string): Study {\n if (!existsSync(filePath)) {\n throw new Error(`Study file not found: ${filePath}. Use 'studies init --file ${filePath}' to create one.`);\n }\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n}\n\nfunction writeStudy(filePath: string, study: Study): void {\n writeFileSync(filePath, JSON.stringify(study, null, 2), 'utf-8');\n}\n\n/** Read study, apply changes, re-validate, write back, return status */\nfunction updateStudy(\n filePath: string,\n updater: (study: Study) => string | undefined, // returns cascade field name or undefined\n): { stepsProgress: StepsProgress; completionPercentage: number; missing: Record<string, string>; cascadeResets: string[] } {\n const study = readStudy(filePath);\n const cascadeField = updater(study);\n\n // Apply cascade resets\n let cascadeResets: string[] = [];\n if (cascadeField) {\n cascadeResets = applyCascadeResets(study, cascadeField);\n }\n\n // Re-evaluate all steps\n const { stepsProgress, missing } = evaluateSteps(study);\n\n // Update solarStudyProgress\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n study.lastStateUpdateMomentMS = Date.now();\n\n writeStudy(filePath, study);\n\n return {\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n cascadeResets,\n };\n}\n\n/**\n * Spreads a total panel count over the study surfaces, keeping the current\n * proportion between them (equal split when none of them has a count yet).\n * Any remainder from the rounding goes to the largest surface.\n *\n * `--panels-count` used to write the whole figure into `surfaces[0]`, which on a\n * multi-surface study silently added panels instead of setting the total: a\n * 24 + 24 roof asked for 48 ended up with 48 + 24 = 72.\n */\nfunction distributePanels(\n surfaces: Record<string, unknown>[],\n total: number,\n): number[] {\n if (!surfaces.length) return [];\n if (surfaces.length === 1) return [total];\n\n const current = surfaces.map((s) => Number(s.panelNumber) || 0);\n const currentTotal = current.reduce((a, b) => a + b, 0);\n const weights = currentTotal > 0\n ? current.map((n) => n / currentTotal)\n : surfaces.map(() => 1 / surfaces.length);\n\n const counts = weights.map((w) => Math.floor(total * w));\n let remainder = total - counts.reduce((a, b) => a + b, 0);\n\n // Hand the leftovers out one by one, largest surface first.\n const order = counts\n .map((n, i) => ({ n, i }))\n .sort((a, b) => b.n - a.n)\n .map((x) => x.i);\n for (let k = 0; remainder > 0; k = (k + 1) % order.length) {\n counts[order[k]] += 1;\n remainder -= 1;\n }\n\n return counts;\n}\n\n/** Deep merge: target ← source (non-destructive, arrays replaced not merged) */\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {\n for (const key of Object.keys(source)) {\n const sv = source[key];\n const tv = target[key];\n if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {\n deepMerge(tv as Record<string, unknown>, sv as Record<string, unknown>);\n } else {\n target[key] = sv;\n }\n }\n}\n\n// ─── CLI helpers ───\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nfunction resolveFile(opts: { file?: string }): string {\n return opts.file || process.env.SUNTROPY_STUDY || './study.json';\n}\n\ntype LatLng = { lat: number; lng: number };\n\n/**\n * Resolve the geographic coordinates used to calculate a surface, in order of\n * preference:\n * 1. surface.center — explicit surface centre (e.g. set by `add surface`)\n * 2. study.location — study-level location\n * 3. polygonPath centroid — average of the drawn polygon vertices\n * 4. polygonPath first point — fallback when the centroid is degenerate\n *\n * A surface drawn in the editor arrives with a full `polygonPath` but no\n * `center`, and studies from that flow may also lack `location`. Deriving the\n * coordinate from the polygon lets those surfaces be calculated instead of\n * failing with \"no coordinates\". Returns null only when no usable point exists.\n */\nexport function resolveSurfaceCoordinates(\n surface: Record<string, unknown>,\n study: Study,\n): LatLng | null {\n const isValid = (c: unknown): c is LatLng => {\n const p = c as LatLng | undefined;\n return !!p && Number.isFinite(p.lat) && Number.isFinite(p.lng);\n };\n\n const center = surface.center as LatLng | undefined;\n if (isValid(center)) return { lat: center.lat, lng: center.lng };\n\n const studyLocation = study.location as LatLng | undefined;\n if (isValid(studyLocation)) return { lat: studyLocation.lat, lng: studyLocation.lng };\n\n const path = surface.polygonPath as Array<{ lat?: number; lng?: number }> | undefined;\n if (Array.isArray(path) && path.length > 0) {\n const points = path.filter(\n (p): p is LatLng => Number.isFinite(p?.lat) && Number.isFinite(p?.lng),\n );\n if (points.length > 0) {\n // Centroid: average of the polygon vertices.\n const sum = points.reduce(\n (acc, p): LatLng => ({ lat: acc.lat + p.lat, lng: acc.lng + p.lng }),\n { lat: 0, lng: 0 },\n );\n const centroid = { lat: sum.lat / points.length, lng: sum.lng / points.length };\n if (isValid(centroid)) return centroid;\n // Fallback: first valid point of the path.\n return { lat: points[0].lat, lng: points[0].lng };\n }\n }\n\n return null;\n}\n\n/**\n * Installed DC power (Watts) sent to `/solar-study/calculateProduction` for a\n * surface, replicating the frontend `generateCalculateProductionDto`:\n *\n * installedPower = (panelsLayoutPolygons?.length ?? panelNumber) * panelPeakPower\n *\n * The panel peak power comes from `study.solarPanel.peakPower` — kit mode also\n * populates `solarPanel` from `solarKit.kitSolarPanel`, so both peak-power modes\n * resolve. An explicit `surface.installedPower` (e.g. from `add surface --power`)\n * takes precedence. The old code read only `surface.installedPower || 5000`, a\n * field the frontend never sets, so studies built in the UI were silently\n * calculated for the 5000 W (5 kWp) default.\n *\n * Returns `isDefault: true` when it had to fall back to 5000 W so the caller can\n * warn instead of emitting wrong production numbers silently.\n */\nexport function resolveSurfaceInstalledPower(\n surface: Record<string, unknown>,\n study: Study,\n): { installedPower: number; isDefault: boolean } {\n const explicit = surface.installedPower as number | undefined;\n if (Number.isFinite(explicit) && (explicit as number) > 0) {\n return { installedPower: explicit as number, isDefault: false };\n }\n\n const solarPanel = study.solarPanel as { peakPower?: number } | undefined;\n const kitPanel = (study.solarKit as { kitSolarPanel?: { peakPower?: number } } | undefined)?.kitSolarPanel;\n const panelPeakPower = (solarPanel?.peakPower as number) || (kitPanel?.peakPower as number) || undefined;\n\n // Frontend precedence: drawn panel layout length, else surface.panelNumber.\n const layout = surface.panelsLayoutPolygons as unknown[] | undefined;\n const panelCount = layout !== undefined\n ? (layout.length || 0)\n : (surface.panelNumber as number | undefined);\n\n if (panelPeakPower && Number.isFinite(panelCount) && (panelCount as number) > 0) {\n return { installedPower: (panelCount as number) * panelPeakPower, isDefault: false };\n }\n\n return { installedPower: 5000, isDefault: true };\n}\n\n// ─── Register commands ───\n\nexport function registerStudyBuilderCommands(studies: Command): void {\n\n // ═══════════════════════════════════════════\n // INIT\n // ═══════════════════════════════════════════\n studies\n .command('init')\n .description(\n 'Create a new study workspace (local JSON file with defaults).\\n' +\n 'Example: suntropy studies init --file /tmp/study.json --name \"Residencial 5kW\"'\n )\n .option('--file <path>', 'Output file path (default: ./study.json)')\n .option('--name <studyName>', 'Study name')\n .option('--market <code>', 'Market country: es, pt, it, fr, de, etc.', 'es')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const study = createDefaultStudy(opts.name);\n if (opts.market) study.market = opts.market;\n writeStudy(filePath, study);\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n file: filePath,\n id: study.id,\n name: study.name,\n stepsProgress,\n completionPercentage: 0,\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // VALIDATE\n // ═══════════════════════════════════════════\n studies\n .command('validate')\n .description(\n 'Check completion status of all study steps.\\n' +\n 'Returns stepsProgress, completionPercentage, and what is missing for each incomplete step.'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const study = readStudy(resolveFile(opts));\n const { stepsProgress, missing } = evaluateSteps(study);\n output({\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // SAVE\n // ═══════════════════════════════════════════\n studies\n .command('save')\n .description(\n 'Save study to the backend (POST /solar-study).\\n' +\n 'If the study has _id, it updates the existing study. Otherwise creates new.\\n' +\n 'Example: suntropy studies save --file /tmp/study.json --state-id 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--state-id <n>', 'Solar study metadata state ID')\n .option('--credit-amount <n>', 'Credit amount to consume')\n .option('--save-as-new', 'Force save as new study (even if _id exists)')\n .action(async (opts) => {\n try {\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const study = readStudy(filePath);\n\n // Re-validate before saving\n const { stepsProgress } = evaluateSteps(study);\n const progress = study.solarStudyProgress as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.lastStateUpdateMomentMS = Date.now();\n\n // Auto-add comment like frontend SaveStudyModal\n const isEditing = progress.editingSolarStudy || !!study._id;\n const comments = (study.comments || []) as Record<string, unknown>[];\n const commentType = opts.saveAsNew ? 'duplicated' : (isEditing ? 'modified' : 'created');\n comments.push(createComment(commentType));\n study.comments = comments;\n\n if (opts.saveAsNew) {\n delete study._id;\n }\n\n const client = createServiceClient('solar', global);\n const params: Record<string, string> = {};\n if (opts.stateId) params.idSolarStudyState = opts.stateId;\n if (opts.creditAmount) params.creditAmount = opts.creditAmount;\n if (opts.saveAsNew) params.saveAsNew = 'true';\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const url = `/solar-study${queryString ? '?' + queryString : ''}`;\n\n const res = await client.post(url, study);\n\n // If response contains _id or solarStudyId, update local file\n const responseData = res.data as Record<string, unknown>;\n if (responseData?.solarStudyId) {\n study._id = responseData.solarStudyId as string;\n progress.editingSolarStudy = true;\n writeStudy(filePath, study);\n }\n\n output({\n saved: true,\n metadata: responseData,\n file: filePath,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // PULL\n // ═══════════════════════════════════════════\n studies\n .command('pull <studyId>')\n .description(\n 'Download an existing study from the backend into a local file.\\n' +\n 'Example: suntropy studies pull abc123 --file /tmp/study.json'\n )\n .option('--file <path>', 'Output file path')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const filePath = resolveFile(opts);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Study;\n\n // Re-validate\n const { stepsProgress, missing } = evaluateSteps(study);\n const progress = (study.solarStudyProgress || {}) as SolarStudyProgress;\n progress.stepsProgress = stepsProgress;\n progress.editingSolarStudy = true;\n study.solarStudyProgress = progress;\n\n writeStudy(filePath, study);\n output({\n file: filePath,\n _id: study._id,\n name: study.name,\n stepsProgress,\n completionPercentage: calculateCompletionPercentage(stepsProgress),\n missing,\n }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // SET — parent command for all sub-commands\n // ═══════════════════════════════════════════\n const set = studies.command('set').description('Set study properties. Each sub-command auto-validates after changes.');\n\n // --- set name ---\n set\n .command('name')\n .description('Set the study name')\n .option('--file <path>', 'Study file path')\n .requiredOption('--name <studyName>', 'Study name')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.name = opts.name;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set market ---\n set\n .command('market')\n .description('Set the market country code (es, pt, it, fr, de, etc.)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--market <code>', 'Market country code')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n study.market = opts.market;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set client ---\n set\n .command('client')\n .description(\n 'Set client details (name, email, phone, cups, address, etc.)\\n' +\n 'Example: suntropy studies set client --file study.json --name \"Juan García\" --email j@co.com --cups ES001234'\n )\n .option('--file <path>', 'Study file path')\n .option('--name <clientName>', 'Client name (identifier/razón social)')\n .option('--email <email>', 'Client email')\n .option('--phone <phone>', 'Phone number')\n .option('--cups <cups>', 'CUPS code')\n .option('--address <addr>', 'Address')\n .option('--city <city>', 'City')\n .option('--region <region>', 'Region (comunidad autónoma)')\n .option('--subregion <subregion>', 'Subregion (provincia)')\n .option('--dni <dni>', 'DNI or CIF')\n .option('--sector <sector>', 'Client sector')\n .option('--installation-location <loc>', 'Installation location description')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const cd = (study.clientDetails || {}) as Record<string, unknown>;\n if (opts.name) cd.identifier = opts.name;\n if (opts.email) cd.email = opts.email;\n if (opts.phone) cd.phoneNumber = opts.phone;\n if (opts.cups) cd.cups = opts.cups;\n if (opts.address) cd.address = opts.address;\n if (opts.city) cd.city = opts.city;\n if (opts.region) cd.region = opts.region;\n if (opts.subregion) cd.subregion = opts.subregion;\n if (opts.dni) cd.dniOrCif = opts.dni;\n if (opts.sector) cd.sector = opts.sector;\n if (opts.installationLocation) cd.instalationLocation = opts.installationLocation;\n study.clientDetails = cd;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set tariff ---\n set\n .command('tariff')\n .description(\n 'Set ATR tariff and geographical zone. Auto-sets phase (>3 periods → three_phase).\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD (3 periods), 14=3.0TD (6 periods)\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n' +\n 'Example: suntropy studies set tariff --file study.json --tariff-id 13 --zone-id 1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--tariff-id <n>', 'ATR tariff ID')\n .option('--zone-id <n>', 'Geographical zone ID', '1')\n .option('--market <code>', 'Market code for tariff lookup', 'es')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('periods', global);\n\n // Fetch tariff info\n const tariffRes = await client.get('/tarifas-atr', {\n params: { market: opts.market },\n });\n const tariffs = (Array.isArray(tariffRes.data) ? tariffRes.data : tariffRes.data?.data || []) as Record<string, unknown>[];\n const tariffId = parseInt(opts.tariffId);\n const tariff = tariffs.find((t) => t.idTarifaATR === tariffId);\n if (!tariff) {\n outputError(new Error(`Tariff ID ${tariffId} not found. Available: ${tariffs.map((t) => `${t.idTarifaATR}=${t.nombre}`).join(', ')}`));\n return;\n }\n\n // Fetch zone info\n const zoneRes = await client.get('/zonas', {\n params: { market: opts.market },\n });\n const zones = (Array.isArray(zoneRes.data) ? zoneRes.data : zoneRes.data?.data || []) as Record<string, unknown>[];\n const zoneId = parseInt(opts.zoneId);\n const zone = zones.find((z) => z.idZona === zoneId);\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.atrTariff = tariff;\n if (zone) study.geographicalZone = zone;\n\n // Auto-set phase based on tariff periods (replicates frontend logic)\n const periods = (tariff.periods as number) || 3;\n study.instalationPhaseNumber = periods > 3 ? 'three_phase' : 'single_phase';\n\n return undefined; // no cascade reset for tariff change\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set prices ---\n set\n .command('prices')\n .description(\n 'Set energy prices by period.\\n' +\n 'Examples:\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,\"p2\":0.08,\"p3\":0.06}\\'\\n' +\n ' suntropy studies set prices --file study.json --energy-p1 0.15 --energy-p2 0.08 --energy-p3 0.06\\n' +\n ' suntropy studies set prices --file study.json --energy \\'{\"p1\":0.15,...}\\' --power \\'{\"p1\":40,...}\\' --contracted \\'{\"p1\":5.5,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--energy <json>', 'Energy prices JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--energy-p1 <n>', 'Energy price period 1 (€/kWh)')\n .option('--energy-p2 <n>', 'Energy price period 2 (€/kWh)')\n .option('--energy-p3 <n>', 'Energy price period 3 (€/kWh)')\n .option('--energy-p4 <n>', 'Energy price period 4 (€/kWh)')\n .option('--energy-p5 <n>', 'Energy price period 5 (€/kWh)')\n .option('--energy-p6 <n>', 'Energy price period 6 (€/kWh)')\n .option('--power <json>', 'Power prices JSON: {\"p1\":N,\"p2\":N,...} (€/kW·day)')\n .option('--contracted <json>', 'Contracted power JSON: {\"p1\":N,\"p2\":N,...} (kW)')\n .option('--extra-cost-p1 <n>', 'Extra cost price P1 (Portugal market)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n // Energy prices: from JSON or individual flags\n const ep = (study.energyPrices || { units: '€/kWh' }) as Record<string, unknown>;\n if (opts.energy) {\n const parsed = JSON.parse(opts.energy);\n Object.assign(ep, parsed);\n }\n for (let i = 1; i <= 6; i++) {\n const val = opts[`energyP${i}`];\n if (val !== undefined) ep[`p${i}`] = parseFloat(val);\n }\n study.energyPrices = ep;\n\n // Power prices\n if (opts.power) {\n const pp = (study.powerPrices || { units: '€/kW · dia' }) as Record<string, unknown>;\n Object.assign(pp, JSON.parse(opts.power));\n study.powerPrices = pp;\n }\n\n // Contracted power\n if (opts.contracted) {\n const cp = (study.contractedPower || {}) as Record<string, unknown>;\n Object.assign(cp, JSON.parse(opts.contracted));\n study.contractedPower = cp;\n }\n\n // Extra cost (Portugal)\n if (opts.extraCostP1 !== undefined) {\n study.extraCostPrice = { p1: parseFloat(opts.extraCostP1), units: '€/kWh' };\n }\n\n return undefined; // no cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set consumption ---\n set\n .command('consumption')\n .description(\n 'Set the consumption curve.\\n' +\n 'Modes:\\n' +\n ' --from-file <path> Load PowerCurve from JSON file\\n' +\n ' --annual + --pattern Generate via consumption-estimation API\\n' +\n ' --by-period <json> Period consumption: {\"p1\":N,\"p2\":N,\"p3\":N} + REE profile\\n' +\n ' --monthly <json> Monthly consumption: {\"1\":N,\"2\":N,...,\"12\":N} + REE profile\\n' +\n ' --monthly-by-period Monthly by period: {\"1\":{\"p1\":N,\"p2\":N},...} + REE profile\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies set consumption --file study.json --from-file /tmp/cons.json\\n' +\n ' suntropy studies set consumption --file study.json --annual 4000 --pattern Balance\\n' +\n ' suntropy studies set consumption --file study.json --by-period \\'{\"p1\":2500,\"p2\":1000,\"p3\":500}\\'\\n' +\n ' suntropy studies set consumption --file study.json --monthly \\'{\"1\":350,\"2\":320,...}\\''\n )\n .option('--file <path>', 'Study file path')\n .option('--from-file <curvePath>', 'Load PowerCurve from JSON file')\n .option('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--by-period <json>', 'Period consumption JSON: {\"p1\":N,\"p2\":N,...}')\n .option('--monthly <json>', 'Monthly consumption JSON: {\"1\":N,...,\"12\":N}')\n .option('--monthly-by-period <json>', 'Monthly by period: {\"1\":{\"p1\":N,...},...}')\n .option('--tariff <code>', 'Tariff code for profile lookup (default: from study)')\n .option('--market <code>', 'Market code (default: from study)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const studyTariff = (study.atrTariff as Record<string, unknown>)?.nombre as string || '3.0TD';\n const studyMarket = (study.market as string) || 'es';\n const tariff = opts.tariff || studyTariff;\n const market = opts.market || studyMarket;\n const year = new Date().getFullYear();\n\n let curveData: unknown;\n let introductionMode: string;\n\n if (opts.fromFile) {\n // Load from file\n curveData = JSON.parse(readFileSync(opts.fromFile, 'utf-8'));\n introductionMode = 'upload';\n\n } else if (opts.annual && opts.pattern) {\n // Generate via backend /consumption-estimation\n const profilesClient = createServiceClient('profiles', global);\n const params: Record<string, string> = {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n anualConsumption: opts.annual,\n market,\n consumptionType: opts.pattern,\n };\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n const res = await profilesClient.post(`/consumption-estimation?${queryString}`, {});\n curveData = res.data;\n introductionMode = 'consumption_patterns';\n\n } else if (opts.byPeriod) {\n // Fetch REE profile + period distribution, apply locally\n const periodValues = JSON.parse(opts.byPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'CONSUMPTION_BY_PERIOD', periodValues);\n introductionMode = 'periods';\n\n } else if (opts.monthly) {\n // Fetch REE profile, apply monthly consumption\n const monthValues = JSON.parse(opts.monthly);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTH_CONSUMPTION', monthValues);\n introductionMode = 'monthly_consumption';\n\n } else if (opts.monthlyByPeriod) {\n // Complex: monthly by period\n const monthPeriodValues = JSON.parse(opts.monthlyByPeriod);\n curveData = await generateFromProfile(global, tariff, market, year, 'MONTHLY_BY_PERIOD', monthPeriodValues);\n introductionMode = 'monthly_periods';\n\n } else {\n outputError(new Error('Specify one of: --from-file, --annual + --pattern, --by-period, --monthly, --monthly-by-period'));\n return;\n }\n\n // Update study with consumption\n const result = updateStudy(filePath, (s) => {\n s.consumption = curveData;\n s.consumptionIntroductionMode = introductionMode;\n if (opts.annual) s.monthlyConsumption = parseFloat(opts.annual) / 12;\n if (opts.pattern) s.selectedConsumptionPattern = opts.pattern;\n if (opts.byPeriod) s.periodConsumptionDictionary = JSON.parse(opts.byPeriod);\n if (opts.monthly) s.monthConsumptionDictionary = JSON.parse(opts.monthly);\n if (opts.monthlyByPeriod) s.monthPeriodConsumptionDictionary = JSON.parse(opts.monthlyByPeriod);\n return 'consumption'; // trigger cascade\n });\n\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- add surface ---\n studies\n .command('add')\n .description('Add elements to the study')\n .command('surface')\n .description(\n 'Add a solar surface to the study.\\n' +\n 'Example: suntropy studies add surface --file study.json --lat 37.39 --lon -5.99 --angle 30 --azimuth 180 --power 5000'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel azimuth degrees (0=N, 180=S)', '180')\n .option('--power <w>', 'Installed power in Watts')\n .option('--panels-count <n>', 'Number of panels')\n .option('--production <file>', 'Production PowerCurve JSON file to attach')\n .option('--identifier <name>', 'Surface name/identifier')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const lat = parseFloat(opts.lat);\n const lng = parseFloat(opts.lon);\n const surface: Record<string, unknown> = {\n surfaceId: v4(),\n name: opts.identifier || `Surface ${((study.surfaces as unknown[])?.length || 0) + 1}`,\n inclination: parseFloat(opts.angle),\n orientation: parseFloat(opts.azimuth),\n panelInclination: parseFloat(opts.angle),\n panelOrientation: parseFloat(opts.azimuth),\n lossesPercentage: 14,\n // polygonPath required by backend metadata constructor\n polygonPath: [{ lat, lng }],\n };\n if (opts.power) surface.installedPower = parseFloat(opts.power);\n if (opts.panelsCount) surface.panelNumber = parseInt(opts.panelsCount);\n if (opts.production) {\n surface.production = JSON.parse(readFileSync(opts.production, 'utf-8'));\n }\n\n // Also set study-level location\n study.location = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n study.mapCenter = { lat: parseFloat(opts.lat), lng: parseFloat(opts.lon) };\n\n const surfaces = (study.surfaces as unknown[]) || [];\n surfaces.push(surface);\n study.surfaces = surfaces;\n\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- remove surface ---\n studies\n .command('remove')\n .description('Remove elements from the study')\n .command('surface')\n .description('Remove a surface by index')\n .option('--file <path>', 'Study file path')\n .requiredOption('--index <n>', 'Surface index (0-based)')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const surfaces = (study.surfaces as unknown[]) || [];\n const idx = parseInt(opts.index);\n if (idx < 0 || idx >= surfaces.length) {\n throw new Error(`Surface index ${idx} out of range (0-${surfaces.length - 1})`);\n }\n surfaces.splice(idx, 1);\n study.surfaces = surfaces.length > 0 ? surfaces : undefined;\n return 'surfaces'; // cascade\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set panel ---\n set\n .command('panel')\n .description(\n 'Set solar panel for the study. Auto-sets peakPowerIntroductionMode to \"solarPanel\".\\n' +\n 'Fetches full panel data from inventory.\\n' +\n '--panels-count is the TOTAL for the study: it is spread over the surfaces keeping\\n' +\n 'their current proportion (use --surface-index to target a single surface).\\n' +\n 'The response lists the resulting panelNumber per surface.\\n' +\n 'Example: suntropy studies set panel --file study.json --panel-id 456 --panels-count 12'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--panel-id <n>', 'Solar panel ID from inventory')\n .option('--panels-count <n>', 'TOTAL number of panels of the study, spread over its surfaces keeping their current proportion')\n .option('--surface-index <n>', 'Apply --panels-count to this surface only (0-based) instead of spreading it')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full panel data\n const panelRes = await solarClient.get(`/solar-panels/${opts.panelId}`);\n const panel = panelRes.data;\n\n let distribution: { surfaceIndex: number; panelNumber: number }[] = [];\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarPanel = panel;\n study.peakPowerIntroductionMode = 'solarPanel';\n // Clear kit when switching to panel mode\n study.solarKit = undefined;\n if (opts.panelsCount) {\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n const total = parseInt(opts.panelsCount);\n if (surfaces?.length) {\n if (opts.surfaceIndex !== undefined) {\n const idx = parseInt(opts.surfaceIndex);\n if (!Number.isInteger(idx) || idx < 0 || idx >= surfaces.length) {\n throw new Error(\n `--surface-index ${opts.surfaceIndex} is out of range: the study has ${surfaces.length} surface(s)`\n );\n }\n surfaces[idx].panelNumber = total;\n } else {\n const counts = distributePanels(surfaces, total);\n surfaces.forEach((surface, i) => { surface.panelNumber = counts[i]; });\n }\n distribution = surfaces.map((surface, i) => ({\n surfaceIndex: i,\n panelNumber: Number(surface.panelNumber) || 0,\n }));\n }\n }\n return undefined;\n });\n // Report what each surface ended up with: a caller that assumes the\n // total landed where it asked would otherwise misreport the peak power.\n output(distribution.length ? { ...result, surfaces: distribution } : result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set kit ---\n set\n .command('kit')\n .description(\n 'Set solar kit for the study. Auto-sets peakPowerIntroductionMode to \"solarKit\".\\n' +\n 'Fetches full kit data from inventory.\\n' +\n 'Example: suntropy studies set kit --file study.json --kit-id 123'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--kit-id <n>', 'Solar kit ID from inventory')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Kits use getViaFilter (no GET /:id)\n const kitsRes = await solarClient.get('/solar-kits', { params: { unactive: true } });\n const allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n const kitId = parseInt(opts.kitId);\n const kit = allKits.find((k: Record<string, unknown>) => k.idSolarKit === kitId);\n if (!kit) {\n outputError(new Error(`Kit ${kitId} not found`));\n return;\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.solarKit = kit;\n study.peakPowerIntroductionMode = 'solarKit';\n // Clear panel + inverters when switching to kit mode\n study.solarPanel = undefined;\n study.solarInverters = undefined;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set inverter ---\n set\n .command('inverter')\n .description(\n 'Set inverter(s) for the study (when using solarPanel mode).\\n' +\n 'REPLACES the whole list: pass every inverter of the installation, comma-separated,\\n' +\n 'repeating an id as many times as units there are. The response reports how many\\n' +\n 'were there before and how many are there now.\\n' +\n 'Example: suntropy studies set inverter --file study.json --inverter-id 789,789'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--inverter-id <ids>', 'Inverter ID(s), comma-separated for multiple')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n const ids = opts.inverterId.split(',').map((s: string) => parseInt(s.trim()));\n\n const inverters: unknown[] = [];\n for (const id of ids) {\n const res = await solarClient.get(`/solar-inverter/${id}`);\n inverters.push(res.data);\n }\n\n let previousCount = 0;\n const result = updateStudy(resolveFile(opts), (study) => {\n previousCount = (study.solarInverters as unknown[] | undefined)?.length ?? 0;\n study.solarInverters = inverters;\n return undefined;\n });\n // The list is replaced, not appended: say so, because dropping units\n // silently undersizes the installation and its budget.\n output({ ...result, inverters: { before: previousCount, after: inverters.length } }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set phase ---\n set\n .command('phase')\n .description('Manually set installation phase (overrides auto-set from tariff)')\n .option('--file <path>', 'Study file path')\n .requiredOption('--phase <type>', 'Phase: single_phase or three_phase')\n .action(async (opts) => {\n try {\n if (!['single_phase', 'three_phase'].includes(opts.phase)) {\n outputError(new Error('Phase must be single_phase or three_phase'));\n return;\n }\n const result = updateStudy(resolveFile(opts), (study) => {\n study.instalationPhaseNumber = opts.phase;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set economics ---\n set\n .command('economics')\n .description(\n 'Set economic parameters for the study.\\n' +\n 'Example: suntropy studies set economics --file study.json --margin 15 --total-cost 6500 --lifetime 25'\n )\n .option('--file <path>', 'Study file path')\n .option('--margin <n>', 'Margin percentage')\n .option('--total-cost <n>', 'Total installation cost (€)')\n .option('--lifetime <n>', 'Installation lifetime in years')\n .option('--inflation <n>', 'Inflation rate percentage')\n .option('--taxes-pct <n>', 'Tax percentage')\n .option('--include-taxes', 'Include taxes in pricing')\n .option('--commercial-fee <n>', 'Commercial fee percentage')\n .option('--excesses-mode <mode>', 'Excesses compensation: gridSelling, PPA, noInjection, virtualBattery')\n .option('--excesses-buy-price <n>', 'Excesses buy price (€/MWh)')\n .option('--excesses-selling-price <n>', 'Excesses selling price (€/MWh)')\n .option('--peak-power-cost <n>', 'Cost per Wp (€/Wp). If --total-cost is omitted, totalCost is derived as cost × installed peak power (W)')\n .option('--guarantee-production <n>', 'Guarantee production percentage')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const er = (study.economicResults || {}) as Record<string, unknown>;\n if (opts.margin !== undefined) er.margen = parseFloat(opts.margin);\n if (opts.totalCost !== undefined) er.totalCost = parseFloat(opts.totalCost);\n if (opts.lifetime !== undefined) er.instalationLifeTime = parseInt(opts.lifetime);\n if (opts.inflation !== undefined) er.inflation = parseFloat(opts.inflation);\n if (opts.taxesPct !== undefined) er.taxesPercentage = parseFloat(opts.taxesPct);\n if (opts.includeTaxes) er.includeTaxes = true;\n if (opts.commercialFee !== undefined) er.commercialFeePercentage = parseFloat(opts.commercialFee);\n if (opts.excessesMode) er.excessesCompensationMode = opts.excessesMode;\n if (opts.excessesBuyPrice !== undefined) er.excessesBuyPrice = parseFloat(opts.excessesBuyPrice);\n if (opts.excessesSellingPrice !== undefined) er.excessesSellingPrice = parseFloat(opts.excessesSellingPrice);\n if (opts.peakPowerCost !== undefined) er.peakPowerCost = parseFloat(opts.peakPowerCost);\n if (opts.guaranteeProduction !== undefined) er.guaranteeProductionPercentage = parseFloat(opts.guaranteeProduction);\n\n // Auto-derive totalCost from the per-Wp cost when --peak-power-cost is set\n // but --total-cost is not. The economic balance uses economicResults.totalCost\n // as the source of truth; the frontend only derives the €/Wp figure from it\n // (totalCost / installedPeakPowerWp). We invert that here so setting the €/Wp\n // cost alone yields a correct total instead of leaving totalCost untouched\n // (which previously kept the balance at 0). Installed peak power is the sum of\n // the surfaces' resolved installedPower (W); peakPowerCost is €/Wp, so\n // totalCost = cost × watts. If no surface has a resolvable power we warn\n // (non-fatal) instead of writing a wrong total.\n if (opts.peakPowerCost !== undefined && opts.totalCost === undefined) {\n const surfaces = (study.surfaces as Record<string, unknown>[] | undefined) || [];\n let totalWatts = 0;\n let resolvedCount = 0;\n let anyDefault = false;\n for (const surface of surfaces) {\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n anyDefault = true;\n continue;\n }\n totalWatts += installedPower;\n resolvedCount += 1;\n }\n if (resolvedCount > 0 && !anyDefault) {\n er.totalCost = Math.round(parseFloat(opts.peakPowerCost) * totalWatts * 100) / 100;\n } else {\n process.stderr.write(\n JSON.stringify({\n warning:\n 'Set --peak-power-cost but could not derive totalCost: ' +\n (surfaces.length === 0\n ? 'the study has no surfaces.'\n : 'some surfaces have no resolvable installed power (set panels + kit/panel first).') +\n ' Pass --total-cost explicitly to set it.',\n }) + '\\n',\n );\n }\n }\n\n study.economicResults = er;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set custom-assets ---\n set\n .command('custom-assets')\n .description(\n 'Set selected custom assets for the study.\\n' +\n 'Example: suntropy studies set custom-assets --file study.json --asset 100:12 --asset 200:1'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--asset <id:qty>', 'Custom asset as id:quantity (repeatable)', collectAssets, [])\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const solarClient = createServiceClient('solar', global);\n\n // Fetch full custom asset data for each\n const assets: unknown[] = [];\n for (const { id, quantity } of opts.asset) {\n const res = await solarClient.get(`/custom-asset/id/${id}`);\n assets.push({ customAsset: res.data, quantity });\n }\n\n const result = updateStudy(resolveFile(opts), (study) => {\n study.selectedCustomAssets = assets;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- set batteries ---\n set\n .command('batteries')\n .description(\n 'Enable/disable batteries and set configuration.\\n' +\n 'Example: suntropy studies set batteries --file study.json --enable --battery-id 789 --count 1'\n )\n .option('--file <path>', 'Study file path')\n .option('--enable', 'Enable batteries')\n .option('--disable', 'Disable batteries')\n .option('--battery-id <n>', 'Battery ID from inventory')\n .option('--count <n>', 'Number of batteries')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n if (opts.enable) study.activeBatteries = true;\n if (opts.disable) study.activeBatteries = false;\n if (opts.batteryId) {\n // Store battery reference — the full battery object would be fetched when calculating\n const config = (study.batteriesConfiguration || {}) as Record<string, unknown>;\n config.batteryId = parseInt(opts.batteryId);\n if (opts.count) config.batteriesNumber = parseInt(opts.count);\n study.batteriesConfiguration = config;\n }\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- set data (generic fallback) ---\n set\n .command('data')\n .description(\n 'Generic JSON merge into the study (fallback for any field).\\n' +\n 'Example: suntropy studies set data --file study.json --data \\'{\"referenceId\":\"REF-001\"}\\''\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--data <json>', 'JSON to merge into the study')\n .action(async (opts) => {\n try {\n const parsed = JSON.parse(opts.data);\n // Detect cascade fields\n const cascadeFields = Object.keys(parsed);\n let cascadeField: string | undefined;\n if (cascadeFields.includes('consumption')) cascadeField = 'consumption';\n if (cascadeFields.includes('surfaces')) cascadeField = 'surfaces';\n\n const result = updateStudy(resolveFile(opts), (study) => {\n deepMerge(study, parsed);\n return cascadeField;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // ═══════════════════════════════════════════\n // CALCULATE — commands that call backend APIs\n // ═══════════════════════════════════════════\n\n // --- calculate production ---\n studies\n .command('calculate')\n .description('Calculate derived data for the study')\n .command('production')\n .description(\n 'Calculate production for study surfaces using backend API.\\n' +\n 'Example: suntropy studies calculate production --file study.json [--surface-index 0 | --all-surfaces]'\n )\n .option('--file <path>', 'Study file path')\n .option('--surface-index <n>', 'Calculate for specific surface index')\n .option('--all-surfaces', 'Calculate for all surfaces')\n .option('--losses <n>', 'Losses percentage', '14')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n\n const solarClient = createServiceClient('solar', global);\n const indicesToCalc = opts.surfaceIndex !== undefined\n ? [parseInt(opts.surfaceIndex)]\n : Array.from({ length: surfaces.length }, (_, i) => i);\n\n for (const idx of indicesToCalc) {\n const surface = surfaces[idx];\n if (!surface) continue;\n // Coordinates: surface center → study location → drawn polygon (centroid, else first point)\n const coords = resolveSurfaceCoordinates(surface, study);\n if (!coords) {\n outputError(new Error(`Surface ${idx} has no coordinates. Use: studies add surface --lat N --lon N`));\n continue;\n }\n const { lat, lng } = coords;\n // Installed power: explicit → (panel layout | panelNumber) × panel peak power (frontend parity)\n const { installedPower, isDefault } = resolveSurfaceInstalledPower(surface, study);\n if (isDefault) {\n outputError(new Error(\n `Surface ${idx} has no resolvable installed power (no installedPower, and no panel layout / panelNumber with a solarPanel/solarKit peak power). `\n + `Using the 5000W default — production will be wrong. Set the panels and kit/panel before calculating.`,\n ));\n }\n const body = {\n lat,\n long: lng,\n instaledPower: installedPower,\n angle: (surface.inclination as number) || (surface.angle as number) || 30,\n azimuth: (surface.orientation as number) || (surface.azimuth as number) || 180,\n lossesPercentage: parseFloat(opts.losses),\n year: new Date().getFullYear(),\n isOptimized: false,\n };\n const res = await solarClient.post('/solar-study/calculateProduction', body);\n surface.production = res.data;\n }\n\n // Write back and validate\n const result = updateStudy(filePath, (s) => {\n s.surfaces = surfaces;\n return undefined; // don't cascade — we're setting production, not changing surfaces\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate results ---\n studies\n .command('calculate-results')\n .description(\n 'Calculate energy results replicating frontend SolarResultCalculator.\\n' +\n 'Computes: net consumption, excesses, spending/savings by period, coverage.\\n' +\n 'Requires: consumption, production, energyPrices, atrTariff.\\n' +\n 'Example: suntropy studies calculate-results --file study.json'\n )\n .option('--file <path>', 'Study file path')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n const consumption = study.consumption as { days?: unknown[]; identifier?: string } | undefined;\n if (!consumption?.days?.length) {\n outputError(new Error('No consumption curve. Use: studies set consumption'));\n return;\n }\n\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces. Use: studies add surface'));\n return;\n }\n\n const energyPrices = study.energyPrices as ByPeriodValues | undefined;\n if (!energyPrices) {\n outputError(new Error('No energy prices. Use: studies set prices'));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const consCurve = new PowerCurve(consumption.days, false, consumption.identifier || 'consumption', false);\n\n // Aggregate production from all surfaces (replicates SolarResultCalculator.aggregateProductionResults)\n let totalProdCurve: InstanceType<typeof PowerCurve> | null = null;\n for (const surf of surfaces) {\n const prod = surf.production as { days?: unknown[]; identifier?: string } | undefined;\n if (prod?.days?.length) {\n const surfProd = new PowerCurve(prod.days, false, prod.identifier || 'production', false);\n totalProdCurve = totalProdCurve ? totalProdCurve.aggregatePowerCurve(surfProd) : surfProd;\n }\n }\n\n if (!totalProdCurve) {\n outputError(new Error('No production curves found. Use: studies calculate production'));\n return;\n }\n\n const results: Record<string, unknown> = {};\n\n // --- Core energy calculations (always computed) ---\n\n // Net consumption = consumption - production\n const netConsumptionCurve = consCurve.aggregatePowerCurve(totalProdCurve.applyMultiplier(-1));\n results.netConsumption = netConsumptionCurve;\n\n // Total production\n results.totalProduction = totalProdCurve.getTotalAcumulate();\n\n // Consumption coverage percentage\n results.totalConsumptionCoverage =\n ((results.totalProduction as number) / consCurve.getTotalAcumulate()) * 100;\n\n // --- Period-based economic calculations (replicates SolarResultCalculator.calculateResults) ---\n const periodDistribution = await fetchPeriodDistribution(study, global);\n\n if (periodDistribution) {\n const clientDetails = study.clientDetails as Record<string, unknown> | undefined;\n const market = study.market as string | undefined;\n const oneBaseEnergyDiscountFactor = 1 - ((study.energyPricesDiscount as number) || 0) / 100;\n const oneBasePowerDiscountFactor = 1 - ((study.powerPricesDiscount as number) || 0) / 100;\n\n // Positive net consumption (filter out negatives = energy still needed from grid)\n const positiveNetConsumptionCurve = netConsumptionCurve.filterNegativeValues();\n const positiveNetByPeriod = positiveNetConsumptionCurve.aggregateByPeriod(periodDistribution);\n const rawConsumptionByPeriod = consCurve.aggregateByPeriod(periodDistribution);\n\n // Contracted power costs (if useAlternativePrices)\n const contractedPower = (study.contractedPower || {}) as ByPeriodValues;\n const powerPrices = (study.powerPrices || {}) as ByPeriodValues;\n const contractedPowerRawCostByPeriod: ByPeriodValues = {};\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && powerPrices[p]) {\n contractedPowerRawCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n }\n\n // PT market peak cost\n if (market === 'pt') {\n const extraCostPrice = (study.extraCostPrice || {}) as ByPeriodValues;\n let numberOfP1hours = 0;\n periodDistribution.forEach((day: any) => {\n Object.values(day.valuesList).forEach((hour: any) => {\n if (hour === 1) numberOfP1hours++;\n });\n });\n const coefficient =\n (1 / numberOfP1hours) * ((extraCostPrice.p1 as number) || 0) * netConsumptionCurve.days.length;\n results.rawPeakConsumptionCostPt = ((rawConsumptionByPeriod as any)?.p1 || 0) * coefficient;\n results.netPeakConsumptionCostPt = ((positiveNetByPeriod as any)?.p1 || 0) * coefficient;\n }\n\n // Raw spending by period\n const totalRawSpendingByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const rawConsP = (rawConsumptionByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n const priceWithTax = includeTaxes && taxPct ? priceP * (1 + taxPct / 100) : priceP;\n totalRawSpendingByPeriod[p] =\n rawConsP * priceWithTax * oneBaseEnergyDiscountFactor +\n ((contractedPowerRawCostByPeriod[p] as number) || 0);\n }\n results.totalRawSpendingByPeriod = totalRawSpendingByPeriod;\n\n // Total raw spending\n results.totalRawSpending =\n Object.values(totalRawSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.rawPeakConsumptionCostPt as number) || 0);\n\n // Net spending by period + alternative prices\n const alternativeEnergyPrices = (study.alternativeEnergyPrices || {}) as ByPeriodValues;\n const alternativePowerPrices = (study.alternativePowerPrices || {}) as ByPeriodValues;\n const contractedPowerFinalCostByPeriod: ByPeriodValues = {};\n const contractedPowerSavingsByPeriod: ByPeriodValues = {};\n\n if (study.useAlternativePrices) {\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n if (contractedPower[p] && alternativePowerPrices[p]) {\n contractedPowerFinalCostByPeriod[p] =\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number);\n }\n if (contractedPower[p] && powerPrices[p] && alternativePowerPrices[p]) {\n contractedPowerSavingsByPeriod[p] =\n (contractedPower[p] as number) * 365 * (powerPrices[p] as number) * oneBasePowerDiscountFactor -\n (contractedPower[p] as number) * 365 * (alternativePowerPrices[p] as number) * oneBasePowerDiscountFactor;\n }\n }\n results.contractedPowerSavingsByPeriod = contractedPowerSavingsByPeriod;\n }\n\n const totalNetSpendingByPeriod: ByPeriodValues = {};\n const alternativeTotalNetSpendingByPeriod: ByPeriodValues = {};\n\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n const posNetP = (positiveNetByPeriod as any)?.[p] || 0;\n const priceP = (energyPrices[p] as number) || 0;\n const altPriceP = (alternativeEnergyPrices[p] as number) || 0;\n const includeTaxes = clientDetails?.includeTaxes;\n const taxPct = (clientDetails?.taxesPercentage as number) || 0;\n\n totalNetSpendingByPeriod[p] =\n posNetP * (includeTaxes ? priceP * (1 + taxPct / 100) : priceP) * oneBaseEnergyDiscountFactor;\n\n if (study.alternativeEnergyPrices) {\n alternativeTotalNetSpendingByPeriod[p] =\n posNetP * altPriceP + ((contractedPowerFinalCostByPeriod[p] as number) || 0);\n }\n }\n results.totalNetSpendingByPeriod = totalNetSpendingByPeriod;\n if (study.alternativeEnergyPrices) {\n results.alternativeTotalNetSpendingByPeriod = alternativeTotalNetSpendingByPeriod;\n }\n\n // Total net spending\n results.totalNetSpending =\n Object.values(totalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) + ((results.netPeakConsumptionCostPt as number) || 0);\n\n // Savings by period = raw - net\n const totalSavingsByPeriod: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n totalSavingsByPeriod[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) - ((totalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriod = totalSavingsByPeriod;\n\n // Alternative savings by period\n if (study.alternativeEnergyPrices) {\n const altSavings: ByPeriodValues = {};\n for (let i = 1; i <= 6; i++) {\n const p = `p${i}`;\n altSavings[p] =\n ((totalRawSpendingByPeriod[p] as number) || 0) -\n ((alternativeTotalNetSpendingByPeriod[p] as number) || 0);\n }\n results.totalSavingsByPeriodAlternativeSavings = altSavings;\n }\n\n // Total savings\n results.totalSavings =\n Object.values(totalSavingsByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n\n // Total savings with alternative prices\n if (study.alternativeEnergyPrices) {\n results.totalSavingsAlternativePrices =\n Object.values(alternativeTotalNetSpendingByPeriod)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0) +\n (((results.rawPeakConsumptionCostPt as number) || 0) -\n ((results.netPeakConsumptionCostPt as number) || 0));\n }\n\n // Excesses curve = (production - consumption), keep positive\n const excessesCurve = totalProdCurve\n .aggregatePowerCurve(consCurve.applyMultiplier(-1))\n .filterNegativeValues();\n results.excessesCurve = excessesCurve;\n\n // Excesses by period\n results.totalExcessesByPeriod = excessesCurve.aggregateByPeriod(periodDistribution);\n results.totalExcesses = Object.values(results.totalExcessesByPeriod as ByPeriodValues)\n .filter((v): v is number => typeof v === 'number')\n .reduce((a, b) => a + b, 0);\n }\n\n const result = updateStudy(filePath, (s) => {\n s.results = results;\n return undefined;\n });\n output(result, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // OPTIMIZE PEAK POWER\n // ═══════════════════════════════════════════\n\n studies\n .command('optimize-peakpower')\n .description(\n 'Optimize peak power based on consumption.\\n\\n' +\n 'Supports two modes:\\n' +\n ' - Panel mode (default or when solarPanel is set): iterates peak power\\n' +\n ' - Kit mode (when solarKit is set or --use-kits): evaluates available kits\\n\\n' +\n 'Optimization criteria (pick one):\\n' +\n ' --energy-savings <pct> Target energy savings percentage\\n' +\n ' --raw-consumption <pct> Production as percentage of consumption\\n' +\n ' --max-excesses <pct> Max excesses as percentage of production\\n' +\n ' --max-overproduction-months <n> Max months with overproduction\\n\\n' +\n 'Surface constraints:\\n' +\n ' If surfaces have area + panel dimensions, max panels per surface is calculated.\\n' +\n ' Without area, no surface constraint is applied (unlimited space).\\n\\n' +\n 'Examples:\\n' +\n ' suntropy studies optimize-peakpower --file study.json --energy-savings 70\\n' +\n ' suntropy studies optimize-peakpower --file study.json --raw-consumption 100 --use-kits\\n' +\n ' suntropy studies optimize-peakpower --file study.json --max-excesses 15'\n )\n .option('--file <path>', 'Study file path')\n .option('--energy-savings <pct>', 'Target energy savings %')\n .option('--raw-consumption <pct>', 'Target production as % of consumption')\n .option('--max-excesses <pct>', 'Max excesses as % of production')\n .option('--max-overproduction-months <n>', 'Max months with overproduction')\n .option('--use-kits', 'Force kit mode (fetch all active kits and select optimal)')\n .option('--apply', 'Apply the result to the study file (set peakpower/kit, recalculate production)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const filePath = resolveFile(opts);\n const study = readStudy(filePath);\n\n // Determine evaluation mode\n const evaluationMode: Record<string, number> = {};\n if (opts.energySavings !== undefined) evaluationMode.energyPercentageSavings = parseFloat(opts.energySavings);\n else if (opts.rawConsumption !== undefined) evaluationMode.rawConsumptionPercentage = parseFloat(opts.rawConsumption);\n else if (opts.maxExcesses !== undefined) evaluationMode.maxExcessesPercentage = parseFloat(opts.maxExcesses);\n else if (opts.maxOverproductionMonths !== undefined) evaluationMode.maxNumberOfOverproductionMonths = parseInt(opts.maxOverproductionMonths);\n else {\n // Default: 100% raw consumption (match consumption)\n evaluationMode.rawConsumptionPercentage = 100;\n }\n\n // Validate study has consumption and production\n const surfaces = study.surfaces as Record<string, unknown>[] | undefined;\n if (!surfaces?.length) {\n outputError(new Error('No surfaces in study. Use: studies add surface'));\n return;\n }\n const consumptionData = study.consumption as Record<string, unknown> | undefined;\n if (!consumptionData) {\n outputError(new Error('No consumption in study. Use: studies set consumption'));\n return;\n }\n\n // Check all surfaces have production\n const surfacesWithoutProduction = surfaces.filter((s) => !s.production);\n if (surfacesWithoutProduction.length > 0) {\n outputError(new Error(`${surfacesWithoutProduction.length} surface(s) without production. Use: studies calculate production --all-surfaces`));\n return;\n }\n\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n\n // Build consumption PowerCurve\n const cd = consumptionData as any;\n const consumptionCurve = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || 'consumption', cd.parseDate ?? false);\n const totalConsumption = consumptionCurve.getTotalAcumulate();\n\n // Build base production (1 kWp) for each surface\n const baseProduction: Record<string, any> = {};\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const prodData = surface.production as any;\n const prodCurve = new PowerCurve(prodData.days || prodData, false, sid, false);\n const installedPower = (surface.installedPower as number) || 5000;\n // Normalize to 1kWp base\n baseProduction[sid] = prodCurve.applyMultiplier(1 / (installedPower / 1000));\n }\n\n // Determine mode: kit vs panel\n const useKits = opts.useKits || study.peakPowerIntroductionMode === 'solarKit';\n const solarClient = createServiceClient('solar', global);\n\n if (useKits) {\n // ── KIT MODE ──\n const phaseNumber = (study.phaseNumber as string) || 'single_phase';\n\n // Fetch all active kits\n const kitsRes = await solarClient.get('/solar-kits', { params: { limit: 500 } });\n let allKits = Array.isArray(kitsRes.data) && Array.isArray(kitsRes.data[0])\n ? kitsRes.data[0]\n : (Array.isArray(kitsRes.data) ? kitsRes.data : kitsRes.data?.data || []);\n\n // Filter by phase\n allKits = allKits.filter((k: any) => k.phaseNumber === phaseNumber && k.active !== false);\n\n // Check coplanar compatibility\n const isCoplanar = surfaces.every((s) => !(s.panelInclination as number));\n allKits = allKits.filter((k: any) =>\n isCoplanar === undefined ? true : isCoplanar === (k.coplanar === null ? true : k.coplanar)\n );\n\n // Sort by peak power ascending (smallest first)\n allKits.sort((a: any, b: any) =>\n (a.panelNumber * (a.kitSolarPanel?.peakPower || 0)) - (b.panelNumber * (b.kitSolarPanel?.peakPower || 0))\n );\n\n if (allKits.length === 0) {\n outputError(new Error('No compatible kits found for current phase/surface configuration'));\n return;\n }\n\n let selectedKit: any = null;\n let bestApproxKit: any = null;\n let bestApproxValue = -Infinity;\n let firstValidKit: any = null;\n const optimizationLog: Record<number, any> = {};\n\n for (const kit of allKits) {\n const kitPanel = kit.kitSolarPanel;\n if (!kitPanel) continue;\n\n // Distribute panels across surfaces\n let remainingPanels = kit.panelNumber || 0;\n const surfPanelCount: Record<string, number> = {};\n let fits = true;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n let maxPanels: number;\n\n if (area && kitPanel.width && kitPanel.heigth) {\n // Calculate max panels from area\n maxPanels = calculateMaxPanels(\n area,\n kitPanel,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n } else {\n // No area constraint — unlimited\n maxPanels = remainingPanels;\n }\n\n const assigned = Math.min(remainingPanels, maxPanels);\n surfPanelCount[sid] = assigned;\n remainingPanels -= assigned;\n }\n\n if (remainingPanels > 0) continue; // Kit doesn't fit\n\n if (!firstValidKit) firstValidKit = kit;\n\n // Calculate production for this kit\n let totalProd: any = null;\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const panelCount = surfPanelCount[sid] || 0;\n const surfPeakPower = (panelCount * kitPanel.peakPower) / 1000;\n const surfProd = baseProduction[sid].applyMultiplier(surfPeakPower);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const kitPeakPower = ((kit.panelNumber || 0) * kitPanel.peakPower) / 1000;\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criteria\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[kit.idSolarKit] = {\n identifier: kit.identifier,\n peakPower: kitPeakPower,\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n panelDistribution: surfPanelCount,\n };\n\n if (criterionValue > bestApproxValue) {\n bestApproxValue = criterionValue;\n bestApproxKit = kit;\n }\n\n if (criterionMet) {\n selectedKit = kit;\n break;\n }\n }\n\n if (!selectedKit) {\n selectedKit = bestApproxKit || firstValidKit;\n }\n\n const resultData: Record<string, unknown> = {\n mode: 'kit',\n evaluationMode,\n selectedKit: selectedKit ? {\n idSolarKit: selectedKit.idSolarKit,\n identifier: selectedKit.identifier,\n peakPower: ((selectedKit.panelNumber || 0) * (selectedKit.kitSolarPanel?.peakPower || 0)) / 1000,\n panelNumber: selectedKit.panelNumber,\n price: selectedKit.price,\n } : null,\n kitsEvaluated: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply && selectedKit) {\n updateStudy(filePath, (s) => {\n s.solarKit = selectedKit;\n s.peakPowerIntroductionMode = 'solarKit';\n s.solarPanel = undefined;\n s.solarInverters = undefined;\n s.peakPowerOptimizationMethod = evaluationMode;\n return undefined;\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n } else {\n // ── PANEL MODE ──\n const panel = study.solarPanel as Record<string, unknown> | undefined;\n if (!panel) {\n outputError(new Error('No solar panel set. Use: studies set panel --panel-id <id>'));\n return;\n }\n\n const panelPeakPower = (panel.peakPower as number) || 450;\n const panelWidth = (panel.width as number) || 1134;\n const panelHeight = (panel.heigth as number) || (panel.height as number) || 1762;\n const panelObj = { peakPower: panelPeakPower, width: panelWidth, heigth: panelHeight };\n\n // Calculate max peak power per surface\n const surfacesMaxPeakPower: Record<string, number> = {};\n let totalMaxPeakPower = 0;\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const area = surface.area as number | undefined;\n\n if (area && panelWidth && panelHeight) {\n const maxPanels = calculateMaxPanels(\n area,\n panelObj,\n (surface.availableAreaPercentage as number) || 85,\n (surface.panelInclination as number) || 0,\n (surface.inclination as number) || 0,\n (surface.panelPosition as string) || 'vertical',\n resolveSurfaceCoordinates(surface, study)?.lat ?? 37,\n );\n surfacesMaxPeakPower[sid] = (maxPanels * panelPeakPower) / 1000;\n } else {\n // No area constraint — use large value (500 kWp per surface)\n surfacesMaxPeakPower[sid] = 500;\n }\n totalMaxPeakPower += surfacesMaxPeakPower[sid];\n }\n\n // Determine iteration direction and initial value\n const isAscending = evaluationMode.energyPercentageSavings !== undefined\n || evaluationMode.economicPercentageSavings !== undefined\n || evaluationMode.rawConsumptionPercentage !== undefined;\n\n let peakPower = isAscending ? panelPeakPower / 1000 : totalMaxPeakPower;\n const optimizationLog: Record<number, any> = {};\n let resultPeakPower: Record<string, number> = {};\n let lastResult: number | undefined;\n const MAX_ITERATIONS = 200;\n const TOLERANCE = 0.005;\n let correctionFactor = 1;\n let itersSinceCorrection = 0;\n\n for (let iter = 0; iter < MAX_ITERATIONS && peakPower > 0 && peakPower <= totalMaxPeakPower; iter++) {\n peakPower = parseFloat(peakPower.toFixed(2));\n itersSinceCorrection++;\n\n if (itersSinceCorrection >= 20) {\n correctionFactor += 1.1;\n itersSinceCorrection = 0;\n }\n\n // Calculate change rate\n let changeRate: number;\n if (peakPower < 20) changeRate = (panelPeakPower / 1000) * correctionFactor;\n else if (peakPower < 500) changeRate = 5 * correctionFactor;\n else changeRate = 50 * correctionFactor;\n\n // Distribute peak power across surfaces\n let remaining = peakPower;\n let totalProd: any = null;\n resultPeakPower = {};\n\n for (const surface of surfaces) {\n const sid = surface.surfaceId as string;\n const surfPP = Math.min(remaining, surfacesMaxPeakPower[sid]);\n remaining -= surfPP;\n resultPeakPower[sid] = surfPP;\n const surfProd = baseProduction[sid].applyMultiplier(surfPP);\n totalProd = totalProd ? totalProd.aggregatePowerCurve(surfProd) : surfProd;\n }\n\n const netConsumption = consumptionCurve.aggregatePowerCurve(totalProd.applyMultiplier(-1));\n const totalProdKwh = totalProd.getTotalAcumulate();\n\n // Evaluate criterion\n let criterionValue: number;\n let criterionMet = false;\n\n if (evaluationMode.energyPercentageSavings !== undefined) {\n const netFiltered = netConsumption.filterNegativeValues().getTotalAcumulate();\n criterionValue = ((totalConsumption - netFiltered) / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.energyPercentageSavings;\n } else if (evaluationMode.rawConsumptionPercentage !== undefined) {\n criterionValue = (totalProdKwh / totalConsumption) * 100;\n criterionMet = criterionValue >= evaluationMode.rawConsumptionPercentage;\n } else if (evaluationMode.maxExcessesPercentage !== undefined) {\n const excessesCurve = netConsumption.filterPositiveValues();\n criterionValue = (excessesCurve.getTotalAcumulate() / totalProdKwh) * 100 * -1;\n criterionMet = criterionValue <= evaluationMode.maxExcessesPercentage;\n } else if (evaluationMode.maxNumberOfOverproductionMonths !== undefined) {\n const stats = netConsumption.calculateStatistics().statistics.anualMonthAccumulate;\n let byMonth = stats[Object.keys(stats).find((k) => k !== 'definition') || ''] || {};\n delete byMonth.yearly;\n criterionValue = Object.values(byMonth).filter((v: any) => v < 0).length;\n criterionMet = criterionValue <= evaluationMode.maxNumberOfOverproductionMonths;\n } else {\n criterionValue = 0;\n }\n\n optimizationLog[peakPower] = {\n totalProduction: totalProdKwh,\n criterionValue,\n criterionMet,\n surfacesPeakpower: { ...resultPeakPower },\n };\n\n if (criterionMet) break;\n\n // Tolerance check — stop if no meaningful progress\n if (isAscending && lastResult !== undefined && lastResult * (1 + TOLERANCE) >= criterionValue) {\n break;\n }\n lastResult = criterionValue;\n\n peakPower += isAscending ? changeRate : -changeRate;\n }\n\n // Compute final totals\n const totalOptimizedPeakPower = Object.values(resultPeakPower).reduce((a, b) => a + b, 0);\n const totalPanels = Math.round(totalOptimizedPeakPower / (panelPeakPower / 1000));\n\n const resultData: Record<string, unknown> = {\n mode: 'panel',\n evaluationMode,\n optimizedPeakPower: parseFloat(totalOptimizedPeakPower.toFixed(2)),\n estimatedPanels: totalPanels,\n surfacesPeakpower: resultPeakPower,\n iterations: Object.keys(optimizationLog).length,\n optimizationLog,\n };\n\n if (opts.apply) {\n updateStudy(filePath, (s) => {\n const surfs = s.surfaces as Record<string, unknown>[] | undefined;\n if (surfs) {\n for (const surf of surfs) {\n const sid = surf.surfaceId as string;\n if (resultPeakPower[sid] !== undefined) {\n const surfPanels = Math.round(resultPeakPower[sid] / (panelPeakPower / 1000));\n surf.panelNumber = surfPanels;\n surf.installedPower = resultPeakPower[sid] * 1000;\n }\n }\n }\n s.peakPowerOptimizationMethod = evaluationMode;\n return 'surfaces';\n });\n resultData.applied = true;\n }\n\n output(resultData, global);\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // ═══════════════════════════════════════════\n // COMMENTS\n // ═══════════════════════════════════════════\n\n // --- add comment (local study file) ---\n studies\n .command('add-comment')\n .description(\n 'Add a comment to the local study file.\\n' +\n 'Example: suntropy studies add-comment --file study.json --content \"Panel layout reviewed\"'\n )\n .option('--file <path>', 'Study file path')\n .requiredOption('--content <text>', 'Comment text')\n .action(async (opts) => {\n try {\n const result = updateStudy(resolveFile(opts), (study) => {\n const comments = (study.comments || []) as Record<string, unknown>[];\n comments.push(createComment('commented', opts.content));\n study.comments = comments;\n return undefined;\n });\n output(result, getGlobalOpts(studies));\n } catch (err) {\n outputError(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n // --- comment (API — add to existing study in backend) ---\n studies\n .command('comment <studyId>')\n .description(\n 'Add a comment to an existing study via API.\\n' +\n 'Example: suntropy studies comment abc123 --content \"Revisado por agente\"'\n )\n .requiredOption('--content <text>', 'Comment text')\n // Hidden flags for the \"Tag de Alexandria en comentarios\" workflow (sprint\n // Suntropy AI). They are intentionally omitted from --help / docs: the\n // Alexandria agent is instructed to use them in that specific workflow only.\n // - `--as-alexandria` signs the comment as Alexandria.\n // - `--reply-to-user`/`--reply-to-name` prepend a mention `@[name](userUID)`\n // with the markup the backend parses to notify that user.\n .addOption(new Option('--as-alexandria').hideHelp())\n .addOption(new Option('--reply-to-user <userUID>').hideHelp())\n .addOption(new Option('--reply-to-name <name>').hideHelp())\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const comment = createComment('commented', opts.content, {\n asAlexandria: Boolean(opts.asAlexandria),\n replyToUser: opts.replyToUser,\n replyToName: opts.replyToName,\n });\n const res = await client.post(`/solar-study/addSolarStudyComment/${studyId}`, comment);\n // The endpoint returns the FULL updated study (and an EMPTY body when the\n // study isn't found). Keep the guard so we never report a non-saved\n // comment as success, but DON'T dump the whole study: emit a compact\n // confirmation of the comment that was created.\n const saved = assertFound(res.data, 'Solar study', studyId) as {\n comments?: unknown[];\n };\n output(\n {\n success: true,\n message: `Comentario añadido al estudio ${studyId}`,\n studyId,\n commentsCount: Array.isArray(saved.comments)\n ? saved.comments.length\n : undefined,\n comment: {\n type: comment.type,\n creationUserUID: comment.creationUserUID,\n creationTimestamp: comment.creationTimestamp,\n aiGenerated: comment.aiGenerated ?? false,\n content: comment.content,\n },\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n\n// ─── Helpers ───\n\n/** Generate consumption curve from REE profile + period/monthly data using energy-types */\nasync function generateFromProfile(\n global: OutputOptions & Record<string, unknown>,\n tariff: string,\n market: string,\n year: number,\n mode: 'CONSUMPTION_BY_PERIOD' | 'MONTH_CONSUMPTION' | 'MONTHLY_BY_PERIOD',\n data: unknown,\n): Promise<unknown> {\n const profilesClient = createServiceClient('profiles', global);\n const periodsClient = createServiceClient('periods', global);\n\n // 1. Fetch REE profile\n const profileRes = await profilesClient.get('/ree-profiles', {\n params: {\n startDate: `${year}-01-01`,\n endDate: `${year}-12-31`,\n tariff,\n type: 'Final',\n market,\n },\n });\n const profile = profileRes.data?.profile || profileRes.data;\n if (!profile || !Array.isArray(profile) || profile.length === 0) {\n throw new Error('Failed to fetch REE profiles');\n }\n\n // 2. Import energy-types\n const { applyProfileToConsumption, ConsumptionIntroductionModes } =\n await import('energy-types/lib/energy/calculations/applyProfileToConsumption.js');\n\n if (mode === 'CONSUMPTION_BY_PERIOD') {\n // Need period distribution\n const tariffIdMap: Record<string, number> = { '2.0TD': 13, '3.0TD': 14, '6.1TD': 15 };\n const tariffId = tariffIdMap[tariff] || 14;\n const periodsRes = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: 1,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const periodDistribution = periodsRes.data;\n\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.CONSUMPTION_BY_PERIOD,\n profile,\n data,\n periodDistribution,\n );\n return result;\n\n } else if (mode === 'MONTH_CONSUMPTION') {\n // Transform flat {month: value} into {year: {month: value}} expected by energy-types\n const flatData = data as Record<string, number>;\n const yearMonthData: Record<number, Record<number, number>> = { [year]: {} };\n for (const [month, value] of Object.entries(flatData)) {\n yearMonthData[year][parseInt(month)] = value;\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n yearMonthData,\n );\n return result;\n\n } else if (mode === 'MONTHLY_BY_PERIOD') {\n // For monthly by period, we need to process month by month\n // This is more complex — for now, use the MONTH_CONSUMPTION as fallback\n // with aggregated monthly totals\n const monthlyData = data as Record<string, Record<string, number>>;\n const monthTotals: Record<string, number> = {};\n for (const [month, periods] of Object.entries(monthlyData)) {\n monthTotals[month] = Object.values(periods).reduce((a, b) => a + b, 0);\n }\n const result = applyProfileToConsumption(\n ConsumptionIntroductionModes.MONTH_CONSUMPTION,\n profile,\n monthTotals,\n );\n return result;\n }\n\n throw new Error(`Unknown consumption mode: ${mode}`);\n}\n\n/** Calculate max panels that fit in an area (replicates frontend calculateSolarPanelsInArea) */\nfunction calculateMaxPanels(\n areaM2: number,\n panel: { width: number; heigth: number; peakPower?: number },\n availablePercentage: number,\n panelInclination: number,\n surfaceInclination: number,\n panelPosition: string,\n latitude: number,\n): number {\n const { heigth, width } = panel;\n // Convert m² to mm² and apply available percentage\n let area = areaM2 * 1000000 * (availablePercentage / 100);\n const x = 1 / Math.atan(61 - (latitude - surfaceInclination));\n let totalPanelNumber: number;\n\n if (panelPosition === 'horizontal') {\n const h = width * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (heigth + 20) * (width + minimumDistance);\n totalPanelNumber = area / panelArea;\n } else {\n const h = heigth * Math.asin(panelInclination * (Math.PI / 180));\n const minimumDistance = x * h;\n const panelArea = (width + 20) * (heigth + minimumDistance);\n totalPanelNumber = area / panelArea;\n }\n\n return isNaN(totalPanelNumber) ? 0 : Math.floor(totalPanelNumber);\n}\n\n/** Collector for repeatable --asset <id:qty> */\nfunction collectAssets(value: string, previous: { id: number; quantity: number }[]): { id: number; quantity: number }[] {\n const [idStr, qtyStr] = value.split(':');\n const id = parseInt(idStr);\n const quantity = qtyStr ? parseInt(qtyStr) : 1;\n if (isNaN(id)) throw new Error(`Invalid asset format: \"${value}\". Use <id>:<quantity>`);\n return [...previous, { id, quantity }];\n}\n\n/** Fetch period distribution from periods service (needed for economic calculations) */\nasync function fetchPeriodDistribution(\n study: Study,\n global: OutputOptions & Record<string, unknown>,\n): Promise<unknown[] | null> {\n const atrTariff = study.atrTariff as Record<string, unknown> | undefined;\n const geoZone = study.geographicalZone as Record<string, unknown> | undefined;\n if (!atrTariff) return null;\n\n const tariffId = atrTariff.idTarifaATR as number;\n const zoneId = (geoZone?.idZona as number) || 1;\n const market = (study.market as string) || 'es';\n const year = new Date().getFullYear();\n\n try {\n const periodsClient = createServiceClient('periods', global);\n const res = await periodsClient.get('/periodos', {\n params: {\n idTarifa: tariffId,\n idZona: zoneId,\n fechaInicio: `${year}-01-01`,\n fechaFin: `${year}-12-31`,\n market,\n },\n });\n const data = res.data;\n if (Array.isArray(data) && data.length > 0) return data;\n return null;\n } catch {\n return null;\n }\n}\n\ninterface CreateCommentExtra {\n /** Sign the comment as Alexandria (AI assistant) instead of the active user. */\n asAlexandria?: boolean;\n /** userUID to mention at the start of the comment so the backend notifies them. */\n replyToUser?: string;\n /** Display name for the mentioned user (defaults to the userUID). */\n replyToName?: string;\n}\n\n/** Create a study comment (replicates frontend createNewComment) */\nfunction createComment(\n type: string,\n content?: string,\n extra?: CreateCommentExtra\n): Record<string, unknown> {\n const config = loadConfig();\n const profile = getActiveProfile(config);\n const autoContent: Record<string, string> = {\n created: 'Estudio creado via CLI',\n modified: 'Estudio actualizado via CLI',\n };\n\n let body = content || autoContent[type] || '';\n // Prepend a mention so the backend parses it and notifies the user. The\n // markup must match react-mentions / the backend regex: @[name](userUID).\n if (extra?.replyToUser) {\n const name = extra.replyToName || extra.replyToUser;\n body = `@[${name}](${extra.replyToUser}) ${body}`.trim();\n }\n\n const comment: Record<string, unknown> = {\n content: body,\n type,\n creationTimestamp: new Date().toISOString(),\n creationUserUID: extra?.asAlexandria\n ? 'alexandria'\n : profile.userUID || 'cli-agent',\n };\n // Mark AI-authored comments so the frontend renders them as Alexandria.\n if (extra?.asAlexandria) {\n comment.aiGenerated = true;\n }\n return comment;\n}\n","import crypto from 'crypto';\nconst rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate\n\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n crypto.randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n\n return rnds8Pool.slice(poolPtr, poolPtr += 16);\n}","export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;","import REGEX from './regex.js';\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && REGEX.test(uuid);\n}\n\nexport default validate;","import validate from './validate.js';\n/**\n * Convert array of 16 byte values to UUID string format of the form:\n * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n */\n\nconst byteToHex = [];\n\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).substr(1));\n}\n\nfunction stringify(arr, offset = 0) {\n // Note: Be careful editing this code! It's been tuned for performance\n // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434\n const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one\n // of the following:\n // - One or more input array values don't map to a hex octet (leading to\n // \"undefined\" in the uuid)\n // - Invalid input values for the RFC `version` or `variant` fields\n\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n\n return uuid;\n}\n\nexport default stringify;","import rng from './rng.js';\nimport stringify from './stringify.js';\n\nfunction v4(options, buf, offset) {\n options = options || {};\n const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`\n\n rnds[6] = rnds[6] & 0x0f | 0x40;\n rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided\n\n if (buf) {\n offset = offset || 0;\n\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n\n return buf;\n }\n\n return stringify(rnds);\n}\n\nexport default v4;","import { Command } from 'commander';\nimport { createServiceClient, handleApiError, assertFound, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, outputPaginated, type OutputOptions } from '../../output.js';\nimport { registerStudyBuilderCommands } from './builder.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Replace PowerCurve objects with lightweight summaries to save tokens */\nfunction compactCurves(obj: unknown): unknown {\n if (obj === null || obj === undefined || typeof obj !== 'object') return obj;\n if (Array.isArray(obj)) return obj.map(compactCurves);\n\n const record = obj as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects containing 'valuesList'\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n // Detect inline DayCurve arrays (consumption, production fields that are PowerCurve-like)\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactCurves(val);\n }\n return result;\n}\n\n/** Expand sections: pick which parts of study to include */\nconst EXPAND_SECTIONS: Record<string, string[]> = {\n surfaces: ['surfaces'],\n results: ['results'],\n economics: ['economicResults'],\n batteries: ['activeBatteries', 'batteriesConfiguration', 'batteriesEnergyBalance', 'batteriesResults', 'bateries'],\n consumption: ['consumption', 'consumptionIntroductionMode', 'monthConsumptionDictionary', 'monthPeriodConsumptionDictionary', 'periodConsumptionDictionary'],\n equipment: ['solarPanel', 'solarKit', 'solarInverters', 'selectedChargers', 'selectedCustomAssets'],\n client: ['clientDetails', 'clientsDetails'],\n location: ['location', 'mapCenter', 'geographicalZone', 'atrTariff'],\n};\n\n/**\n * Fields that users often ask for on the study but actually live on the\n * metadata entity (MySQL) — surfaced via `studies list` or `studies metadata`.\n */\nconst METADATA_ONLY_FIELDS: Record<string, string> = {\n peakPower: 'metadata',\n sellingPrice: 'metadata',\n totalCost: 'metadata',\n anualProduction: 'metadata',\n anualConsumption: 'metadata',\n currentState: 'metadata',\n clientName: 'metadata',\n idSolarStudyMetadata: 'metadata',\n solarStudyId: 'metadata',\n};\n\n/**\n * Fields that don't exist on either the study document or its metadata —\n * they are computed client-side (builder) or simply don't exist in this API.\n */\nconst COMPUTED_OR_UNKNOWN_FIELDS: Record<string, string> = {\n completionPercentage: 'computed by `studies validate` / `studies save` from stepsProgress',\n isCompleted: 'not a persisted field; derive from solarStudyProgress or completionPercentage',\n stepsProgress: 'computed by `studies validate` / `studies save`',\n};\n\nfunction explainMissingStudyFields(missing: string[], studyId: string): void {\n const metadataFields = missing.filter(f => f in METADATA_ONLY_FIELDS);\n const computedFields = missing.filter(f => f in COMPUTED_OR_UNKNOWN_FIELDS);\n const unknownFields = missing.filter(f => !(f in METADATA_ONLY_FIELDS) && !(f in COMPUTED_OR_UNKNOWN_FIELDS));\n\n const lines: string[] = [];\n lines.push(`warning: ${missing.length} requested field(s) are not present on the study document returned by findById.`);\n\n if (metadataFields.length > 0) {\n lines.push('');\n lines.push(` These fields live on the STUDY METADATA (MySQL), not on the study document:`);\n for (const f of metadataFields) lines.push(` - ${f}`);\n lines.push(` Use: suntropy studies metadata ${studyId} --by-study-id --fields ${metadataFields.join(',')}`);\n lines.push(` Or: suntropy studies list --client-name <name> (list already projects these fields)`);\n }\n\n if (computedFields.length > 0) {\n lines.push('');\n lines.push(` These fields are not persisted on the study:`);\n for (const f of computedFields) lines.push(` - ${f}: ${COMPUTED_OR_UNKNOWN_FIELDS[f]}`);\n lines.push(` Use: suntropy studies validate ${studyId} (returns stepsProgress + completionPercentage)`);\n }\n\n if (unknownFields.length > 0) {\n lines.push('');\n lines.push(` These fields were not found on the study document:`);\n for (const f of unknownFields) lines.push(` - ${f}`);\n lines.push(` If you expected them, try: suntropy studies get ${studyId} --expand all --format json`);\n lines.push(` and inspect the full payload to locate the correct field path.`);\n }\n\n process.stderr.write(lines.join('\\n') + '\\n');\n}\n\n/** Core identity fields always included in get */\nconst CORE_FIELDS = [\n '_id', 'id', 'name', 'identifier', 'clientUID',\n 'creationTimestamp', 'lastEditTimestamp',\n 'assignedUserUID', 'creationUserUID',\n 'selectedSolarStudyMode', 'solarStudyProgress',\n 'market', 'layout',\n 'peakPowerIntroductionMode', 'instalationPhaseNumber',\n];\n\nfunction filterStudy(study: Record<string, unknown>, expand?: string): Record<string, unknown> {\n if (expand === 'all') return study;\n\n const sections = expand ? expand.split(',').map(s => s.trim()) : [];\n const allowedFields = new Set(CORE_FIELDS);\n\n for (const section of sections) {\n const fields = EXPAND_SECTIONS[section];\n if (fields) fields.forEach(f => allowedFields.add(f));\n }\n\n // If no expand, include summary numeric fields\n if (sections.length === 0) {\n ['peakPowerIntroductionMode', 'instalationPhaseNumber', 'location', 'atrTariff'].forEach(f => allowedFields.add(f));\n }\n\n const result: Record<string, unknown> = {};\n for (const key of allowedFields) {\n if (key in study) result[key] = study[key];\n }\n\n return compactCurves(result) as Record<string, unknown>;\n}\n\nexport function registerStudiesCommands(program: Command): void {\n const studies = program.command('studies').description(\n 'Explore and manage solar studies. Progressive exploration: list → metadata → get → get --expand → curves'\n );\n\n // --- list ---\n studies\n .command('list')\n .description('List solar studies metadata. Fields: idSolarStudyMetadata, solarStudyId, clientName, peakPower, currentState, creationTimestamp')\n .option('--limit <n>', 'Max results', '20')\n .option('--offset <n>', 'Skip results', '0')\n .option('--state <state>', 'Filter by state name')\n .option('--client-name <name>', 'Filter by client name')\n .option('--from <date>', 'Filter from date (YYYY-MM-DD)')\n .option('--to <date>', 'Filter to date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body: Record<string, unknown> = {\n limit: parseInt(opts.limit),\n offset: parseInt(opts.offset),\n };\n if (opts.state) body.state = opts.state;\n if (opts.clientName) body.clientName = opts.clientName;\n if (opts.from) body.fromDate = opts.from;\n if (opts.to) body.toDate = opts.to;\n\n const res = await client.post('/solar-study/findWithPaginationAndFilters', body);\n // Response: [items[], totalCount, ...] tuple or {data, total}\n let data: unknown[];\n let total: number;\n if (Array.isArray(res.data) && res.data.length >= 2 && Array.isArray(res.data[0]) && typeof res.data[1] === 'number') {\n data = res.data[0];\n total = res.data[1];\n } else if (Array.isArray(res.data)) {\n data = res.data;\n total = res.data.length;\n } else {\n data = res.data?.data || res.data?.solarStudiesMetadata || [];\n total = res.data?.total ?? res.data?.count ?? (Array.isArray(data) ? data.length : 0);\n }\n\n const outOpts: OutputOptions = { ...global };\n if (!global.fields) {\n outOpts.fields = 'idSolarStudyMetadata,solarStudyId,clientName,peakPower,anualProduction,anualConsumption,totalCost,sellingPrice,currentState,creationTimestamp';\n }\n outputPaginated(data, total, parseInt(opts.limit), parseInt(opts.offset), outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- metadata ---\n studies\n .command('metadata <id>')\n .description('Get solar study metadata by metadata ID (relational). Full MySQL record with state, costs, versions.')\n .option('--by-study-id', 'Interpret <id> as MongoDB solarStudyId instead of metadata ID')\n .action(async (id, opts) => {\n try {\n // --by-study-id resolves against the MongoDB solarStudyId, so guard it\n // the same way as `get`; the default path uses a numeric metadata id.\n if (opts.byStudyId) assertStudyObjectId(id);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const path = opts.byStudyId\n ? `/solar-study/metadata/solar-study-id/${id}`\n : `/solar-study/findSolarStudyMetadataById/${id}`;\n const res = await client.get(path);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- get ---\n studies\n .command('get <studyId>')\n .description(\n 'Get solar study by MongoDB ID. By default returns summary (no heavy curves).\\n' +\n 'Expand sections: surfaces, results, economics, batteries, consumption, equipment, client, location\\n' +\n 'Examples:\\n' +\n ' suntropy studies get abc123\\n' +\n ' suntropy studies get abc123 --expand surfaces,results\\n' +\n ' suntropy studies get abc123 --expand all\\n' +\n ' suntropy studies get abc123 --fields name,market (bypasses expand filter)'\n )\n .option('--expand <sections>', 'Comma-separated sections to expand (or \"all\")')\n .action(async (studyId, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n // If the user passes --fields, they have already expressed exactly what\n // they want — don't pre-filter the study, let output() select from the\n // full object. Otherwise apply the expand-based summary filter.\n const filtered = global.fields ? study : filterStudy(study, opts.expand);\n\n if (global.fields) {\n const requested = global.fields.split(',').map(f => f.trim());\n const topLevel = requested.map(f => f.split('.')[0]);\n const missing = topLevel.filter(f => !(f in study));\n if (missing.length > 0) {\n explainMissingStudyFields(missing, studyId);\n }\n }\n\n output(filtered, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- curves ---\n studies\n .command('curves <studyId> <curveName>')\n .description(\n 'Extract and analyze a PowerCurve from a study.\\n' +\n 'Curve names: consumption, production, net-consumption, excesses\\n' +\n 'Default: --stats. Use --raw for full hourly data (8760 values).\\n' +\n 'Use --monthly for monthly aggregates, --daily for daily totals.'\n )\n .option('--stats', 'Show statistics (default if no other flag)')\n .option('--monthly', 'Monthly accumulated values')\n .option('--daily', 'Daily accumulated values')\n .option('--raw', 'Full hourly DayCurve[] data')\n .option('--total', 'Just the total accumulated value')\n .option('--surface-index <n>', 'Surface index for production curve', '0')\n .option('--save <file>', 'Save curve data to file')\n .action(async (studyId, curveName, opts) => {\n try {\n assertStudyObjectId(studyId);\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/findById/${studyId}`);\n const study = assertFound(res.data, 'Solar study', studyId) as Record<string, unknown>;\n\n // Extract the requested curve\n let curveData: unknown;\n switch (curveName) {\n case 'consumption':\n curveData = study.consumption;\n break;\n case 'production': {\n const surfaces = study.surfaces as any[];\n const idx = parseInt(opts.surfaceIndex);\n if (surfaces && surfaces[idx]?.production) {\n curveData = surfaces[idx].production;\n } else {\n outputError(new Error(`No production curve at surface index ${idx}. Study has ${surfaces?.length || 0} surfaces.`));\n return;\n }\n break;\n }\n case 'net-consumption':\n curveData = (study.results as any)?.netConsumption;\n break;\n case 'excesses':\n curveData = (study.results as any)?.excessesCurve;\n break;\n default:\n outputError(new Error(`Unknown curve: ${curveName}. Available: consumption, production, net-consumption, excesses`));\n return;\n }\n\n if (!curveData) {\n outputError(new Error(`Curve \"${curveName}\" not found or empty in this study.`));\n return;\n }\n\n // Import PowerCurve from energy-types\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n const cd = curveData as any;\n const pc = new PowerCurve(cd.days || cd, cd.ignore0 ?? false, cd.identifier || curveName, cd.parseDate ?? false);\n\n // Determine output mode\n const showRaw = opts.raw;\n const showMonthly = opts.monthly;\n const showDaily = opts.daily;\n const showTotal = opts.total;\n const showStats = opts.stats || (!showRaw && !showMonthly && !showDaily && !showTotal);\n\n let result: unknown;\n\n if (showRaw) {\n result = pc.days;\n } else if (showTotal) {\n result = { total: pc.getTotalAcumulate(), identifier: curveName, days: pc.days.length };\n } else if (showStats) {\n const raw = pc.calculateStatistics();\n result = raw.statistics || raw;\n } else if (showMonthly) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { anualMonthAccumulate: s.anualMonthAccumulate, anualMonthCount: s.anualMonthCount, anualMonthlyAverage: s.anualMonthlyAverage };\n } else if (showDaily) {\n const raw = pc.calculateStatistics();\n const s = raw.statistics || raw;\n result = { dailyAccumulate: s.dailyAccumulate };\n }\n\n const outOpts = { ...global, save: opts.save || global.save };\n output(result, outOpts);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate-production ---\n studies\n .command('calculate-production')\n .description('Calculate solar production curve for given coordinates and configuration')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .requiredOption('--power <w>', 'Installed power in Watts')\n .option('--angle <n>', 'Panel inclination degrees', '30')\n .option('--azimuth <n>', 'Panel orientation degrees (0=north, 180=south)', '180')\n .option('--losses <n>', 'Losses percentage', '14')\n .option('--year <n>', 'Year for calculation', String(new Date().getFullYear()))\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const body = {\n lat: parseFloat(opts.lat),\n long: parseFloat(opts.lon),\n instaledPower: parseFloat(opts.power),\n angle: parseFloat(opts.angle),\n azimuth: parseFloat(opts.azimuth),\n lossesPercentage: parseFloat(opts.losses),\n year: parseInt(opts.year),\n isOptimized: false,\n };\n const res = await client.post('/solar-study/calculateProduction', body);\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- optimize-surfaces ---\n studies\n .command('optimize-surfaces')\n .description('Calculate optimal panel angle and azimuth for coordinates')\n .requiredOption('--lat <n>', 'Latitude')\n .requiredOption('--lon <n>', 'Longitude')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(studies);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/optimizeSurfaces', {\n params: { lat: parseFloat(opts.lat), lon: parseFloat(opts.lon) },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // Register study builder commands (init, validate, save, pull, set, add, remove, calculate)\n registerStudyBuilderCommands(studies);\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read curve data from file, stdin, or --input flag */\nasync function readCurveInput(inputPath?: string): Promise<any> {\n let raw: string;\n if (inputPath && inputPath !== '-') {\n raw = readFileSync(inputPath, 'utf-8');\n } else {\n raw = await readStdin();\n }\n return JSON.parse(raw);\n}\n\n/** Build a PowerCurve from parsed JSON data */\nasync function buildCurve(data: any, identifier = 'curve') {\n const { PowerCurve } = await import('energy-types/lib/energy/classes/powerCurve.class.js');\n // Data might be: { days: [...], identifier } or just a DayCurve[]\n if (Array.isArray(data)) {\n return new PowerCurve(data, false, identifier, false);\n }\n return new PowerCurve(data.days || data, data.ignore0 ?? false, data.identifier || identifier, data.parseDate ?? false);\n}\n\n/** Serialize PowerCurve back to JSON-friendly format */\nfunction serializeCurve(pc: any): any {\n return { days: pc.days, identifier: pc.identifier, ignore0: pc.ignore0 };\n}\n\nexport function registerCurvesCommands(program: Command): void {\n const curves = program.command('curves').description(\n 'PowerCurve operations (pipe-friendly). Accept input via --input <file> or stdin.\\n' +\n 'Curve-returning commands output serialized PowerCurve JSON for chaining.\\n' +\n 'Use --save <file> to persist and still output to stdout.'\n );\n\n // --- stats ---\n curves\n .command('stats')\n .description('Calculate comprehensive statistics: monthly/daily/hourly averages, max, min, period aggregation')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'stats');\n const raw = pc.calculateStatistics();\n output(raw.statistics || raw, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- total ---\n curves\n .command('total')\n .description('Calculate total accumulated value across all hours')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'total');\n output({ total: pc.getTotalAcumulate(), days: pc.days.length }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- multiply ---\n curves\n .command('multiply <factor>')\n .description('Multiply all hourly values by a factor. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (factor, opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'multiplied');\n const result = pc.applyMultiplier(parseFloat(factor));\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- aggregate ---\n curves\n .command('aggregate')\n .description('Sum two PowerCurves (A + B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file')\n .requiredOption('--b <file>', 'Second curve file')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const result = pcA.aggregatePowerCurve(pcB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- subtract ---\n curves\n .command('subtract')\n .description('Subtract two PowerCurves (A - B). Returns a new PowerCurve.')\n .requiredOption('--a <file>', 'First curve file (minuend)')\n .requiredOption('--b <file>', 'Second curve file (subtrahend)')\n .action(async (opts) => {\n try {\n const dataA = JSON.parse(readFileSync(opts.a, 'utf-8'));\n const dataB = JSON.parse(readFileSync(opts.b, 'utf-8'));\n const pcA = await buildCurve(dataA, 'a');\n const pcB = await buildCurve(dataB, 'b');\n const negB = pcB.applyMultiplier(-1);\n const result = pcA.aggregatePowerCurve(negB);\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-positive ---\n curves\n .command('filter-positive')\n .description('Keep only non-negative hourly values (zero out negatives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'positive');\n const result = pc.filterNegativeValues(); // filterNegativeValues returns curve with negatives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-negative ---\n curves\n .command('filter-negative')\n .description('Keep only non-positive hourly values (zero out positives). Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'negative');\n const result = pc.filterPositiveValues(); // filterPositiveValues returns curve with positives zeroed\n output(serializeCurve(result), getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- sort ---\n curves\n .command('sort')\n .description('Sort curve days by date ascending. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'sorted');\n const sortedDays = pc.sortByDate();\n output({ days: sortedDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- filter-dates ---\n curves\n .command('filter-dates')\n .description('Filter curve to a date range. Returns a new PowerCurve.')\n .option('--input <file>', 'Input file (or - for stdin)')\n .option('--start <date>', 'Start date (YYYY-MM-DD)')\n .option('--end <date>', 'End date (YYYY-MM-DD)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'filtered');\n const start = opts.start ? new Date(opts.start) : undefined;\n const end = opts.end ? new Date(opts.end) : undefined;\n const filteredDays = pc.filterByDates(start, end);\n output({ days: filteredDays, identifier: pc.identifier, ignore0: pc.ignore0 }, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- to-serie ---\n curves\n .command('to-serie')\n .description('Convert curve to chart-ready series format (x/y arrays)')\n .option('--input <file>', 'Input file (or - for stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'serie');\n const serie = pc.convertoToSerie();\n output(serie, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n\n // --- by-period ---\n curves\n .command('by-period')\n .description(\n 'Aggregate a PowerCurve by tariff periods (P1-P6) using a period distribution.\\n' +\n 'Returns { p1, p2, p3, p4, p5, p6 } with accumulated kWh per period.\\n\\n' +\n 'The period distribution maps each hour of each day to a tariff period.\\n' +\n 'Get it with: suntropy consumption periods --save /tmp/periods.json\\n\\n' +\n 'Examples:\\n' +\n ' suntropy curves by-period --input /tmp/production.json --periods /tmp/periods.json\\n' +\n ' suntropy curves by-period --input /tmp/consumption.json --periods /tmp/periods.json'\n )\n .requiredOption('--periods <file>', 'Period distribution file (DayCurve[] from consumption periods)')\n .option('--input <file>', 'Input PowerCurve file (or stdin)')\n .action(async (opts) => {\n try {\n const data = await readCurveInput(opts.input);\n const pc = await buildCurve(data, 'by-period');\n const periodsData = JSON.parse(readFileSync(opts.periods, 'utf-8'));\n const result = pc.aggregateByPeriod(periodsData);\n output(result, getGlobalOpts(curves));\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerConsumptionCommands(program: Command): void {\n const consumption = program.command('consumption').description(\n 'Generate consumption curves using the profiles service.\\n' +\n 'Supports multiple estimation methods: standard patterns, custom profiles, monthly data.\\n' +\n 'Returns PowerCurve JSON compatible with `suntropy curves` for further processing.'\n );\n\n // --- estimate ---\n consumption\n .command('estimate')\n .description(\n 'Generate a consumption PowerCurve from patterns and annual consumption.\\n' +\n 'Patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Examples:\\n' +\n ' suntropy consumption estimate --annual 5000 --pattern Balance\\n' +\n ' suntropy consumption estimate --annual 8000 --pattern Domestic --tariff 3.0TD --market es\\n' +\n ' suntropy consumption estimate --annual 3500 --monthly-data \\'{\"1\":300,\"2\":280,...}\\'\\n' +\n ' suntropy consumption estimate --annual 5000 --custom-profile-id abc123'\n )\n .requiredOption('--annual <kWh>', 'Annual consumption in kWh')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial')\n .option('--start-date <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end-date <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--tariff <code>', 'Electricity tariff code (e.g. 3.0TD)', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market: es, pt, it', 'es')\n .option('--custom-profile-id <id>', 'Use a custom consumption profile by ID')\n .option('--monthly-data <json>', 'Monthly consumption JSON: {\"1\":val,\"2\":val,...,\"12\":val}')\n .option('--daily-curve <json>', 'Custom daily curve JSON (DayCurve format)')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n const year = new Date().getFullYear();\n const startDate = opts.startDate || `${year}-01-01`;\n const endDate = opts.endDate || `${year}-12-31`;\n\n // Build query params\n const params: Record<string, string> = {\n startDate,\n endDate,\n tariff: opts.tariff,\n type: opts.type,\n anualConsumption: opts.annual,\n market: opts.market,\n };\n\n if (opts.pattern) params.consumptionType = opts.pattern;\n if (opts.customProfileId) params.customProfileId = opts.customProfileId;\n\n // Build optional body\n let body: Record<string, unknown> | undefined;\n if (opts.monthlyData || opts.dailyCurve) {\n body = {};\n if (opts.monthlyData) body.consumptionByMonth = JSON.parse(opts.monthlyData);\n if (opts.dailyCurve) body.dailyCurve = JSON.parse(opts.dailyCurve);\n }\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const res = await client.post(`/consumption-estimation?${queryString}`, body || {});\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ree-profiles ---\n consumption\n .command('ree-profiles')\n .description(\n 'Fetch REE (Red Eléctrica) hourly profiles for a date range and tariff.\\n' +\n 'Returns the raw profile data used as basis for consumption estimation.\\n' +\n 'Example: suntropy consumption ree-profiles --start 2024-01-01 --end 2024-12-31 --tariff 3.0TD'\n )\n .requiredOption('--start <YYYY-MM-DD>', 'Start date')\n .requiredOption('--end <YYYY-MM-DD>', 'End date')\n .option('--tariff <code>', 'Tariff code', '3.0TD')\n .option('--type <type>', 'Profile type: Initial or Final', 'Final')\n .option('--market <code>', 'Market code: es, pt, it', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/ree-profiles', {\n params: {\n startDate: opts.start,\n endDate: opts.end,\n tariff: opts.tariff,\n type: opts.type,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-tags ---\n consumption\n .command('custom-tags')\n .description('List available custom consumption profile tags for the authenticated client')\n .action(async () => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getTags');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- custom-profile-info ---\n consumption\n .command('custom-profile-info')\n .description('Get details of a custom consumption profile by ID')\n .requiredOption('--id <profileId>', 'Custom profile ID')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n const res = await client.get('/custom-profiles/getInfo', {\n params: { id: opts.id },\n });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- periods ---\n consumption\n .command('periods')\n .description(\n 'Fetch period distribution (hour→P1-P6 mapping) from the periods service.\\n' +\n 'Returns DayCurve[] where each hour\\'s value is the period number (1-6).\\n' +\n 'Use with `suntropy curves by-period` to aggregate any curve by tariff period.\\n\\n' +\n 'Common tariff IDs (Spain): 13=2.0TD, 14=3.0TD\\n' +\n 'Zone IDs (Spain): 1=Peninsula, 2=Canarias, 3=Baleares\\n\\n' +\n 'Examples:\\n' +\n ' suntropy consumption periods --tariff-id 14 --zone-id 1 --save /tmp/periods.json\\n' +\n ' suntropy consumption periods --tariff-id 13 --start 2025-01-01 --end 2025-12-31'\n )\n .option('--tariff-id <n>', 'ATR tariff ID (13=2.0TD, 14=3.0TD)', '14')\n .option('--zone-id <n>', 'Geographical zone ID (1=Peninsula)', '1')\n .option('--start <YYYY-MM-DD>', 'Start date (default: Jan 1 current year)')\n .option('--end <YYYY-MM-DD>', 'End date (default: Dec 31 current year)')\n .option('--market <code>', 'Market: es, pt, it, fr', 'es')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('periods', global);\n const year = new Date().getFullYear();\n const res = await client.get('/periodos', {\n params: {\n idTarifa: parseInt(opts.tariffId),\n idZona: parseInt(opts.zoneId),\n fechaInicio: opts.start || `${year}-01-01`,\n fechaFin: opts.end || `${year}-12-31`,\n market: opts.market,\n },\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- from-file ---\n consumption\n .command('from-file')\n .description(\n 'Generate consumption curve from an uploaded file.\\n' +\n 'Supported formats: Portuguese EREDES ZIP files.\\n' +\n 'Example: suntropy consumption from-file --eredes-zip /path/to/file.zip'\n )\n .option('--eredes-zip <path>', 'Path to Portuguese EREDES ZIP file')\n .option('--save <file>', 'Save result to file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(consumption);\n const client = createServiceClient('profiles', global);\n\n if (opts.eredesZip) {\n const FormData = (await import('form-data')).default;\n const form = new FormData();\n form.append('file', readFileSync(opts.eredesZip), {\n filename: opts.eredesZip.split('/').pop(),\n contentType: 'application/zip',\n });\n const res = await client.post('/consumption-files-processor/portugal/eredes-zip', form, {\n headers: form.getHeaders(),\n });\n output(res.data, { ...global, save: opts.save || global.save });\n } else {\n outputError(new Error('Specify a file format: --eredes-zip <path>'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Unwrap PublicApiResponse: { code, data, error } → data or throw */\nfunction unwrapPublicApiResponse(resData: unknown): unknown {\n if (resData && typeof resData === 'object' && !Array.isArray(resData)) {\n const r = resData as Record<string, unknown>;\n // Detect PublicApiResponse shape: has 'code' field (number)\n if ('code' in r && typeof r.code === 'number') {\n // Prefer data if present (API may return both error and data)\n if (r.data !== undefined) return r.data;\n // No data — check for error\n if (r.error) {\n const err = r.error as Record<string, unknown>;\n throw new Error(`API error (${err.code || r.code}): ${err.message || JSON.stringify(err)}`);\n }\n // code present but no data and no error — return as-is\n return resData;\n }\n }\n return resData;\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerSolarformCommands(program: Command): void {\n const solarform = program.command('solarform').description(\n 'Create solar studies via the Solar Form API.\\n' +\n 'Two modes: \"simple\" (minimal params, auto-optimized) and \"calculate\" (full control).\\n' +\n 'Use --save flag to persist the study to the database.'\n );\n\n // --- simple ---\n solarform\n .command('simple')\n .description(\n 'Create a solar study with minimal parameters (simplified mode).\\n' +\n 'Automatically resolves location from region/subregion, applies consumption patterns,\\n' +\n 'and optimizes kit selection.\\n\\n' +\n 'Consumption patterns: Balance, Nightly, Morning, Afternoon, Domestic, Commercial\\n' +\n 'Consumption mode: monthlyConsumption (kWh) or monthlySpending (EUR)\\n' +\n 'Excesses modes: PPA, gridSelling, noInjection, virtualBattery\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform simple --region \"Andalucía\" --sub-region \"Sevilla\" --consumption 5000\\n' +\n ' suntropy solarform simple --region \"Cataluña\" --sub-region \"Barcelona\" --consumption 300 --consumption-mode monthlySpending --save\\n' +\n ' suntropy solarform simple --region \"Madrid\" --sub-region \"Madrid\" --consumption 8000 --pattern Domestic --kit-id abc123 --save'\n )\n .requiredOption('--region <name>', 'Region name (must exist in database)')\n .requiredOption('--sub-region <name>', 'Sub-region name')\n .requiredOption('--consumption <value>', 'Consumption value (kWh or EUR depending on --consumption-mode)')\n .option('--pattern <name>', 'Consumption pattern: Balance, Nightly, Morning, Afternoon, Domestic, Commercial', 'Balance')\n .option('--consumption-mode <mode>', 'monthlyConsumption (kWh) or monthlySpending (EUR)', 'monthlyConsumption')\n .option('--kit-id <id>', 'Use a specific solar kit instead of auto-optimization')\n .option('--excesses-mode <mode>', 'Excesses compensation: PPA, gridSelling, noInjection, virtualBattery')\n .option('--assigned-user <uid>', 'Assign study to a user UID')\n .option('--email <email>', 'Send results to this email')\n .option('--save', 'Save study to database')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body: Record<string, unknown> = {\n region: opts.region,\n subRegion: opts.subRegion,\n selectedConsumptionPattern: opts.pattern,\n consumptionQuantity: parseFloat(opts.consumption),\n consumptionQuantityIntroductionMode: opts.consumptionMode,\n };\n\n if (opts.assignedUser) body.assignedUserUID = opts.assignedUser;\n\n // Build query params\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n if (opts.kitId) params.solarKitId = opts.kitId;\n if (opts.excessesMode) params.excessesCompensationMode = opts.excessesMode;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form/simple${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- calculate ---\n solarform\n .command('calculate')\n .description(\n 'Create a solar study with full control over all parameters.\\n' +\n 'Pass the complete SimplifiedSolarStudy body as JSON.\\n\\n' +\n 'Required body fields:\\n' +\n ' center: { lat, lng } — Installation coordinates\\n' +\n ' surfaces: [{ path, inclination, orientation }] — Panel surfaces\\n' +\n ' consumptionMode: \"cups\" | \"consumptionPatterns\"\\n' +\n ' clientDetails: { name, email, phone }\\n\\n' +\n 'Optional: atrTariff, geographicalZone, location, contractedPower,\\n' +\n ' monthPeriodConsumptionDictionary, selectedConsumptionPattern,\\n' +\n ' consumptionQuantity, consumptionQuantityIntroductionMode\\n\\n' +\n 'Examples:\\n' +\n ' suntropy solarform calculate --data \\'{\"center\":{\"lat\":37.39,\"lng\":-5.99},...}\\' --save\\n' +\n ' cat study-input.json | suntropy solarform calculate --data - --save --email client@co.com'\n )\n .requiredOption('--data <json>', 'Full SimplifiedSolarStudy JSON body (or - for stdin)')\n .option('--save', 'Save study to database')\n .option('--email <email>', 'Send results to this email')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n const body = await parseData(opts.data);\n if (!body) {\n outputError(new Error('--data is required. Pass JSON or - for stdin.'));\n return;\n }\n\n const params: Record<string, string> = {};\n if (opts.save) params.save = 'true';\n if (opts.email) params.email = opts.email;\n\n const queryString = Object.entries(params)\n .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)\n .join('&');\n\n const url = `/api/solar-form${queryString ? '?' + queryString : ''}`;\n const res = await client.post(url, body);\n\n const study = unwrapPublicApiResponse(res.data);\n if (!study || (typeof study === 'object' && !Array.isArray(study) && !('selectedSolarStudyMode' in (study as Record<string, unknown>)))) {\n outputError(new Error('API returned no study data. The /api/solar-form endpoint requires a complete body with: center, surfaces, consumptionMode, and typically locationMode. Use \"solarform simple\" for minimal-parameter study creation.'));\n return;\n }\n const result = opts.raw ? study : compactStudyOutput(study);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- config ---\n solarform\n .command('config')\n .description(\n 'Get the solar form configuration for the authenticated client.\\n' +\n 'Returns form settings, appearance, enabled steps, custom fields, etc.'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-form/solar-form-config');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- statistics ---\n solarform\n .command('statistics')\n .description(\n 'List or create solar form submission statistics.\\n' +\n 'Used for tracking form analytics and conversion data.'\n )\n .option('--create', 'Create a new statistics entry')\n .option('--update', 'Update an existing statistics entry')\n .option('--data <json>', 'Statistics data as JSON')\n .option('--stats-id <id>', 'Statistics ID (for update or linking)')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(solarform);\n const client = createServiceClient('solar', global);\n\n if (opts.update) {\n const body = await parseData(opts.data);\n const res = await client.put('/solar-form/solar-form-statistics', body);\n output(res.data, global);\n } else if (opts.create) {\n const body = (await parseData(opts.data)) || {};\n const params: Record<string, string> = {};\n if (opts.statsId) params.statsId = opts.statsId;\n const res = await client.post('/solar-form/solar-form-statistics', body, { params });\n output(res.data, global);\n } else {\n outputError(new Error('Specify --create or --update'));\n }\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\n/** Compact study output: replace heavy PowerCurve objects with summaries */\nfunction compactStudyOutput(study: unknown): unknown {\n if (study === null || study === undefined || typeof study !== 'object') return study;\n if (Array.isArray(study)) return study.map(compactStudyOutput);\n\n const record = study as Record<string, unknown>;\n\n // Detect PowerCurve: has 'days' array with objects and identifier\n if (Array.isArray(record.days) && record.days.length > 0 && record.identifier !== undefined) {\n return { _type: 'PowerCurve', days: record.days.length, identifier: record.identifier };\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const v = val as Record<string, unknown>;\n if (Array.isArray(v.days) && v.days.length > 0 && v.identifier !== undefined) {\n result[key] = { _type: 'PowerCurve', days: v.days.length, identifier: v.identifier };\n continue;\n }\n }\n result[key] = compactStudyOutput(val);\n }\n return result;\n}\n\nexport function registerPPACommands(program: Command): void {\n const ppa = program.command('ppa').description(\n 'PPA (Power Purchase Agreement) analysis.\\n' +\n 'Read PPA templates and run PPA simulations on a solar study.'\n );\n\n // --- ppa templates (read-only sub-group) ---\n const templates = ppa\n .command('templates')\n .description('Read-only access to the client PPA templates.');\n\n templates\n .command('list')\n .description(\n 'List all PPA templates for the authenticated client.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates list --fields _id,name,mode,ppaPrice,useInSolarForm'\n )\n .action(async () => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get('/solar-study/ppa-templates');\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n templates\n .command('get <id>')\n .description(\n 'Get a single PPA template by its Mongo _id.\\n' +\n 'Example:\\n' +\n ' suntropy ppa templates get 665f0a1b2c3d4e5f60718293'\n )\n .action(async (id: string) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n const res = await client.get(`/solar-study/ppa-templates/${id}`);\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- ppa calculate ---\n ppa\n .command('calculate')\n .description(\n 'Run PPA simulations on a solar study (read-only, does not persist).\\n\\n' +\n 'Provide the study via --study <id> (downloaded from the API) or --data <json>|- (full SolarStudy).\\n' +\n 'With --template <ppaTemplateId> the simulation uses that single PPA template;\\n' +\n 'without it, the backend uses the client templates flagged useInSolarForm.\\n\\n' +\n 'Note: the study must include consumption and economicResults (a study fetched\\n' +\n 'by --study already does). The response is the study with economicResults.ppaAnalysis populated.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy ppa calculate --study 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy ppa calculate --study 665f... --template 6700aa11bb22cc33dd44ee55\\n' +\n ' cat study.json | suntropy ppa calculate --data -'\n )\n .option('--study <id>', 'Solar study Mongo id to download and analyze')\n .option('--data <json>', 'Full SolarStudy JSON body (or - for stdin)')\n .option('--template <ppaTemplateId>', 'PPA template id to apply (defaults to client useInSolarForm templates)')\n .option('--raw', 'Return full study with PowerCurve data (no compaction)')\n .option('--save-file <file>', 'Save result to local file')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(ppa);\n const client = createServiceClient('solar', global);\n\n let study: unknown;\n if (opts.study) {\n const res = await client.get(`/solar-study/findById/${opts.study}`);\n study = res.data;\n } else if (opts.data) {\n study = await parseData(opts.data);\n } else {\n outputError(new Error('Provide --study <id> or --data <json>|- (full SolarStudy).'));\n return;\n }\n\n const body: Record<string, unknown> = { data: study };\n if (opts.template) body.ppaTemplateId = opts.template;\n\n const res = await client.post('/solar-study/calculate-ppa-on-study', body);\n const result = opts.raw ? res.data : compactStudyOutput(res.data);\n output(result, { ...global, save: opts.saveFile || global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/** Read all stdin as a promise */\nfunction readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (chunk) => { data += chunk; });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n}\n\n/** Read JSON data from --data flag or stdin */\nasync function parseData(data: string | undefined): Promise<Record<string, unknown> | undefined> {\n if (!data) return undefined;\n if (data === '-') {\n const input = await readStdin();\n return JSON.parse(input);\n }\n return JSON.parse(data);\n}\n\nexport function registerShareableCommands(program: Command): void {\n const shareables = program.command('shareables').description(\n 'Create shareable links for studies (sharing service, exposed under /templates).'\n );\n\n // --- create ---\n shareables\n .command('create')\n .description(\n 'Create a shareable link for a study (POST /shareable).\\n' +\n 'The backend fills uid, url, clientUID and idShareable from the token.\\n\\n' +\n 'elementType: solarStudy (default), colectiveSolarStudy, veChargerStudy, heatpumpStudy, billing\\n' +\n 'shareableType: TEMPLATE (default), CONTRACT\\n' +\n 'privacy: PUBLIC (default), PRIVATE (use --password)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy shareables create --element-id 665f0a1b2c3d4e5f60718293\\n' +\n ' suntropy shareables create --element-id 665f... --template-id 6700aa... --name \"Estudio Juan\"\\n' +\n ' suntropy shareables create --element-id 665f... --privacy PRIVATE --password secret --email-list \"a@x.com;b@y.com\"\\n' +\n ' suntropy shareables create --element-id 665f... --expiration-date 2026-12-31 --link-params \"utm_source=cli\"'\n )\n .requiredOption('--element-id <id>', 'Id of the element (study) to share')\n .option('--element-type <type>', 'solarStudy | colectiveSolarStudy | veChargerStudy | heatpumpStudy | billing', 'solarStudy')\n .option('--shareable-type <type>', 'TEMPLATE | CONTRACT', 'TEMPLATE')\n .option('--privacy <privacy>', 'PUBLIC | PRIVATE', 'PUBLIC')\n .option('--template-id <id>', 'Template id to apply to the shareable')\n .option('--name <name>', 'Descriptive name for the shareable')\n .option('--password <pwd>', 'Protect the link with a password (implies PRIVATE)')\n .option('--expiration-date <date>', 'Expiration date (e.g. 2026-12-31)')\n .option('--activation-date <date>', 'Activation date (e.g. 2026-01-01)')\n .option('--email-list <emails>', 'Semicolon-separated list of recipient emails')\n .option('--reply-to <email>', 'Reply-to email for notifications')\n .option('--custom-layout', 'Enable custom layout')\n .option('--read-only', 'Mark the shareable as read-only')\n .option('--link-params <qs>', 'Extra query params appended to the shareable link (k=v&k2=v2)')\n .option('--data <json>', 'Extra ShareableDto fields as JSON (or - for stdin), merged last')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(shareables);\n const client = createServiceClient('templates', global);\n\n const extra = (await parseData(opts.data)) || {};\n const body: Record<string, unknown> = {\n elementId: opts.elementId,\n elementType: opts.elementType,\n shareableType: opts.shareableType,\n privacy: opts.password ? 'PRIVATE' : opts.privacy,\n ...(opts.templateId ? { templateId: opts.templateId } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n ...(opts.password ? { password: opts.password, passwordConfirm: opts.password } : {}),\n ...(opts.expirationDate ? { expirationDate: opts.expirationDate } : {}),\n ...(opts.activationDate ? { activationDate: opts.activationDate } : {}),\n ...(opts.emailList ? { emailList: opts.emailList } : {}),\n ...(opts.replyTo ? { replyTo: opts.replyTo } : {}),\n ...(opts.customLayout ? { customLayout: true } : {}),\n ...(opts.readOnly ? { readOnly: true } : {}),\n ...extra,\n };\n\n const url = opts.linkParams ? `/shareable?${opts.linkParams}` : '/shareable';\n const res = await client.post(url, body);\n output(res.data, { ...global, save: global.save });\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\nexport function registerTemplatesCommands(program: Command): void {\n const templates = program.command('templates').description(\n 'Read client document templates (id + name), proxied via solar from the sharing service.'\n );\n\n // --- list ---\n templates\n .command('list')\n .description(\n 'List templates returning only _id and templateName (GET /api/templates).\\n' +\n 'Defaults to the solar study templates (--type solarStudy).\\n\\n' +\n 'Types: solarStudy (default) | colectiveSolarStudy | veChargerStudy.\\n' +\n 'Use --type generic for the generic (untyped) templates.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy templates list\\n' +\n ' suntropy templates list --type colectiveSolarStudy\\n' +\n ' suntropy templates list --type generic --fields _id,templateName --format csv'\n )\n .option(\n '--type <identifier>',\n 'solarStudy (default) | colectiveSolarStudy | veChargerStudy | generic',\n 'solarStudy',\n )\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(templates);\n const client = createServiceClient('solar', global);\n\n const params: Record<string, string> = {};\n // 'generic' means the untyped templates -> omit the identifier so the\n // backend forwards no filter (sharing returns templateIdentifier: null).\n if (opts.type && opts.type !== 'generic') {\n params.templateIdentifier = opts.type;\n }\n\n const res = await client.get('/api/templates', { params });\n output(res.data, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { createServiceClient, handleApiError } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\ninterface GeocodeResult {\n formattedAddress: string;\n lat: number;\n lng: number;\n locationType: string;\n placeId: string;\n types: string[];\n addressComponents: { longName: string; shortName: string; types: string[] }[];\n}\n\ninterface GeocodeResponse {\n status: 'OK' | 'ZERO_RESULTS';\n count: number;\n results: GeocodeResult[];\n}\n\n/** Envelope returned by the solar public API (/api/*). */\ninterface PublicApiResponse<T> {\n code?: number;\n error?: { code?: string; message?: string };\n warning?: { code?: string; message?: string };\n data?: T;\n}\n\n/**\n * Unwrap the PublicApiResponse envelope, print the best match by default (or the\n * full candidate list with --all), and surface API-level errors consistently.\n */\nfunction emit(\n envelope: PublicApiResponse<GeocodeResponse>,\n all: boolean | undefined,\n query: Record<string, unknown>,\n global: OutputOptions,\n): void {\n if (envelope.error) {\n outputError({\n error: true,\n status: envelope.code,\n message: envelope.error.message || envelope.error.code || 'Geocoding error',\n details: envelope.error,\n });\n return;\n }\n\n const data = envelope.data;\n if (!data) {\n output({ found: false, ...query }, global);\n return;\n }\n if (all) {\n output(data.results, global);\n return;\n }\n if (data.count === 0) {\n output({ found: false, ...query }, global);\n return;\n }\n output(data.results[0], global);\n}\n\nexport function registerGeocodeCommands(program: Command): void {\n const geocode = program.command('geocode').description(\n 'Geocoding via the solar service (proxy to Google Geocoding API).\\n' +\n 'Resolve an address into coordinates and vice versa.',\n );\n\n // --- geocode resolve (address -> coordinates) ---\n geocode\n .command('resolve')\n .description(\n 'Resolve an address into coordinates (lat/lng + formatted address).\\n' +\n 'Examples:\\n' +\n ' suntropy geocode resolve --address \"Calle Mayor 1, Madrid\"\\n' +\n ' suntropy geocode resolve --address \"Gran Vía, Madrid\" --country es --all',\n )\n .requiredOption('--address <string>', 'Address to geocode (quote it)')\n .option('--country <code>', 'Bias results to a country (ISO code, e.g. es, pt, it)')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/geocode',\n { params: { address: opts.address, country: opts.country } },\n );\n emit(res.data, opts.all, { address: opts.address }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n\n // --- geocode reverse (coordinates -> address) ---\n geocode\n .command('reverse')\n .description(\n 'Resolve coordinates into an address (reverse geocoding).\\n' +\n 'Example:\\n' +\n ' suntropy geocode reverse --lat 40.4168 --lng -3.7038',\n )\n .requiredOption('--lat <number>', 'Latitude')\n .requiredOption('--lng <number>', 'Longitude')\n .option('--all', 'Return all candidate matches instead of only the best one')\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(geocode);\n const client = createServiceClient('solar', global);\n const res = await client.get<PublicApiResponse<GeocodeResponse>>(\n '/api/reverse-geocode',\n { params: { lat: opts.lat, lng: opts.lng } },\n );\n emit(res.data, opts.all, { lat: opts.lat, lng: opts.lng }, global);\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import { Command, Option } from 'commander';\nimport { createServiceClient, handleApiError, assertStudyObjectId } from '../../client.js';\nimport { output, outputError, type OutputOptions } from '../../output.js';\nimport { loadConfig, getActiveProfile } from '../../config.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions & Record<string, unknown> {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as any;\n}\n\n/**\n * Well-known Suntropy user identity for the Alexandria agent. The front resolves\n * this uid to Alexandria's name/avatar (see `isAlexandriaComment`), so a\n * notification whose `fromUserUid` is this value is rendered as coming FROM\n * Alexandria — not as a self-notification from the acting user whose token the\n * CLI runs with.\n */\nconst ALEXANDRIA_USER_UID = 'alexandria';\n\nconst SEVERITIES = ['info', 'warning', 'urgent'] as const;\ntype Severity = (typeof SEVERITIES)[number];\n\nexport function registerNotificationsCommands(program: Command): void {\n const notifications = program\n .command('notifications')\n .description(\n 'Send in-app (and email) notifications to Suntropy users.\\n' +\n 'Useful for Alexandria to proactively tell a user a task is done, since a\\n' +\n 'direct/email execution leaves no study comment (and thus no auto-notification).',\n );\n\n // --- send ---\n notifications\n .command('send')\n .description(\n 'Send a notification to a user. It appears in the recipient\\'s notification\\n' +\n 'bell and, if enabled in their config, is also emailed. Sent FROM Alexandria\\n' +\n 'by default so it is not shown as a self-notification.\\n' +\n 'Examples:\\n' +\n ' suntropy notifications send --to-user <userUID> --message \"He terminado el estudio.\"\\n' +\n ' suntropy notifications send --to-user <userUID> --title \"Estudio listo\" \\\\\\n' +\n ' --message \"Revisa los resultados.\" --study <solarStudyId> --mention',\n )\n .requiredOption('--to-user <userUID>', 'Recipient userUID (who gets notified)')\n .requiredOption('--message <text>', 'Notification body (supports Markdown)')\n .option('--title <text>', 'Notification title', 'Alexandria')\n .option('--severity <severity>', `Severity: ${SEVERITIES.join(' | ')}`, 'info')\n .option(\n '--mention',\n 'Send as a mention (type new_mention) instead of an update (new_comment). ' +\n 'Mentions are gated by the user\\'s \"mention\" notification setting.',\n )\n .option(\n '--study <solarStudyId>',\n 'Link the notification to a solar study: makes it click-through to that study',\n )\n .option('--link <url>', 'Custom link for the email call-to-action')\n .option(\n '--from-user <userUID>',\n 'Sender userUID shown as the author (default: the authenticated user)',\n )\n // Hidden flag mirroring `studies comment --as-alexandria`: signs the\n // notification as Alexandria (fromUserUid = \"alexandria\", which the front\n // resolves to Alexandria's name/avatar). Omitted from --help; the agent is\n // instructed to use it. `--from-user` still takes precedence if provided.\n .addOption(new Option('--as-alexandria').hideHelp())\n .action(async (opts) => {\n try {\n const global = getGlobalOpts(notifications);\n\n const severity = opts.severity as Severity;\n if (!SEVERITIES.includes(severity)) {\n throw new Error(\n `Invalid --severity \"${opts.severity}\". Use one of: ${SEVERITIES.join(', ')}.`,\n );\n }\n // A linked study must be an actual study _id (24-hex ObjectId), or the\n // click-through would point nowhere.\n if (opts.study) assertStudyObjectId(opts.study);\n\n const client = createServiceClient('notifications', global);\n\n // Sender identity: explicit --from-user wins; else --as-alexandria signs\n // it as Alexandria; else fall back to the authenticated user (a plain\n // user-to-user notification).\n const profile = getActiveProfile(loadConfig());\n const fromUserUid = opts.fromUser\n ? opts.fromUser\n : opts.asAlexandria\n ? ALEXANDRIA_USER_UID\n : profile.userUID;\n\n const notification = {\n notificationType: opts.mention ? 'new_mention' : 'new_comment',\n severity,\n origin: opts.asAlexandria ? 'ALEXANDRIA' : 'CLI',\n fromUserUid,\n toUserUid: opts.toUser,\n notificationContent: {\n contentType: 'COMMENT',\n name: opts.title,\n description: opts.message,\n ...(opts.study ? { externalId: opts.study } : {}),\n ...(opts.link ? { link: opts.link } : {}),\n // The notifications backend only persists notificationContent when a\n // `data` payload is present (the OneToOne isn't cascaded), so without\n // this the notification renders blank in the bell. Always send a\n // small data object; harmless once the backend also persists content\n // without it. Not read by the front for these types.\n data: {\n source: opts.asAlexandria ? 'alexandria' : 'cli',\n ...(opts.study ? { studyId: opts.study } : {}),\n },\n },\n };\n\n // `@Controller('notifications')` behind the `/notifications` gateway\n // prefix → the create route is `/notifications`. clientUID/creator come\n // from the JWT; `toUserUid` in the body is the recipient.\n const res = await client.post('/notifications', notification);\n\n // The service returns the created Notification, or a string reason when\n // the client/type has notifications disabled — surface both clearly.\n if (typeof res.data === 'string') {\n output(\n { sent: false, reason: res.data, toUser: opts.toUser },\n global,\n );\n return;\n }\n output(\n {\n sent: true,\n notificationId: res.data?.idNotification,\n toUser: opts.toUser,\n type: notification.notificationType,\n severity,\n },\n global,\n );\n } catch (err) {\n outputError(handleApiError(err));\n }\n });\n}\n","import axios, { AxiosInstance } from 'axios';\nimport { readFileSync } from 'fs';\nimport type { Command } from 'commander';\nimport { createServiceClient, type ApiError } from '../../client.js';\nimport type { OutputOptions } from '../../output.js';\n\nexport type GlobalOpts = OutputOptions & {\n server?: string;\n token?: string;\n profile?: string;\n verbose?: boolean;\n};\n\nexport function getGlobalOpts(cmd: Command): GlobalOpts {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as GlobalOpts;\n}\n\n/**\n * Satvolt is only deployed on the dev cluster; there is no Satvolt behind\n * `api.enerlence.com` yet, so the path-based routing of `getServiceUrl` would\n * send every call to a 404. While the preliminary testing phase lasts, any\n * non-local server is rewritten to dev so `suntropy satvolt ...` works with\n * the default profile without having to remember `--server`.\n *\n * TODO: drop this once Satvolt is deployed to production — `getServiceUrl`\n * already resolves `<server>/satvolt` on its own.\n */\nexport const SATVOLT_DEV_BASE_URL = 'https://api-dev.suntropy.domain.eu.axebow.cloud/satvolt';\n\n/**\n * Two escape hatches so the hardcoded host does not get in the way:\n * `SUNTROPY_SATVOLT_URL` points anywhere, and a local server is left alone so\n * developing against `localhost:8099` still works.\n */\nfunction resolveSatvoltBaseUrl(resolved: string): string {\n const override = process.env.SUNTROPY_SATVOLT_URL?.trim();\n if (override) return override.replace(/\\/+$/, '');\n if (/^https?:\\/\\/(localhost|127\\.0\\.0\\.1)([:/]|$)/.test(resolved)) return resolved;\n return SATVOLT_DEV_BASE_URL;\n}\n\n/**\n * Client for the Satvolt public API (`/api/v1` on the satvolt service:\n * `<server>/satvolt/api/v1` in production, `localhost:8099/api/v1` locally).\n */\nexport function satvoltClient(global: GlobalOpts, timeout = 60000): AxiosInstance {\n const client = createServiceClient('satvolt', global);\n const base = resolveSatvoltBaseUrl(client.defaults.baseURL ?? '');\n if (global.verbose && base !== client.defaults.baseURL) {\n process.stderr.write(`\\u2192 satvolt pinned to ${base} (preliminary testing phase)\\n`);\n }\n client.defaults.baseURL = `${base}/api/v1`;\n client.defaults.timeout = timeout;\n return client;\n}\n\n/** Envelope returned by every JSON endpoint of the public API. */\ninterface Envelope<T> {\n code?: number;\n data?: T;\n error?: { code?: string; message?: string; details?: unknown };\n}\n\nexport async function call<T = any>(\n client: AxiosInstance,\n method: 'get' | 'post' | 'put' | 'patch' | 'delete',\n path: string,\n options: { params?: Record<string, unknown>; data?: unknown } = {},\n): Promise<T> {\n const res = await client.request<Envelope<T>>({\n method,\n url: path,\n params: dropEmpty(options.params),\n data: options.data,\n });\n return res.data?.data as T;\n}\n\nfunction dropEmpty(params?: Record<string, unknown>) {\n if (!params) return undefined;\n return Object.fromEntries(\n Object.entries(params).filter(([, v]) => v !== undefined && v !== null && v !== ''),\n );\n}\n\n/**\n * Turns API failures into the CLI error shape, keeping the machine-readable\n * `code` and validation `details` from the envelope (e.g. which step and field\n * failed) instead of axios' generic status text.\n */\nexport function satvoltError(err: unknown): ApiError & { code?: string } {\n if (axios.isAxiosError(err)) {\n let body = err.response?.data as unknown;\n // Downloads use responseType arraybuffer: decode the JSON error body.\n if (body instanceof ArrayBuffer || Buffer.isBuffer(body)) {\n try {\n body = JSON.parse(Buffer.from(body as ArrayBuffer).toString('utf-8'));\n } catch {\n body = undefined;\n }\n }\n const envelope = body as Envelope<unknown> | undefined;\n if (envelope?.error) {\n return {\n error: true,\n status: err.response?.status ?? 0,\n code: envelope.error.code,\n message: envelope.error.message || envelope.error.code || 'Request failed',\n details: envelope.error.details,\n };\n }\n return {\n error: true,\n status: err.response?.status ?? 0,\n message:\n err.response?.status === 404 && !envelope\n ? 'Endpoint not found: is the Satvolt public API deployed on this server?'\n : err.response?.statusText || err.message,\n details: body,\n };\n }\n return { error: true, status: 0, message: err instanceof Error ? err.message : String(err) };\n}\n\n/**\n * Reads a JSON argument: inline JSON, `@path/to/file.json`, or `-` for stdin.\n */\nexport function readJsonArg(value: string, label: string): any {\n let raw: string;\n if (value === '-') {\n raw = readFileSync(0, 'utf-8');\n } else if (value.startsWith('@')) {\n raw = readFileSync(value.slice(1), 'utf-8');\n } else {\n raw = value;\n }\n try {\n return JSON.parse(raw);\n } catch (err) {\n throw new Error(`${label} is not valid JSON: ${(err as Error).message}`);\n }\n}\n\nexport function parseId(value: string, label = 'id'): number {\n const n = Number(value);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`${label} must be a positive integer, got \"${value}\"`);\n }\n return n;\n}\n\nexport function parseIntOption(value: string | undefined, label: string): number | undefined {\n if (value === undefined) return undefined;\n const n = Number(value);\n if (!Number.isInteger(n) || n < 0) throw new Error(`${label} must be a non-negative integer`);\n return n;\n}\n\n/** \"lat,lng\" → [lat, lng] */\nexport function parseLatLng(value: string, label: string): [number, number] {\n const parts = value.split(',').map((p) => Number(p.trim()));\n if (parts.length !== 2 || parts.some((n) => !Number.isFinite(n))) {\n throw new Error(`${label} must be \"lat,lng\", got \"${value}\"`);\n }\n return [parts[0], parts[1]];\n}\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { output, outputError, outputPaginated } from '../../output.js';\nimport {\n call,\n getGlobalOpts,\n parseId,\n parseIntOption,\n parseLatLng,\n readJsonArg,\n satvoltClient,\n satvoltError,\n} from './api.js';\n\nconst TERMINAL_CAMPAIGN_STATES = new Set(['completed', 'failed', 'canceled']);\n\nconst CAMPAIGN_LIST_FIELDS =\n 'idCampaign,name,state,source,totalLeads,maxLeads,leadsCompletionPercentage,creationTimestamp';\n\n/**\n * Builds the `area` payload from the mutually exclusive area flags.\n * Polygons accept [[lat,lng],...], [{lat,lng},...] or GeoJSON (Polygon geometry\n * or Feature), whose coordinates are [lng,lat].\n */\nfunction buildArea(opts: Record<string, string | undefined>) {\n const given = ['circle', 'polygon', 'bounds'].filter((k) => opts[k] !== undefined);\n if (given.length !== 1) {\n throw new Error('Pass exactly one area: --circle <lat,lng> --radius <m> | --polygon <json|@file> | --bounds <nwLat,nwLng,seLat,seLng>');\n }\n if (opts.circle !== undefined) {\n if (opts.radius === undefined) throw new Error('--circle requires --radius <meters>');\n return {\n type: 'circle',\n center: parseLatLng(opts.circle, '--circle'),\n radiusMeters: Number(opts.radius),\n };\n }\n if (opts.bounds !== undefined) {\n const n = opts.bounds.split(',').map((p) => Number(p.trim()));\n if (n.length !== 4 || n.some((x) => !Number.isFinite(x))) {\n throw new Error('--bounds must be \"nwLat,nwLng,seLat,seLng\"');\n }\n return { type: 'bounds', northWest: [n[0], n[1]], southEast: [n[2], n[3]] };\n }\n const parsed = readJsonArg(opts.polygon as string, '--polygon');\n const geometry = parsed?.type === 'Feature' ? parsed.geometry : parsed;\n if (geometry?.type === 'Polygon') {\n const ring = geometry.coordinates?.[0] as [number, number][];\n if (!Array.isArray(ring)) throw new Error('GeoJSON Polygon has no outer ring');\n return { type: 'polygon', coordinates: ring.map(([lng, lat]) => [lat, lng]) };\n }\n if (!Array.isArray(parsed)) {\n throw new Error('--polygon must be an array of [lat,lng] points or a GeoJSON Polygon');\n }\n return { type: 'polygon', coordinates: parsed };\n}\n\nexport function registerSatvoltCampaignCommands(satvolt: Command): void {\n const campaigns = satvolt\n .command('campaigns')\n .description('Satvolt campaigns: list, create from an area, start, pause, cancel, reset, resume, usage, logs and funnel.');\n\n // --- list ---\n campaigns\n .command('list')\n .description(\n 'List campaigns, newest first.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns list --state completed,inProgress\\n' +\n ' suntropy satvolt campaigns list --search \"Alcobendas\" --format human',\n )\n .option('--limit <n>', 'Max results (max 200)', '50')\n .option('--offset <n>', 'Skip results', '0')\n .option('--search <text>', 'Match name, region or input address')\n .option('--state <states>', 'Comma-separated campaign states (see: satvolt catalog states)')\n .option('--source <source>', 'maps | excel | campaign')\n .action(async (opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const client = satvoltClient(global);\n const page = await call(client, 'get', '/campaigns', {\n params: { limit: opts.limit, offset: opts.offset, search: opts.search, state: opts.state, source: opts.source },\n });\n const outOpts = { ...global, fields: global.fields ?? (global.format !== 'json' ? CAMPAIGN_LIST_FIELDS : undefined) };\n // CSV: solo las filas (el sobre paginado no se puede aplanar).\n if (outOpts.format === 'csv') output(page.items, outOpts);\n else outputPaginated(page.items, page.total, page.limit, page.offset, outOpts);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- get ---\n campaigns\n .command('get <campaignId>')\n .description('Campaign detail: area, lead counts by state and pipeline configuration.')\n .action(async (campaignId) => {\n const global = getGlobalOpts(campaigns);\n try {\n const data = await call(satvoltClient(global), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- create ---\n campaigns\n .command('create')\n .summary('Create a Maps campaign over an area, optionally from a template or campaign.')\n .description(\n 'Create a Maps campaign over an area. It stays queued unless --start is passed\\n' +\n '(same as the web app). Steps are the LEAD steps only: SECTORIZE, FIND_LEADS\\n' +\n 'and COMPLETE are added by the backend, and missing dependencies are added too.\\n\\n' +\n 'Area (exactly one):\\n' +\n ' --circle <lat,lng> --radius <meters> stored as a circle (100 m - 50 km)\\n' +\n ' --bounds <nwLat,nwLng,seLat,seLng> rectangle\\n' +\n ' --polygon <json|@file|-> [[lat,lng],...] or GeoJSON; searched as its\\n' +\n ' bounding rectangle (a warning is returned)\\n\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns create --name \"Polígono Cobo Calleja\" \\\\\\n' +\n ' --circle 40.2597,-3.7545 --radius 1500 --max-leads 300 \\\\\\n' +\n ' --business-groups businesses --steps @steps.json\\n' +\n ' suntropy satvolt campaigns create --name \"Test\" --bounds 40.45,-3.70,40.44,-3.68 \\\\\\n' +\n ' --steps \\'[{\"action\":\"FIND_ROOFTOP\"},{\"action\":\"SOLAR_ANALYSIS\"}]\\' --start\\n' +\n ' suntropy satvolt campaigns create --data @campaign.json (full request body)\\n\\n' +\n 'Base configuration (optional, one of them): steps, business groups, description,\\n' +\n 'search query and lead limit come from it; any flag you pass wins.\\n' +\n ' --template <id|name> a campaign template (see: satvolt templates list)\\n' +\n ' --from-campaign <id> copy the pipeline of another Maps campaign\\n' +\n ' suntropy satvolt campaigns create --name \"Sonda Huévar\" --template \"Greenvolt industria\" \\\\\\n' +\n ' --circle 37.3509,-6.2757 --radius 5000 --max-leads 50',\n )\n .option('--name <name>', 'Campaign name')\n .option('--template <idOrName>', 'Base the campaign on a campaign template')\n .option('--from-campaign <id>', 'Base the campaign on the configuration of another Maps campaign')\n .option('--description <text>', 'Natural language description of the configuration')\n .option('--circle <lat,lng>', 'Circle center')\n .option('--radius <meters>', 'Circle radius in meters')\n .option('--bounds <nwLat,nwLng,seLat,seLng>', 'Rectangle corners')\n .option('--polygon <json>', 'Polygon points, GeoJSON, @file or - for stdin')\n .option('--search-query <text>', 'Use Places text search with this query instead of nearby search')\n .option('--max-leads <n>', 'Stop discovering leads after this many')\n .option('--business-groups <ids>', 'Comma-separated group ids (default: businesses). See: satvolt catalog business-groups')\n .option('--steps <json>', 'LEAD steps as JSON array, @file or -. See: satvolt catalog actions')\n .option('--address <text>', 'Reference address shown in the web app')\n .option('--region <text>', 'Region shown in the web app')\n .option('--start', 'Start the pipeline right after creating it (spends credits)')\n .option('--data <json>', 'Full request body (JSON, @file or -); flags override its fields')\n .action(async (opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const body: Record<string, unknown> = opts.data ? readJsonArg(opts.data, '--data') : {};\n if (opts.name) body.name = opts.name;\n if (opts.circle !== undefined || opts.polygon !== undefined || opts.bounds !== undefined) {\n body.area = buildArea(opts);\n }\n if (!body.name) throw new Error('--name is required');\n if (!body.area) throw new Error('An area is required: --circle/--radius, --bounds or --polygon');\n if (opts.template && opts.fromCampaign) throw new Error('Use either --template or --from-campaign, not both');\n if (opts.template) body.templateId = opts.template;\n if (opts.fromCampaign) body.fromCampaignId = parseId(opts.fromCampaign, '--from-campaign');\n if (opts.description !== undefined) body.description = opts.description;\n if (opts.searchQuery) body.searchQuery = opts.searchQuery;\n if (opts.maxLeads !== undefined) body.maxLeads = parseIntOption(opts.maxLeads, '--max-leads');\n if (opts.businessGroups) body.businessGroups = opts.businessGroups.split(',').map((s: string) => s.trim()).filter(Boolean);\n if (opts.steps) body.steps = readJsonArg(opts.steps, '--steps');\n if (opts.address) body.inputAddress = opts.address;\n if (opts.region) body.region = opts.region;\n if (opts.start) body.start = true;\n\n const data = await call(satvoltClient(global), 'post', '/campaigns', { data: body });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- estimate ---\n campaigns\n .command('estimate')\n .summary('Count the businesses a campaign would find over an area, without creating it.')\n .description(\n 'Preview of FIND_LEADS: how many businesses Google Maps returns inside the area with\\n' +\n 'the given business groups (nearby search) or text query, plus a sample to inspect.\\n' +\n 'Nothing is created and no credits are spent. Use it to iterate the filters before\\n' +\n '`campaigns create`: check `places.atLeast`, `byType` and the `sample` names, then\\n' +\n 'tighten or widen --business-groups until the sample looks like the target.\\n\\n' +\n 'The count is a minimum: the preview has a request budget and is cached (7 days) per\\n' +\n 'area, groups and query; `places.exhaustive:false` means dense zones were left out.\\n' +\n 'A text query matches place NAMES, not categories (\"manufactura\" only finds businesses\\n' +\n 'called \"Manufacturas …\"): for a category, use business groups without --search-query.\\n\\n' +\n 'Area (exactly one): --circle <lat,lng> --radius <m> | --bounds <nwLat,nwLng,seLat,seLng>\\n' +\n '| --polygon <json|@file|->. Base (optional): --template or --from-campaign give the\\n' +\n 'groups and query when not passed explicitly.\\n\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns estimate --circle 43.3934,-3.8445 --radius 1500 \\\\\\n' +\n ' --business-groups businesses --format human\\n' +\n ' suntropy satvolt campaigns estimate --circle 43.3934,-3.8445 --radius 1500 \\\\\\n' +\n ' --business-groups industrial_logistics,automotive --sample 50\\n' +\n ' suntropy satvolt campaigns estimate --bounds 40.45,-3.70,40.44,-3.68 --template \"Industria\"',\n )\n .option('--circle <lat,lng>', 'Circle center')\n .option('--radius <meters>', 'Circle radius in meters')\n .option('--bounds <nwLat,nwLng,seLat,seLng>', 'Rectangle corners')\n .option('--polygon <json>', 'Polygon points, GeoJSON, @file or - for stdin')\n .option('--template <idOrName>', 'Take business groups and query from a campaign template')\n .option('--from-campaign <id>', 'Take business groups and query from another Maps campaign')\n .option('--business-groups <ids>', 'Comma-separated group ids or raw Google Places types. See: satvolt catalog business-groups')\n .option('--search-query <text>', 'Places text search with this query instead of nearby search (matches names, not categories)')\n .option('--sample <n>', 'Sample places to return (1-100, default 20)')\n .option('--offset <n>', 'Skip this many sample places (to page through them)')\n .action(async (opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const body: Record<string, unknown> = { area: buildArea(opts) };\n if (opts.template && opts.fromCampaign) throw new Error('Use either --template or --from-campaign, not both');\n if (opts.template) body.templateId = opts.template;\n if (opts.fromCampaign) body.fromCampaignId = parseId(opts.fromCampaign, '--from-campaign');\n if (opts.businessGroups) body.businessGroups = opts.businessGroups.split(',').map((s: string) => s.trim()).filter(Boolean);\n if (opts.searchQuery) body.searchQuery = opts.searchQuery;\n if (opts.sample !== undefined) body.sample = parseIntOption(opts.sample, '--sample');\n if (opts.offset !== undefined) body.offset = parseIntOption(opts.offset, '--offset');\n\n const data = await call(satvoltClient(global, 120000), 'post', '/campaigns/estimate', { data: body });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- delete ---\n campaigns\n .command('delete <campaignId>')\n .summary('Delete a campaign and everything it generated (irreversible, --yes).')\n .description(\n 'Delete a campaign with its sectors, leads, step executions, pipeline configuration\\n' +\n 'and queued jobs. Irreversible. Export tables of the campaign stop working.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt campaigns delete 63 --yes',\n )\n .option('--yes', 'Confirm the deletion (required)')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n if (!opts.yes) throw new Error('Deleting a campaign is irreversible. Re-run with --yes to confirm.');\n const data = await call(satvoltClient(global), 'delete', `/campaigns/${parseId(campaignId, 'campaignId')}`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- start ---\n campaigns\n .command('start <campaignId>')\n .description('Start the pipeline of a queued campaign (spends credits).')\n .action(async (campaignId) => {\n const global = getGlobalOpts(campaigns);\n try {\n const data = await call(satvoltClient(global), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/start`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- pause ---\n campaigns\n .command('pause <campaignId>')\n .summary('Pause a running campaign: nothing else runs or is charged until unpause.')\n .description(\n 'Pause a running campaign. Queued work is withdrawn and steps already in flight\\n' +\n 'finish without queuing their successors, so no more credits are spent. Results\\n' +\n 'of async steps whose webhook arrives meanwhile are kept. Only a running\\n' +\n 'campaign (inProgress, sectorized, leadsFound, analyzed) can be paused;\\n' +\n 'otherwise 409 INVALID_CAMPAIGN_STATE.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt campaigns pause 72',\n )\n .action(async (campaignId) => {\n const global = getGlobalOpts(campaigns);\n try {\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/pause`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- unpause ---\n campaigns\n .command('unpause <campaignId>')\n .summary('Resume a paused campaign where it stopped (no step is run twice).')\n .description(\n 'Resume a paused campaign where it stopped: every lead that is not finished gets\\n' +\n 'its next pending step queued, and steps already executed are neither re-run\\n' +\n 'nor charged again. Only a paused campaign can be unpaused. This is not\\n' +\n '`resume`, which appends a NEW step to a finished campaign.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt campaigns unpause 72',\n )\n .action(async (campaignId) => {\n const global = getGlobalOpts(campaigns);\n try {\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/unpause`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- cancel ---\n campaigns\n .command('cancel <campaignId>')\n .summary('Cancel a running or paused campaign for good, keeping its leads and data (--yes).')\n .description(\n 'Cancel a running, paused or queued campaign. Irreversible: it cannot be unpaused\\n' +\n 'or started again (reset relaunches it from scratch, deleting the leads). Leads\\n' +\n 'and the data already enriched are kept, can be exported and are still charged.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt campaigns cancel 72 --yes',\n )\n .option('--yes', 'Confirm the cancellation (required)')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n if (!opts.yes) throw new Error('Cancelling a campaign is irreversible. Re-run with --yes to confirm.');\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/cancel`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- reset ---\n campaigns\n .command('reset <campaignId>')\n .summary('Relaunch a campaign from scratch: deletes its leads and results (--yes).')\n .description(\n 'Relaunch a campaign from scratch: deletes its sectors, leads and processing data\\n' +\n 'and returns it to queued, keeping the configuration. Excel/campaign-sourced\\n' +\n 'campaigns keep their imported leads. Irreversible.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt campaigns reset 59 --yes --start',\n )\n .option('--start', 'Start the pipeline again after resetting')\n .option('--yes', 'Confirm the reset (required)')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n if (!opts.yes) throw new Error('Reset deletes the campaign leads and results. Re-run with --yes to confirm.');\n const data = await call(satvoltClient(global), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/reset`, {\n params: { start: opts.start ? 'true' : undefined },\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- extend ---\n campaigns\n .command('extend <campaignId>')\n .summary('Get more leads from a finished Maps campaign without relaunching it.')\n .description(\n 'Get more leads from a finished Maps campaign without relaunching it: raises (or\\n' +\n 'removes) its lead limit and searches again only in the sectors whose search was\\n' +\n 'cut short. Existing leads are kept and only the new ones go through the pipeline\\n' +\n '(spends credits). `campaigns get` shows sectorSearch: incomplete + unknown > 0\\n' +\n 'means more leads can still be found; 0 means the area is exhausted.\\n' +\n 'Cost: new leads x credits per lead (`campaigns usage` → avgCreditsPerLead). With\\n' +\n '--max-leads the new leads are at most the difference; with --no-limit estimate them\\n' +\n 'from the leads found per sector so far.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns extend 62 --max-leads 500\\n' +\n ' suntropy satvolt campaigns extend 62 --no-limit',\n )\n .option('--max-leads <n>', 'New lead limit (must be greater than the current number of leads)')\n .option('--no-limit', 'Remove the lead limit and search every pending sector fully')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n // commander turns --no-limit into opts.limit === false.\n const removeLimit = opts.limit === false;\n if (removeLimit === (opts.maxLeads !== undefined)) {\n throw new Error('Pass exactly one of --max-leads <n> or --no-limit.');\n }\n const maxLeads = removeLimit ? null : parseIntOption(opts.maxLeads, '--max-leads');\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/extend`, {\n data: { maxLeads },\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- resume ---\n campaigns\n .command('resume <campaignId>')\n .summary('Append a new step at the end and run it over the existing leads.')\n .description(\n 'Resume a finished campaign from a NEW step: appends it at the end of the pipeline\\n' +\n '(before COMPLETE) and runs it over the existing leads that reached the previous\\n' +\n 'step. Missing dependencies are added before it. If the step cannot run, the\\n' +\n 'configuration change is rolled back. --config is only the config object of the step\\n' +\n '(see configSchema in `satvolt catalog actions`), not { action, config }.\\n' +\n 'Cost: leads that reached the last step (`campaigns funnel`) x creditCost of the action.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns resume 59 --action ESTIMATE_CONSUMPTION --config \\'{\"tariffTemplate\":\"3.0TD\"}\\'\\n' +\n ' suntropy satvolt campaigns resume 59 --action AI_AGENT \\\\\\n' +\n ' --config \\'{\"customName\":\"Web corporativa\",\"agentId\":\"<id from catalog ai-agents>\",\"outputKey\":\"web\"}\\'',\n )\n .requiredOption('--action <ACTION>', 'Action to add (see: satvolt catalog actions)')\n .option('--config <json>', 'Step config as JSON, @file or -')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const step: Record<string, unknown> = { action: String(opts.action).toUpperCase() };\n if (opts.config) step.config = readJsonArg(opts.config, '--config');\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/resume`, {\n data: { step },\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- usage ---\n campaigns\n .command('usage <campaignId>')\n .description(\n 'Credits consumed by the campaign, as shown in the Usage tab: total, per lead\\n' +\n 'average and per step. --by-lead adds the per-lead breakdown.',\n )\n .option('--by-lead', 'Include the per-lead breakdown')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const data = await call(satvoltClient(global, 120000), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/usage`, {\n params: { include: opts.byLead ? 'leads' : undefined },\n });\n if (global.format === 'human' || global.format === 'csv') {\n // Tables read better per step; the summary goes to stderr in human mode.\n if (global.format === 'human') {\n process.stderr.write(\n chalk.bold(`Total ${data.totalCredits} credits · ${data.totalLeads} leads · ${data.avgCreditsPerLead} per lead\\n\\n`),\n );\n }\n output(data.byStep, global);\n return;\n }\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- funnel ---\n campaigns\n .command('funnel <campaignId>')\n .summary('Leads per pipeline step, by execution or by success criteria')\n .description(\n 'Funnel of the campaign: for each LEAD step, how many leads reached it and how many\\n' +\n 'succeeded, failed, were skipped, are processing (async) or still pending, plus\\n' +\n 'the lead counts by state.\\n' +\n '\\n' +\n '--mode success shows how many leads the step actually brought data for, which is\\n' +\n 'not the same thing: an agent can finish without error answering that it found\\n' +\n 'nothing. It uses the `successIf` paths configured on each step, evaluated against\\n' +\n \"the lead's current data — change the criteria and the numbers change, with no\\n\" +\n 're-run. Steps without criteria fall back to their successful executions.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns funnel 62\\n' +\n ' suntropy satvolt campaigns funnel 62 --mode success',\n )\n .option('--mode <mode>', 'execution (default) | success', 'execution')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const mode = String(opts.mode || 'execution').toLowerCase();\n if (mode !== 'execution' && mode !== 'success') {\n outputError({ code: 'INVALID_MODE', message: '--mode must be execution or success' });\n return;\n }\n const data = await call(satvoltClient(global, 120000), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/funnel`);\n if (global.format === 'human' || global.format === 'csv') {\n output(\n (data.steps ?? []).map((s: any) =>\n mode === 'success'\n ? {\n step: s.name,\n action: s.action,\n reached: s.reached,\n withData: s.criteria ? s.criteria.met : s.success,\n pctOfTotal: s.criteria ? s.criteria.metPct : s.reachedPct,\n missingData: s.criteria ? s.criteria.unmet : '',\n retries: s.criteria?.maxRetries || '',\n successIf: s.criteria ? s.criteria.paths.join(', ') : '(no criteria)',\n }\n : {\n step: s.name,\n action: s.action,\n reached: s.reached,\n pctOfTotal: s.reachedPct,\n success: s.success,\n failure: s.failure,\n skipped: s.skipped,\n processing: s.processing,\n pending: s.pending,\n },\n ),\n global,\n );\n return;\n }\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n // --- logs ---\n campaigns\n .command('logs <campaignId>')\n .description(\n 'Campaign processing logs (kept 30 days, last 5000 entries).\\n' +\n '--follow keeps polling and stops by itself when the campaign reaches a final state.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt campaigns logs 59 --level error\\n' +\n ' suntropy satvolt campaigns logs 59 --follow --format human',\n )\n .option('--limit <n>', 'Max entries (max 5000)', '500')\n .option('--since <ts>', 'Only entries after this epoch-ms timestamp (use lastTs from a previous call)')\n .option('--level <level>', 'debug | log | warn | error')\n .option('--follow', 'Poll for new entries until the campaign finishes')\n .option('--interval <seconds>', 'Polling interval with --follow', '3')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(campaigns);\n try {\n const id = parseId(campaignId, 'campaignId');\n const client = satvoltClient(global);\n const fetchLogs = (sinceTs?: number | string) =>\n call(client, 'get', `/campaigns/${id}/logs`, {\n params: { limit: opts.limit, sinceTs, level: opts.level },\n });\n\n const printEntries = (entries: Array<{ ts: number; level: string; source: string; message: string }>) => {\n for (const e of entries) {\n if (global.format === 'human') {\n const color = e.level === 'error' ? chalk.red : e.level === 'warn' ? chalk.yellow : chalk.dim;\n process.stdout.write(`${chalk.dim(new Date(e.ts).toISOString())} ${color(e.level.padEnd(5))} ${e.source}: ${e.message}\\n`);\n } else {\n process.stdout.write(JSON.stringify(e) + '\\n');\n }\n }\n };\n\n const first = await fetchLogs(opts.since);\n if (!opts.follow) {\n if (global.format === 'human') printEntries(first.entries);\n else output(first, global);\n return;\n }\n\n // --follow streams JSON lines (one entry per line) so it can be piped.\n printEntries(first.entries);\n let lastTs = first.lastTs;\n const intervalMs = Math.max(1, Number(opts.interval) || 3) * 1000;\n for (;;) {\n const campaign = await call(client, 'get', `/campaigns/${id}`);\n await new Promise((r) => setTimeout(r, intervalMs));\n const next = await fetchLogs(lastTs ?? undefined);\n printEntries(next.entries);\n lastTs = next.lastTs ?? lastTs;\n if (TERMINAL_CAMPAIGN_STATES.has(campaign.state)) {\n process.stderr.write(`Campaign ${id} is ${campaign.state}; stopped following.\\n`);\n return;\n }\n }\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { output, outputError } from '../../output.js';\nimport {\n call,\n getGlobalOpts,\n parseId,\n readJsonArg,\n satvoltClient,\n satvoltError,\n} from './api.js';\n\nconst STEP_LIST_FIELDS = 'index,uid,action,name,disable,creditCost,executedLeads,runnable,reason';\n\nasync function patchSteps(cmd: Command, campaignId: string, steps: unknown[]) {\n const global = getGlobalOpts(cmd);\n const data = await call(satvoltClient(global), 'patch', `/campaigns/${parseId(campaignId, 'campaignId')}/configuration`, {\n data: { steps },\n });\n output(data, global);\n}\n\n/**\n * `satvolt config`: the whole pipeline configuration as JSON (get / update / patch).\n * `satvolt steps`: step-level commands built on top of it (list, add, set, remove, run).\n */\nexport function registerSatvoltPipelineCommands(satvolt: Command): void {\n const config = satvolt\n .command('config')\n .summary('Pipeline configuration of a campaign as JSON (get, update, patch).')\n .description(\n 'Pipeline configuration of a campaign as JSON.\\n' +\n 'Workflow: config get > edit the JSON > config update (full) or config patch (partial).',\n );\n\n config\n .command('get <campaignId>')\n .description(\n 'Get the configuration: source, businessGroups, description and steps\\n' +\n '(uid, action, target, disable, structural, config).\\n' +\n 'Example:\\n' +\n ' suntropy satvolt config get 59 --save pipeline.json',\n )\n .action(async (campaignId) => {\n const global = getGlobalOpts(config);\n try {\n const data = await call(satvoltClient(global), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/configuration`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n config\n .command('update <campaignId>')\n .description(\n 'Replace the pipeline (PUT). The body is { steps, businessGroups?, description? } where\\n' +\n 'steps is the FULL list of editable steps in order. Structural steps (SECTORIZE,\\n' +\n 'FIND_LEADS, IMPORT_LEADS, COMPLETE) are ignored in the input and kept by the backend,\\n' +\n 'so the output of `config get` can be sent back as is. Steps without uid get one;\\n' +\n 'config is validated against each action schema (satvolt catalog actions).\\n' +\n 'Example:\\n' +\n ' suntropy satvolt config update 59 --data @pipeline.json',\n )\n .requiredOption('--data <json>', 'Configuration JSON, @file or -')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(config);\n try {\n const body = readJsonArg(opts.data, '--data');\n const data = await call(satvoltClient(global), 'put', `/campaigns/${parseId(campaignId, 'campaignId')}/configuration`, {\n data: body,\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n config\n .command('patch <campaignId>')\n .description(\n 'Partial change (PATCH). Body: { steps?, businessGroups?, description? }.\\n' +\n 'Each item in steps:\\n' +\n ' { \"uid\": \"<existing>\", \"config\": {...} } merge config (JSON Merge Patch: null resets a key to its default)\\n' +\n ' { \"uid\": \"<existing>\", \"replaceConfig\": true, \"config\": {...} } replace config\\n' +\n ' { \"uid\": \"<existing>\", \"disable\": true }\\n' +\n ' { \"uid\": \"<existing>\", \"after\": \"<uid>\" } move (also \"before\")\\n' +\n ' { \"uid\": \"<existing>\", \"remove\": true }\\n' +\n ' { \"action\": \"QUALIFY\", \"config\": {...} } add (before COMPLETE, or before/after a uid)\\n' +\n 'Example:\\n' +\n ' suntropy satvolt config patch 59 --data \\'{\"steps\":[{\"uid\":\"d3f2849c52281f36\",\"config\":{\"enableWebSearch\":true}}]}\\'',\n )\n .requiredOption('--data <json>', 'Patch JSON, @file or -')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(config);\n try {\n const body = readJsonArg(opts.data, '--data');\n const data = await call(satvoltClient(global), 'patch', `/campaigns/${parseId(campaignId, 'campaignId')}/configuration`, {\n data: body,\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n const steps = satvolt\n .command('steps')\n .description('Steps of a campaign pipeline: list with run status, add, set, remove and run.');\n\n steps\n .command('list <campaignId>')\n .description(\n 'List the pipeline steps in order with catalog data (name, credits, async) and run\\n' +\n 'status: executedLeads, and runnable/reason for steps no lead has executed yet.',\n )\n .action(async (campaignId) => {\n const global = getGlobalOpts(steps);\n try {\n const data = await call(satvoltClient(global), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/steps`);\n if (global.format === 'json' && !global.fields) {\n output(data, global);\n } else {\n output(data.steps, { ...global, fields: global.fields ?? STEP_LIST_FIELDS });\n }\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n steps\n .command('add <campaignId>')\n .description(\n 'Add a step. Goes before COMPLETE unless --before/--after is given. Config defaults\\n' +\n 'from the action schema are filled in and missing dependencies are added.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt steps add 59 --action QUALIFY --config \\'{\"qualificationDefinition\":\"...\"}\\'',\n )\n .requiredOption('--action <ACTION>', 'Action (see: satvolt catalog actions)')\n .option('--config <json>', 'Step config as JSON, @file or -')\n .option('--uid <uid>', 'Explicit uid for the new step')\n .option('--before <uid>', 'Insert before this step')\n .option('--after <uid>', 'Insert after this step')\n .option('--disabled', 'Add it disabled')\n .action(async (campaignId, opts) => {\n try {\n const step: Record<string, unknown> = { action: String(opts.action).toUpperCase() };\n if (opts.config) step.config = readJsonArg(opts.config, '--config');\n if (opts.uid) step.uid = opts.uid;\n if (opts.before) step.before = opts.before;\n if (opts.after) step.after = opts.after;\n if (opts.disabled) step.disable = true;\n await patchSteps(steps, campaignId, [step]);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n steps\n .command('set <campaignId> <stepUid>')\n .description(\n 'Change one step: merge --config into its config (null resets a key to its default), or replace it\\n' +\n 'with --replace-config; enable/disable; move with --before/--after.\\n' +\n '\\n' +\n 'Every step also takes two common config keys, whatever its action:\\n' +\n ' skipIfEmpty path that, when empty, skips the step for that lead\\n' +\n ' successIf paths the step must fill for its result to count as useful, relative\\n' +\n ' to what the step writes (an agent: relative to its response), or\\n' +\n ' absolute with fullData./lead. Feeds `campaigns funnel --mode success`\\n' +\n ' maxRetries 0-5. Repeats the step while successIf is not met. Credits are charged\\n' +\n ' once per step, not per attempt; if the last attempt still has no data\\n' +\n ' the lead carries on to the next step.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt steps set 59 95161b8b080180e4 --config \\'{\"outputKey\":\"company\"}\\'\\n' +\n ' suntropy satvolt steps set 62 7f3edaf055d60627 --config \\'{\"successIf\":[\"response.linkedinUrl\"],\"maxRetries\":2}\\'',\n )\n .option('--config <json>', 'Config JSON, @file or -')\n .option('--replace-config', 'Replace the whole config instead of merging')\n .option('--enable', 'Enable the step')\n .option('--disable', 'Disable the step')\n .option('--before <uid>', 'Move before this step')\n .option('--after <uid>', 'Move after this step')\n .action(async (campaignId, stepUid, opts) => {\n try {\n if (opts.enable && opts.disable) throw new Error('Use either --enable or --disable');\n const step: Record<string, unknown> = { uid: stepUid };\n if (opts.config) step.config = readJsonArg(opts.config, '--config');\n if (opts.replaceConfig) step.replaceConfig = true;\n if (opts.enable) step.disable = false;\n if (opts.disable) step.disable = true;\n if (opts.before) step.before = opts.before;\n if (opts.after) step.after = opts.after;\n if (Object.keys(step).length === 1) throw new Error('Nothing to change: pass --config, --enable/--disable or --before/--after');\n await patchSteps(steps, campaignId, [step]);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n steps\n .command('remove <campaignId> <stepUid>')\n .description('Remove a step from the pipeline (results already stored on leads are kept).')\n .action(async (campaignId, stepUid) => {\n try {\n await patchSteps(steps, campaignId, [{ uid: stepUid, remove: true }]);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n steps\n .command('run <campaignId> <stepUid>')\n .description(\n 'Run a step that no lead has executed yet over the existing leads, then continue the\\n' +\n 'pipeline to the end. Only the first never-executed step with nothing executed\\n' +\n 'after it is runnable (see runnable/reason in `steps list`). Spends credits.',\n )\n .action(async (campaignId, stepUid) => {\n const global = getGlobalOpts(steps);\n try {\n const data = await call(satvoltClient(global, 120000), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/steps/${encodeURIComponent(stepUid)}/run`);\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n","import type { Command } from 'commander';\nimport { output, outputError } from '../../output.js';\nimport { call, getGlobalOpts, parseId, satvoltClient, satvoltError } from './api.js';\n\ninterface Field {\n path: string;\n label: string;\n type: string;\n source?: string;\n coverage?: number | null;\n example?: unknown;\n}\n\ninterface FieldCatalog {\n sampledLeads: number;\n lead: Field[];\n synthetic: Field[];\n steps: Array<{\n uid: string | null;\n action: string;\n name: string;\n keys: string[];\n coverage: number | null;\n fields: Field[];\n dynamic: Array<{ path: string; description: string; inferredFrom?: { campaignId: number; sampledLeads: number } }>;\n }>;\n other: Field[];\n}\n\nconst pct = (v: number | null | undefined) => (v === null || v === undefined ? '-' : `${Math.round(v * 100)}%`);\n\n/** One row per path, with the step it belongs to, for human and CSV output. */\nfunction flatten(catalog: FieldCatalog, onlyStep: boolean): Array<Record<string, unknown>> {\n const rows: Array<Record<string, unknown>> = [];\n const push = (group: string, f: Field, source = f.source) =>\n rows.push({ group, path: f.path, label: f.label, type: f.type, source, coverage: pct(f.coverage), example: f.example ?? null });\n if (!onlyStep) {\n for (const f of catalog.lead) push('Lead', f, 'lead');\n for (const f of catalog.synthetic) push('Lead', f, 'synthetic');\n }\n for (const step of catalog.steps) {\n const group = `${step.name} [${step.action}]`;\n for (const f of step.fields) push(group, f);\n for (const d of step.dynamic) {\n rows.push({\n group,\n path: `${d.path}.*`,\n label: '-',\n type: '-',\n source: 'dynamic',\n coverage: '-',\n example: d.inferredFrom\n ? `${d.description} Fields above inferred from campaign ${d.inferredFrom.campaignId}.`\n : d.description,\n });\n }\n }\n if (!onlyStep) for (const f of catalog.other) push('Other (no current step)', f);\n return rows;\n}\n\nexport function registerFieldsCommand(parent: Command, note?: string): void {\n parent\n .command('fields <campaignId>')\n .summary('Fields for export table columns, grouped by pipeline step.')\n .description(\n 'Data paths for export table columns, grouped by pipeline step. Each step lists the\\n' +\n 'fields it declares (available before the campaign has data) plus the ones seen in a\\n' +\n 'sample of leads, with column type, coverage and an example. AI agent responses depend\\n' +\n 'on the agent: until this campaign has answers they are inferred from another campaign\\n' +\n 'of yours with the same agent (source: otherCampaign).\\n' +\n 'source: catalog (declared by the step) | observed (seen in leads) | otherCampaign |\\n' +\n ' dynamic (shape depends on the step config) | lead | synthetic\\n' +\n '--search matches path and label (labels are in English: consumption, email…).\\n' +\n (note ? `${note}\\n` : '') +\n 'Examples:\\n' +\n ' suntropy satvolt export-tables fields 59 --format human\\n' +\n ' suntropy satvolt export-tables fields 59 --step QUALIFY --format human\\n' +\n ' suntropy satvolt export-tables fields 59 --search cnae --format human',\n )\n .option('--sample <n>', 'Leads to sample (max 100)', '25')\n .option('--step <step>', 'Only this step: uid, ACTION (if unique), step name or fullData key')\n .option('--search <text>', 'Only paths or labels containing this text')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(parent);\n try {\n const catalog: FieldCatalog = await call(\n satvoltClient(global, 120000),\n 'get',\n `/campaigns/${parseId(campaignId, 'campaignId')}/fields`,\n { params: { sample: opts.sample, step: opts.step } },\n );\n const search = typeof opts.search === 'string' ? opts.search.toLowerCase() : undefined;\n if (global.format === 'json') {\n if (search) {\n const match = (f: Field) => f.path.toLowerCase().includes(search) || f.label?.toLowerCase().includes(search);\n catalog.lead = catalog.lead.filter(match);\n catalog.synthetic = catalog.synthetic.filter(match);\n catalog.other = catalog.other.filter(match);\n catalog.steps = catalog.steps\n .map((s) => ({ ...s, fields: s.fields.filter(match) }))\n .filter((s) => s.fields.length > 0);\n }\n output(catalog, global);\n return;\n }\n let rows = flatten(catalog, Boolean(opts.step));\n if (search) {\n rows = rows.filter(\n (r) => String(r.path).toLowerCase().includes(search) || String(r.label).toLowerCase().includes(search),\n );\n }\n output(rows, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { output, outputError, outputPaginated } from '../../output.js';\nimport { registerFieldsCommand } from './fields.js';\nimport {\n call,\n getGlobalOpts,\n parseId,\n satvoltClient,\n satvoltError,\n} from './api.js';\n\nconst LEAD_LIST_FIELDS = 'idLead,commercialName,state,stateError,lastAction,address,phone,url';\n\nexport function registerSatvoltLeadCommands(satvolt: Command): void {\n const leads = satvolt\n .command('leads')\n .description('Leads of a campaign: paginated list with state, filters by step, detail and available data fields.');\n\n leads\n .command('list <campaignId>')\n .description(\n 'List leads with their state (plus stateError, last action and QUALIFY verdicts).\\n\\n' +\n 'Filters:\\n' +\n ' --name <text> commercial name contains (like the web table)\\n' +\n ' --search <text> name, address, phone, place id or reference\\n' +\n ' --state <a,b> lead states (see: satvolt catalog states)\\n' +\n ' --step <step> pipeline step: uid, ACTION (if it appears once), step name\\n' +\n ' (\"Buscador de CIF\") or fullData key (cif)\\n' +\n ' --step-status <s> reached (default) | success | failure | skipped | processing | pending\\n\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt leads list 59 --name \"logistica\" --limit 25\\n' +\n ' suntropy satvolt leads list 59 --step QUALIFY --step-status failure\\n' +\n ' suntropy satvolt leads list 59 --step 95161b8b080180e4 --step-status pending --format csv',\n )\n .option('--limit <n>', 'Page size (max 200)', '25')\n .option('--offset <n>', 'Skip results', '0')\n .option('--page <n>', 'Page number (1-based); overrides --offset')\n .option('--name <text>', 'Commercial name contains')\n .option('--search <text>', 'Broad search')\n .option('--state <states>', 'Comma-separated lead states')\n .option('--step <step>', 'Filter by pipeline step: uid, ACTION (if unique), step name or fullData key')\n .option('--step-status <status>', 'Status in that step')\n .option('--with-steps', 'Include the status of every LEAD step on each lead')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(leads);\n try {\n const limit = Number(opts.limit);\n const offset = opts.page ? (Math.max(1, Number(opts.page)) - 1) * limit : Number(opts.offset);\n const page = await call(satvoltClient(global), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/leads`, {\n params: {\n limit,\n offset,\n name: opts.name,\n search: opts.search,\n state: opts.state,\n step: opts.step,\n stepStatus: opts.stepStatus,\n include: opts.withSteps ? 'steps' : undefined,\n },\n });\n const outOpts = { ...global, fields: global.fields ?? (global.format !== 'json' ? LEAD_LIST_FIELDS : undefined) };\n // CSV: solo las filas (el sobre paginado no se puede aplanar).\n if (outOpts.format === 'csv') output(page.items, outOpts);\n else outputPaginated(page.items, page.total, page.limit, page.offset, outOpts);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n leads\n .command('get <campaignId> <leadId>')\n .description(\n 'Lead detail: columns, status of each pipeline step, state history and the list of\\n' +\n 'fullData keys. --full-data adds the enriched data (all of it, or only some keys).\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt leads get 59 1216\\n' +\n ' suntropy satvolt leads get 59 1216 --full-data consumptionEstimate,solarPanelAnalysis',\n )\n .option('--full-data [keys]', 'Include fullData (optionally comma-separated top-level keys)')\n .action(async (campaignId, leadId, opts) => {\n const global = getGlobalOpts(leads);\n try {\n const fullData = opts.fullData === true ? 'true' : opts.fullData;\n const data = await call(\n satvoltClient(global),\n 'get',\n `/campaigns/${parseId(campaignId, 'campaignId')}/leads/${parseId(leadId, 'leadId')}`,\n { params: { fullData } },\n );\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n leads\n .command('full-data <campaignId> <leadId>')\n .summary('Only the enriched data of a lead (all, some keys or one path).')\n .description(\n 'Print only the enriched data (fullData) of a lead, optionally a subset of keys or a\\n' +\n 'single nested path.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt leads full-data 62 2078\\n' +\n ' suntropy satvolt leads full-data 62 2078 --keys consumptionEstimate,cif\\n' +\n ' suntropy satvolt leads full-data 62 2078 --path cif.response.extras.cnae',\n )\n .option('--keys <keys>', 'Comma-separated top-level keys')\n .option('--path <dotted.path>', 'Return the value at this path inside fullData')\n .action(async (campaignId, leadId, opts) => {\n const global = getGlobalOpts(leads);\n try {\n const topKey = opts.path ? String(opts.path).split('.')[0] : undefined;\n const data = await call(\n satvoltClient(global),\n 'get',\n `/campaigns/${parseId(campaignId, 'campaignId')}/leads/${parseId(leadId, 'leadId')}`,\n { params: { fullData: topKey ?? opts.keys ?? 'true' } },\n );\n let value: unknown = data.fullData ?? {};\n if (opts.path) {\n for (const part of String(opts.path).split('.')) {\n value = value && typeof value === 'object' ? (value as Record<string, unknown>)[part] : undefined;\n }\n if (value === undefined) throw new Error(`Path \"${opts.path}\" not found in the fullData of lead ${leadId}`);\n }\n output(value, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n leads\n .command('run-step <campaignId> <leadId> <step>')\n .summary('Run one pipeline step on a single lead (only that step, or --continue).')\n .description(\n 'Run one pipeline step on a single lead, through the same queue as the pipeline.\\n' +\n 'Step: uid, action if it appears once, step name or fullData key (e.g. cif).\\n' +\n 'Spends the credits of that step (a failed or skipped run is free).\\n' +\n ' default only that step: later steps are not queued and a completed or\\n' +\n ' unqualified lead keeps its state (except when re-running QUALIFY)\\n' +\n ' --continue continue the pipeline from that step (later steps run again)\\n' +\n ' --force skip the check that the lead completed the step dependencies\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt leads run-step 62 2034 ESTIMATE_CONSUMPTION\\n' +\n ' suntropy satvolt leads run-step 62 2081 f8771dae3f963702 --continue',\n )\n .option('--continue', 'Continue the pipeline after the step')\n .option('--force', 'Run even if the lead has not completed the step dependencies')\n .action(async (campaignId, leadId, step, opts) => {\n const global = getGlobalOpts(leads);\n try {\n const data = await call(\n satvoltClient(global),\n 'post',\n `/campaigns/${parseId(campaignId, 'campaignId')}/leads/${parseId(leadId, 'leadId')}/steps/${encodeURIComponent(step)}/run`,\n { data: { mode: opts.continue ? 'continue' : 'only', force: opts.force === true } },\n );\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n registerFieldsCommand(leads, 'Same as `satvolt export-tables fields`.');\n}\n","import { Command } from 'commander';\nimport { writeFileSync } from 'fs';\nimport { resolve } from 'path';\nimport { output, outputError, outputPaginated } from '../../output.js';\nimport {\n call,\n getGlobalOpts,\n parseId,\n parseIntOption,\n readJsonArg,\n satvoltClient,\n satvoltError,\n} from './api.js';\nimport { registerFieldsCommand } from './fields.js';\n\ninterface Column {\n id: string;\n label: string;\n path: string;\n type: string;\n}\n\n/**\n * Columns can be given as full objects or as shorthand strings\n * \"Label=path[:type]\" (e.g. \"CIF=fullData.webData.tax_id\"). Without a type\n * the server uses the one the pipeline step declares for that path, or string.\n */\nfunction parseColumns(value: string): unknown[] {\n const trimmed = value.trim();\n if (trimmed.startsWith('[') || trimmed.startsWith('@') || trimmed === '-') {\n const parsed = readJsonArg(value, '--columns');\n if (!Array.isArray(parsed)) throw new Error('--columns JSON must be an array');\n return parsed;\n }\n return trimmed.split(';').map((part) => {\n const m = /^(.+?)=([^:]+)(?::(string|number|boolean|date|url))?$/.exec(part.trim());\n if (!m) throw new Error(`Invalid column \"${part}\". Use \"Label=path[:type]\" separated by \";\" or a JSON array`);\n return { label: m[1].trim(), path: m[2].trim(), ...(m[3] ? { type: m[3] } : {}) };\n });\n}\n\nexport function registerSatvoltExportTableCommands(satvolt: Command): void {\n const tables = satvolt\n .command('export-tables')\n .summary('Export tables: column sets over lead data, paged reads and XLSX/CSV downloads.')\n .description(\n 'Export tables of a campaign: named column sets over lead data, readable page by page\\n' +\n 'and downloadable as XLSX or CSV. Column paths: lead.<column>, fullData.<path> and\\n' +\n 'synthetic.googleMapsUrl. `export-tables fields <campaignId>` lists them by pipeline step.',\n );\n\n registerFieldsCommand(tables, 'Same as `satvolt leads fields`.');\n\n tables\n .command('list <campaignId>')\n .description('List the export tables of a campaign.')\n .action(async (campaignId) => {\n const global = getGlobalOpts(tables);\n try {\n const data = await call(satvoltClient(global), 'get', `/campaigns/${parseId(campaignId, 'campaignId')}/export-tables`);\n output(global.format === 'json' ? data : data.map((t: { columns: Column[] }) => ({ ...t, columns: t.columns.length })), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('get <tableId>')\n .description('Get an export table with its columns.')\n .action(async (tableId) => {\n const global = getGlobalOpts(tables);\n try {\n output(await call(satvoltClient(global), 'get', `/export-tables/${tableId}`), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('create <campaignId>')\n .summary('Create an export table with its columns.')\n .description(\n 'Create an export table. Column ids are generated when omitted. Without a type, the\\n' +\n 'column takes the one declared by the step that writes the path, or string.\\n' +\n 'Find paths with: suntropy satvolt export-tables fields <campaignId>\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt export-tables create 59 --name \"CRM\" \\\\\\n' +\n ' --columns \"Empresa=lead.commercialName;Web=lead.url;Consumo kWh=fullData.consumptionEstimate.annualKwh;Maps=synthetic.googleMapsUrl\"\\n' +\n 'fullData paths depend on the steps of each campaign (an AI agent with outputKey \"cif\"\\n' +\n 'writes fullData.cif.response.<field>): take them from `export-tables fields`.\\n' +\n 'Synthetic paths: synthetic.googleMapsUrl (Google Maps link built from the coordinates).\\n' +\n 'The response is the table: { id, campaignId, name, description, columns, warnings }.\\n' +\n ' suntropy satvolt export-tables create 59 --data @table.json ({ name, description?, columns })',\n )\n .option('--name <name>', 'Table name')\n .option('--description <text>', 'Description')\n .option('--columns <spec>', '\"Label=path[:type];...\" or JSON array, @file or -')\n .option('--data <json>', 'Full body as JSON, @file or -; flags override its fields')\n .action(async (campaignId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const body: Record<string, unknown> = opts.data ? readJsonArg(opts.data, '--data') : {};\n if (opts.name) body.name = opts.name;\n if (opts.description) body.description = opts.description;\n if (opts.columns) body.columns = parseColumns(opts.columns);\n if (!body.name) throw new Error('--name is required');\n if (!Array.isArray(body.columns) || body.columns.length === 0) throw new Error('--columns is required');\n const data = await call(satvoltClient(global), 'post', `/campaigns/${parseId(campaignId, 'campaignId')}/export-tables`, { data: body });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('update <tableId>')\n .description(\n 'Replace a table (PUT): name and the full columns list are required. Keep column ids\\n' +\n 'from `export-tables get` to preserve them.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables get 6650... --save table.json # edit, then:\\n' +\n ' suntropy satvolt export-tables update 6650... --data @table.json',\n )\n .requiredOption('--data <json>', '{ name, description?, columns } as JSON, @file or -')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const body = readJsonArg(opts.data, '--data');\n output(await call(satvoltClient(global), 'put', `/export-tables/${tableId}`, { data: body }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('patch <tableId>')\n .summary('Change the name, description or the whole column list.')\n .description(\n 'Change the name, the description or the whole column list. To add, edit, move or\\n' +\n 'remove single columns use `export-tables columns`.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables patch 6650... --name \"CRM v2\"',\n )\n .option('--name <name>', 'New name')\n .option('--description <text>', 'New description')\n .option('--columns <spec>', 'Replace all columns: \"Label=path[:type];...\" or JSON')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const body: Record<string, unknown> = {};\n if (opts.name) body.name = opts.name;\n if (opts.description !== undefined) body.description = opts.description;\n if (opts.columns) body.columns = parseColumns(opts.columns);\n if (Object.keys(body).length === 0) throw new Error('Nothing to change');\n output(await call(satvoltClient(global), 'patch', `/export-tables/${tableId}`, { data: body }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n registerColumnCommands(tables);\n\n tables\n .command('delete <tableId>')\n .description('Delete an export table.')\n .action(async (tableId) => {\n const global = getGlobalOpts(tables);\n try {\n output(await call(satvoltClient(global), 'delete', `/export-tables/${tableId}`), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('duplicate <tableId>')\n .description('Copy a table (its columns) into another campaign.')\n .requiredOption('--campaign <campaignId>', 'Target campaign')\n .option('--name <name>', 'Name of the copy (default: same name)')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const data = await call(satvoltClient(global), 'post', `/export-tables/${tableId}/duplicate`, {\n data: { targetCampaignId: parseId(opts.campaign, '--campaign'), name: opts.name },\n });\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('data <tableId>')\n .description(\n 'Read table rows page by page, one object per lead keyed by column label.\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables data 6650... --limit 100 --format csv',\n )\n .option('--limit <n>', 'Page size (max 500)', '50')\n .option('--offset <n>', 'Skip rows', '0')\n .option('--search <text>', 'Name, address or phone contains')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const page = await call(satvoltClient(global), 'get', `/export-tables/${tableId}/data`, {\n params: { limit: opts.limit, offset: opts.offset, search: opts.search },\n });\n const columns = page.columns as Column[];\n const rows = (page.items as Array<{ idLead: number; values: Record<string, unknown> }>).map((r) => {\n const row: Record<string, unknown> = { 'Lead ID': r.idLead };\n for (const c of columns) row[c.label] = r.values[c.id] ?? null;\n return row;\n });\n // CSV: solo las filas (el sobre paginado no se puede aplanar).\n if (global.format === 'csv') output(rows, global);\n else outputPaginated(rows, page.total, page.limit, page.offset, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n tables\n .command('export <tableId>')\n .description(\n 'Download every row of the table (up to 100k) as XLSX or CSV (UTF-8 with BOM).\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables export 6650... --file-format csv --out leads.csv',\n )\n .option('--file-format <format>', 'xlsx | csv', 'xlsx')\n .option('--out <path>', 'Output file (default: the name suggested by the server, in the current directory)')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const format = String(opts.fileFormat).toLowerCase();\n if (format !== 'xlsx' && format !== 'csv') throw new Error('--file-format must be xlsx or csv');\n const client = satvoltClient(global, 300000);\n const res = await client.get<ArrayBuffer>(`/export-tables/${tableId}/export`, {\n params: { format },\n responseType: 'arraybuffer',\n });\n const disposition = String(res.headers['content-disposition'] ?? '');\n const suggested = /filename=\"([^\"]+)\"/.exec(disposition)?.[1] ?? `export-${tableId}.${format}`;\n const path = resolve(opts.out ?? suggested);\n const buffer = Buffer.from(res.data);\n writeFileSync(path, buffer);\n output(\n {\n saved: path,\n format,\n bytes: buffer.length,\n rows: res.headers['x-row-count'] !== undefined ? Number(res.headers['x-row-count']) : null,\n },\n global,\n );\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n\nconst normalizeLabel = (s: string) =>\n s.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').trim().toLowerCase();\n\n/** Column by id, or by label (ignoring case and accents) when no id matches. */\nfunction resolveColumn(columns: Column[], ref: string): Column {\n const byId = columns.find((c) => c.id === ref);\n if (byId) return byId;\n const byLabel = columns.filter((c) => normalizeLabel(c.label) === normalizeLabel(ref));\n if (byLabel.length === 1) return byLabel[0];\n if (byLabel.length > 1) {\n throw new Error(`Label \"${ref}\" matches several columns; use one of the ids: ${byLabel.map((c) => c.id).join(', ')}`);\n }\n throw new Error(\n `No column \"${ref}\". Columns: ${columns.map((c) => `${c.id} (${c.label})`).join(', ') || '(none)'}`,\n );\n}\n\n/**\n * 0-based position for the API from --position, --before or --after. `moving`\n * is the column being moved: positions count the other columns.\n */\nfunction targetPosition(\n columns: Column[],\n opts: { position?: string; before?: string; after?: string },\n moving?: Column,\n): number | undefined {\n const given = [opts.position, opts.before, opts.after].filter((v) => v !== undefined).length;\n if (given > 1) throw new Error('Use only one of --position, --before or --after');\n if (opts.position !== undefined) return parseIntOption(opts.position, '--position');\n const anchorRef = opts.before ?? opts.after;\n if (anchorRef === undefined) return undefined;\n const others = columns.filter((c) => c.id !== moving?.id);\n const anchor = resolveColumn(others, anchorRef);\n const index = others.findIndex((c) => c.id === anchor.id);\n return opts.before !== undefined ? index : index + 1;\n}\n\nfunction registerColumnCommands(tables: Command): void {\n const columns = tables\n .command('columns')\n .summary('Add, edit, move, reorder or remove single columns of an export table.')\n .description(\n 'Edit one column at a time without resending the whole list. Columns are referenced\\n' +\n 'by id or by label (case and accents ignored; if two share a label, use the id).\\n' +\n 'Positions are 0-based (0 = first column). Each change returns { table, column, warnings }.\\n' +\n 'Find paths with: suntropy satvolt export-tables fields <campaignId>',\n );\n\n const list = async (client: ReturnType<typeof satvoltClient>, tableId: string): Promise<Column[]> =>\n call(client, 'get', `/export-tables/${tableId}/columns`);\n\n columns\n .command('list <tableId>')\n .description('List the columns of a table in order, with their position.')\n .action(async (tableId) => {\n const global = getGlobalOpts(tables);\n try {\n const cols = await list(satvoltClient(global), tableId);\n output(cols.map((c, position) => ({ position, ...c })), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n columns\n .command('add <tableId>')\n .summary('Add one or more columns, optionally at a position.')\n .description(\n 'Add a column (at the end unless --position, --before or --after). Without --type the\\n' +\n 'server uses the type the pipeline step declares for the path, or string. --columns adds\\n' +\n 'several at once.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt export-tables columns add 6650... --label \"Consumo kWh\" --path fullData.consumptionEstimate.annualKwh\\n' +\n ' suntropy satvolt export-tables columns add 6650... --label CIF --path fullData.cif.response.cif --after Empresa\\n' +\n ' suntropy satvolt export-tables columns add 6650... --columns \"Web=lead.url:url;Teléfono=lead.phone\"',\n )\n .option('--label <label>', 'Column header')\n .option('--path <path>', 'lead.<column>, fullData.<path> or synthetic.googleMapsUrl')\n .option('--type <type>', 'string | number | boolean | date | url')\n .option('--id <id>', 'Column id (letters, digits, _ or -); generated when omitted')\n .option('--columns <spec>', 'Several columns: \"Label=path[:type];...\" or JSON array')\n .option('--position <n>', '0-based position')\n .option('--before <column>', 'Insert before this column (id or label)')\n .option('--after <column>', 'Insert after this column (id or label)')\n .action(async (tableId, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const client = satvoltClient(global);\n const specs: Array<Record<string, unknown>> = opts.columns\n ? (parseColumns(opts.columns) as Array<Record<string, unknown>>)\n : [{ label: opts.label, path: opts.path, ...(opts.type ? { type: opts.type } : {}), ...(opts.id ? { id: opts.id } : {}) }];\n if (opts.columns && (opts.label || opts.path || opts.type || opts.id)) {\n throw new Error('--columns cannot be combined with --label/--path/--type/--id');\n }\n if (specs.some((c) => !c.label || !c.path)) throw new Error('--label and --path are required (or --columns)');\n let position = targetPosition(await list(client, tableId), opts);\n let result: { table: unknown; column: unknown; warnings: unknown[] } | undefined;\n const added: unknown[] = [];\n const warnings: unknown[] = [];\n for (const spec of specs) {\n result = await call(client, 'post', `/export-tables/${tableId}/columns`, {\n data: { ...spec, ...(position !== undefined ? { position } : {}) },\n });\n added.push(result!.column);\n warnings.push(...(result!.warnings ?? []));\n if (position !== undefined) position++;\n }\n output(specs.length === 1 ? result : { table: result!.table, columns: added, warnings }, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n columns\n .command('set <tableId> <column>')\n .summary('Change the label, path, type or position of one column.')\n .description(\n 'Change the label, path, type and/or position of one column (id or label). What is not\\n' +\n 'given stays the same; changing the path keeps the type unless --type is given.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt export-tables columns set 6650... \"Consumo kWh\" --label \"Consumo anual (kWh)\"\\n' +\n ' suntropy satvolt export-tables columns set 6650... c_1a2b3c4d --path fullData.cif.response.revenue.value --type number',\n )\n .option('--label <label>', 'New header')\n .option('--path <path>', 'New data path')\n .option('--type <type>', 'string | number | boolean | date | url')\n .option('--position <n>', 'Move to this 0-based position')\n .option('--before <column>', 'Move before this column')\n .option('--after <column>', 'Move after this column')\n .action(async (tableId, columnRef, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const client = satvoltClient(global);\n const cols = await list(client, tableId);\n const column = resolveColumn(cols, columnRef);\n const position = targetPosition(cols, opts, column);\n const body: Record<string, unknown> = {};\n if (opts.label !== undefined) body.label = opts.label;\n if (opts.path !== undefined) body.path = opts.path;\n if (opts.type !== undefined) body.type = opts.type;\n if (position !== undefined) body.position = position;\n if (Object.keys(body).length === 0) throw new Error('Nothing to change: give --label, --path, --type or a position');\n output(await call(client, 'patch', `/export-tables/${tableId}/columns/${encodeURIComponent(column.id)}`, { data: body }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n columns\n .command('move <tableId> <column>')\n .summary('Move one column to a position, or before/after another.')\n .description(\n 'Move one column to a 0-based position, or before/after another column.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt export-tables columns move 6650... Maps --position 0\\n' +\n ' suntropy satvolt export-tables columns move 6650... CIF --after Empresa',\n )\n .option('--position <n>', '0-based position')\n .option('--before <column>', 'Move before this column')\n .option('--after <column>', 'Move after this column')\n .action(async (tableId, columnRef, opts) => {\n const global = getGlobalOpts(tables);\n try {\n const client = satvoltClient(global);\n const cols = await list(client, tableId);\n const column = resolveColumn(cols, columnRef);\n const position = targetPosition(cols, opts, column);\n if (position === undefined) throw new Error('Give --position, --before or --after');\n output(\n await call(client, 'patch', `/export-tables/${tableId}/columns/${encodeURIComponent(column.id)}`, { data: { position } }),\n global,\n );\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n columns\n .command('reorder <tableId> <columns...>')\n .description(\n 'Set the order of all columns at once (ids or labels, every column exactly once).\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables columns reorder 6650... Empresa CIF Teléfono Maps',\n )\n .action(async (tableId, refs: string[]) => {\n const global = getGlobalOpts(tables);\n try {\n const client = satvoltClient(global);\n const cols = await list(client, tableId);\n const columnIds = refs.map((ref) => resolveColumn(cols, ref).id);\n output(await call(client, 'put', `/export-tables/${tableId}/columns/order`, { data: { columnIds } }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n columns\n .command('remove <tableId> <columns...>')\n .summary('Remove one or more columns (ids or labels).')\n .description(\n 'Remove one or more columns (ids or labels).\\n' +\n 'Example:\\n' +\n ' suntropy satvolt export-tables columns remove 6650... Maps c_1a2b3c4d',\n )\n .action(async (tableId, refs: string[]) => {\n const global = getGlobalOpts(tables);\n try {\n const client = satvoltClient(global);\n const cols = await list(client, tableId);\n const targets = [...new Map(refs.map((ref) => resolveColumn(cols, ref)).map((c) => [c.id, c])).values()];\n let result: { table: unknown } | undefined;\n for (const column of targets) {\n result = await call(client, 'delete', `/export-tables/${tableId}/columns/${encodeURIComponent(column.id)}`);\n }\n output({ table: result!.table, removed: targets }, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { output, outputError } from '../../output.js';\nimport {\n call,\n getGlobalOpts,\n parseId,\n parseIntOption,\n readJsonArg,\n satvoltClient,\n satvoltError,\n} from './api.js';\n\nconst TEMPLATE_LIST_FIELDS = 'id,name,description,steps,businessGroups,searchQuery,maxLeads,sourceCampaignId';\n\nconst splitList = (value: string) => value.split(',').map((s) => s.trim()).filter(Boolean);\nconst templatePath = (idOrName: string) => `/campaign-templates/${encodeURIComponent(idOrName)}`;\n\n/**\n * `satvolt templates`: reusable campaign configuration (pipeline steps, business\n * groups, description, search query and lead limit) without name or area.\n */\nexport function registerSatvoltTemplateCommands(satvolt: Command): void {\n const templates = satvolt\n .command('templates')\n .summary('Campaign templates: reuse a pipeline for probes, final campaigns or new areas.')\n .description(\n 'Campaign templates keep everything that defines a campaign except its name and area:\\n' +\n 'pipeline steps (with their uids), business groups, configuration description, search\\n' +\n 'query and lead limit. Reference them by id or by exact name.\\n' +\n 'Typical flow:\\n' +\n ' satvolt templates create --name \"Greenvolt industria\" --from-campaign 62\\n' +\n ' satvolt campaigns create --name \"Sonda Elche\" --template \"Greenvolt industria\" \\\\\\n' +\n ' --circle 38.29,-0.61 --radius 3000 --max-leads 50',\n );\n\n templates\n .command('list')\n .description('List the campaign templates of your company.')\n .option('--search <text>', 'Filter by name')\n .action(async (opts) => {\n const global = getGlobalOpts(templates);\n try {\n const data = await call<any[]>(satvoltClient(global), 'get', '/campaign-templates', {\n params: { search: opts.search },\n });\n if (global.format === 'human' && !global.fields) {\n output(\n data.map((t) => ({ ...t, steps: t.steps.map((s: any) => s.action).join(' → '), businessGroups: t.businessGroups.join(',') })),\n { ...global, fields: TEMPLATE_LIST_FIELDS },\n );\n return;\n }\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n templates\n .command('get <idOrName>')\n .description('Template detail, with its full steps and config.')\n .action(async (idOrName) => {\n const global = getGlobalOpts(templates);\n try {\n output(await call(satvoltClient(global), 'get', templatePath(idOrName)), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n templates\n .command('create')\n .summary('Create a template from a campaign or from JSON steps.')\n .description(\n 'Create a template from a campaign (--from-campaign) or from JSON steps.\\n' +\n 'Steps are LEAD steps, validated like `campaigns create` (defaults filled, missing\\n' +\n 'dependencies added). Business groups default to \"businesses\".\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt templates create --name \"Greenvolt industria\" --from-campaign 62\\n' +\n ' suntropy satvolt templates create --name \"Solo tejados\" --steps \\'[{\"action\":\"FIND_ROOFTOP\"}]\\' --max-leads 100\\n' +\n ' suntropy satvolt templates create --data @template.json',\n )\n .option('--name <name>', 'Template name (unique in your company)')\n .option('--description <text>', 'What the template is for')\n .option('--from-campaign <id>', 'Copy the configuration of this Maps campaign')\n .option('--steps <json>', 'LEAD steps as JSON array, @file or -')\n .option('--business-groups <ids>', 'Comma-separated business group ids')\n .option('--configuration-description <text>', 'Natural language description copied to campaigns')\n .option('--search-query <text>', 'Places text search query')\n .option('--max-leads <n>', 'Default lead limit of campaigns created from it')\n .option('--data <json>', 'Full request body (JSON, @file or -); flags override its fields')\n .action(async (opts) => {\n const global = getGlobalOpts(templates);\n try {\n const body: Record<string, unknown> = opts.data ? readJsonArg(opts.data, '--data') : {};\n if (opts.name) body.name = opts.name;\n if (opts.description !== undefined) body.description = opts.description;\n if (opts.fromCampaign) body.fromCampaignId = parseId(opts.fromCampaign, '--from-campaign');\n if (opts.steps) body.steps = readJsonArg(opts.steps, '--steps');\n if (opts.businessGroups) body.businessGroups = splitList(opts.businessGroups);\n if (opts.configurationDescription !== undefined) body.configurationDescription = opts.configurationDescription;\n if (opts.searchQuery) body.searchQuery = opts.searchQuery;\n if (opts.maxLeads !== undefined) body.maxLeads = parseIntOption(opts.maxLeads, '--max-leads');\n if (!body.name) throw new Error('--name is required');\n if (body.fromCampaignId === undefined && body.steps === undefined) {\n throw new Error('Pass --from-campaign <id> or --steps <json>');\n }\n output(await call(satvoltClient(global), 'post', '/campaign-templates', { data: body }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n templates\n .command('update <idOrName>')\n .summary('Replace a whole template (PUT).')\n .description(\n 'Replace a template (PUT). The body is the whole template: steps are required and\\n' +\n 'omitted fields are cleared. Tip: `templates get <id> --save t.json`, edit, update.',\n )\n .requiredOption('--data <json>', 'Template body (JSON, @file or -)')\n .action(async (idOrName, opts) => {\n const global = getGlobalOpts(templates);\n try {\n output(\n await call(satvoltClient(global), 'put', templatePath(idOrName), { data: readJsonArg(opts.data, '--data') }),\n global,\n );\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n templates\n .command('patch <idOrName>')\n .summary('Change some fields or steps of a template.')\n .description(\n 'Change some fields of a template. --steps takes step patches by uid, like\\n' +\n '`config patch`: {uid, config} merges (null resets a key to its default),\\n' +\n '{uid, remove: true} deletes, {action, config} without uid adds a step.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt templates patch \"Greenvolt industria\" --max-leads 500\\n' +\n ' suntropy satvolt templates patch \"Greenvolt industria\" --no-max-leads --business-groups businesses\\n' +\n ' suntropy satvolt templates patch <id> --steps \\'[{\"uid\":\"8771dae3f9637027\",\"config\":{\"tariffTemplate\":\"6.1TD\"}}]\\'',\n )\n .option('--name <name>', 'Rename the template')\n .option('--description <text>', 'New description')\n .option('--steps <json>', 'Step patches as JSON array, @file or -')\n .option('--business-groups <ids>', 'Comma-separated business group ids (empty string: no filter)')\n .option('--configuration-description <text>', 'Natural language description copied to campaigns')\n .option('--search-query <text>', 'Places text search query (empty string removes it)')\n .option('--max-leads <n>', 'Default lead limit')\n .option('--no-max-leads', 'Remove the default lead limit')\n .option('--data <json>', 'Patch body (JSON, @file or -); flags override its fields')\n .action(async (idOrName, opts) => {\n const global = getGlobalOpts(templates);\n try {\n const body: Record<string, unknown> = opts.data ? readJsonArg(opts.data, '--data') : {};\n if (opts.name) body.name = opts.name;\n if (opts.description !== undefined) body.description = opts.description;\n if (opts.steps) body.steps = readJsonArg(opts.steps, '--steps');\n if (opts.businessGroups !== undefined) body.businessGroups = splitList(opts.businessGroups);\n if (opts.configurationDescription !== undefined) body.configurationDescription = opts.configurationDescription;\n if (opts.searchQuery !== undefined) body.searchQuery = opts.searchQuery === '' ? null : opts.searchQuery;\n // commander: --max-leads <n> sets a string, --no-max-leads sets false.\n if (opts.maxLeads === false) body.maxLeads = null;\n else if (opts.maxLeads !== undefined && opts.maxLeads !== true) body.maxLeads = parseIntOption(opts.maxLeads, '--max-leads');\n if (Object.keys(body).length === 0) throw new Error('Nothing to change: pass at least one option');\n output(await call(satvoltClient(global), 'patch', templatePath(idOrName), { data: body }), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n templates\n .command('delete <idOrName>')\n .description('Delete a template. Campaigns created from it are not affected.')\n .option('--yes', 'Confirm the deletion (required)')\n .action(async (idOrName, opts) => {\n const global = getGlobalOpts(templates);\n try {\n if (!opts.yes) throw new Error('Re-run with --yes to delete the template.');\n output(await call(satvoltClient(global), 'delete', templatePath(idOrName)), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n}\n","import { Command } from 'commander';\nimport { output, outputError } from '../../output.js';\nimport { call, getGlobalOpts, satvoltClient, satvoltError, SATVOLT_DEV_BASE_URL } from './api.js';\nimport { registerSatvoltCampaignCommands } from './campaigns.js';\nimport { registerSatvoltPipelineCommands } from './pipeline.js';\nimport { registerSatvoltLeadCommands } from './leads.js';\nimport { registerSatvoltExportTableCommands } from './export-tables.js';\nimport { registerSatvoltTemplateCommands } from './templates.js';\n\nexport function registerSatvoltCommands(program: Command): void {\n const satvolt = program\n .command('satvolt')\n .description(\n 'Satvolt lead-generation campaigns (public API /satvolt/api/v1), with the same auth token.\\n' +\n `Preliminary testing phase: every call is pinned to the dev cluster (${SATVOLT_DEV_BASE_URL}),\\n` +\n 'whatever the active profile says. Override with SUNTROPY_SATVOLT_URL, or use a localhost server.\\n' +\n 'Typical flow:\\n' +\n ' satvolt catalog actions actions and their config schema\\n' +\n ' satvolt campaigns create --circle ... --steps @steps.json\\n' +\n ' satvolt campaigns start <id> · satvolt campaigns logs <id> --follow\\n' +\n ' satvolt campaigns funnel <id> · satvolt leads list <id> --step QUALIFY\\n' +\n ' satvolt export-tables create <id> ... · satvolt export-tables export <tableId>\\n' +\n ' satvolt campaigns resume <id> --action AI_AGENT --config @step.json\\n' +\n ' satvolt templates create --name <n> --from-campaign <id> · campaigns create --template <n>\\n' +\n ' satvolt campaigns extend <id> --max-leads N · leads run-step <id> <leadId> <step>\\n' +\n ' satvolt campaigns pause <id> · unpause <id> · cancel <id> --yes\\n' +\n ' satvolt usage [--month YYYY-MM] credits spent by the account this month',\n );\n\n registerSatvoltCampaignCommands(satvolt);\n registerSatvoltPipelineCommands(satvolt);\n registerSatvoltLeadCommands(satvolt);\n registerSatvoltExportTableCommands(satvolt);\n registerSatvoltTemplateCommands(satvolt);\n\n // --- usage (account) ---\n satvolt\n .command('usage')\n .summary('Credits spent by the whole account in a calendar month, by campaign and by step.')\n .description(\n 'Credits spent by the whole account in a calendar month (UTC): total, previous\\n' +\n 'month for comparison, and the breakdown by campaign and by step. It sums every\\n' +\n 'charge in the period, including the Google Maps search (FIND_LEADS), so it\\n' +\n 'does not have to match `campaigns usage`, which reconstructs the cost of one\\n' +\n 'campaign and leaves the search out.\\n' +\n 'Examples:\\n' +\n ' suntropy satvolt usage\\n' +\n ' suntropy satvolt usage --month 2026-08 --format human',\n )\n .option('--month <YYYY-MM>', 'Month to report (default: current month)')\n .action(async (opts) => {\n const global = getGlobalOpts(satvolt);\n try {\n if (opts.month !== undefined && !/^\\d{4}-\\d{2}$/.test(String(opts.month))) {\n throw new Error('--month must be YYYY-MM, e.g. 2026-08');\n }\n const data = await call(satvoltClient(global, 120000), 'get', '/usage', { params: { month: opts.month } });\n if (global.format === 'human' || global.format === 'csv') {\n if (global.format === 'human') {\n process.stderr.write(\n `${data.month}: ${data.credits} credits · ${data.executions} executions · previous month (${data.previous.month}): ${data.previous.credits} credits\\n\\n`,\n );\n }\n output(data.byCampaign, global);\n return;\n }\n output(data, global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n\n const catalog = satvolt\n .command('catalog')\n .description('Reference data for building campaigns and pipelines.');\n\n const catalogEntries: Array<[string, string, string]> = [\n ['actions', '/catalog/actions', 'Pipeline actions: credits per lead (fixed per action; failed or skipped runs are free), dependencies, multiple, and the JSON Schema of their config (the input). The data each step writes: satvolt export-tables fields <campaignId>.'],\n ['ai-agents', '/catalog/ai-agents', 'AI agents allowed in AI_AGENT config.agentId: id, name and description. Every agent costs the AI_AGENT credits.'],\n ['business-groups', '/catalog/business-groups', 'Business category groups for --business-groups.'],\n ['states', '/catalog/states', 'Campaign and lead states.'],\n ];\n for (const [name, path, description] of catalogEntries) {\n catalog\n .command(name)\n .description(description)\n .action(async () => {\n const global = getGlobalOpts(catalog);\n try {\n output(await call(satvoltClient(global), 'get', path), global);\n } catch (err) {\n outputError(satvoltError(err));\n }\n });\n }\n\n addSummaries(satvolt);\n}\n\n/**\n * Commander lists subcommands with their whole description, so multi-line ones\n * (with examples) break the command list. Use the first line as the summary\n * when a command does not set one.\n */\nfunction addSummaries(cmd: Command): void {\n for (const sub of cmd.commands) {\n const description = sub.description();\n if (!sub.summary() && description.includes('\\n')) {\n const first = description.split('\\n')[0].trim();\n sub.summary(/[.:)]$/.test(first) ? first.replace(/:$/, '.') : `${first}…`);\n }\n addSummaries(sub);\n }\n}\n","import type { Command } from 'commander';\nimport { loadConfig, saveConfig } from './config.js';\n\n/**\n * Command access profiles (\"permission tiers\").\n *\n * The CLI can be locked to a permission tier so that only a subset of commands\n * is registered. Tiers are CUMULATIVE:\n *\n * read ⊂ write (read + write) ⊂ delete (read + write + delete = full)\n *\n * Commands above the active tier are pruned from the command tree before\n * parsing, so they (a) never appear in `--help` and (b) when invoked, Commander\n * reports them natively as `error: unknown command 'X'` — i.e. \"the command\n * does not exist\". This is an admin/automation control (e.g. to constrain the\n * Alexandria agent's sandbox to read-only). It is intentionally not advertised\n * in the user-facing help; it is driven by the hidden `command-profile` command\n * or the SUNTROPY_COMMAND_PROFILE environment variable.\n */\nexport type CommandTier = 'read' | 'write' | 'delete';\n\nexport const COMMAND_TIERS: CommandTier[] = ['read', 'write', 'delete'];\n\nconst TIER_VALUE: Record<CommandTier, number> = { read: 0, write: 1, delete: 2 };\n\n/** Default when nothing is configured: full access (legacy behavior). */\nexport const DEFAULT_TIER: CommandTier = 'delete';\n\nexport const ENV_VAR = 'SUNTROPY_COMMAND_PROFILE';\n\nexport function tierValue(t: CommandTier): number {\n return TIER_VALUE[t];\n}\n\nexport function isValidTier(value: unknown): value is CommandTier {\n return typeof value === 'string' && (COMMAND_TIERS as string[]).includes(value);\n}\n\nexport interface ResolvedCommandProfile {\n tier: CommandTier;\n source: 'env' | 'config' | 'default';\n /** Raw env value when present but invalid (for diagnostics). */\n invalidEnv?: string;\n}\n\n/**\n * Resolve the active tier. Precedence: env var > config file > default.\n * Pure (no side effects) so it can be called from both the gating step and the\n * `command-profile` status command.\n */\nexport function getActiveCommandProfile(): ResolvedCommandProfile {\n const envRaw = process.env[ENV_VAR]?.trim();\n if (envRaw) {\n const envNorm = envRaw.toLowerCase();\n if (isValidTier(envNorm)) return { tier: envNorm, source: 'env' };\n // Invalid env value: fall through to config/default but report it.\n const fallback = resolveFromConfig();\n return { ...fallback, invalidEnv: envRaw };\n }\n return resolveFromConfig();\n}\n\nfunction resolveFromConfig(): ResolvedCommandProfile {\n try {\n const cfg = loadConfig();\n if (isValidTier(cfg.commandProfile)) return { tier: cfg.commandProfile, source: 'config' };\n } catch {\n // ignore: fall back to default\n }\n return { tier: DEFAULT_TIER, source: 'default' };\n}\n\n/** Persist (or clear, when null) the stored command profile. */\nexport function setStoredCommandProfile(tier: CommandTier | null): void {\n const cfg = loadConfig();\n if (tier === null) delete cfg.commandProfile;\n else cfg.commandProfile = tier;\n saveConfig(cfg);\n}\n\n// ─── Classification ───────────────────────────────────────────────────────\n//\n// A command's tier is the MAX tier over the verbs in its path. Verbs are the\n// command/group names, so e.g. `studies set name` inherits `write` from `set`,\n// and `inventory kits panels delete` inherits `delete` from `delete`.\n\n// `reset` wipes a Satvolt campaign's leads and processing data, so it is destructive.\nconst DELETE_VERBS = new Set(['delete', 'delete-batch', 'archive', 'reset']);\n\nconst WRITE_VERBS = new Set([\n 'create', 'update', 'edit', 'set', 'add', 'remove', 'assemble', 'featured',\n 'save', 'init', 'init-default', 'add-comment', 'comment', 'send',\n 'calculate-results', 'optimize-peakpower',\n // satvolt: these launch pipeline work (spending credits) or change configuration.\n 'patch', 'start', 'resume', 'run', 'run-step', 'duplicate', 'extend', 'move', 'reorder',\n 'pause', 'unpause', 'cancel',\n]);\n\n/**\n * Explicit overrides for paths whose verbs are ambiguous. `studies calculate\n * production` writes to the local draft (write), but the bare verb `calculate`\n * is also used by pure-compute commands (`ppa calculate`, `solarform calculate`,\n * `studies calculate-production`) that are read-only — so `calculate` is NOT a\n * global write verb; this path is pinned instead.\n */\nconst PATH_OVERRIDES: Record<string, CommandTier> = {\n 'studies calculate production': 'write',\n};\n\nexport function classifyPath(segs: string[]): CommandTier {\n const key = segs.join(' ');\n if (PATH_OVERRIDES[key]) return PATH_OVERRIDES[key];\n let tier: CommandTier = 'read';\n for (const seg of segs) {\n if (DELETE_VERBS.has(seg)) return 'delete';\n if (WRITE_VERBS.has(seg)) tier = 'write';\n }\n return tier;\n}\n\n// ─── Exemptions ───────────────────────────────────────────────────────────\n//\n// CLI plumbing that must always work regardless of the active tier: you always\n// need to authenticate, configure the CLI, and manage the command profile\n// itself. NOTE: only the *local* `config` leaves are exempt — the tenant\n// configuration subtrees (`config theme`, `config solarform …`) hit the backend\n// and are gated like any other business command.\n\nconst EXEMPT_CONFIG_LEAVES = new Set(['set', 'get', 'list', 'create-profile', 'use']);\n\nexport function isExemptPath(segs: string[]): boolean {\n if (segs[0] === 'auth') return true;\n if (segs[0] === 'command-profile') return true;\n if (segs[0] === 'config' && segs.length === 2 && EXEMPT_CONFIG_LEAVES.has(segs[1])) return true;\n return false;\n}\n\n// ─── Pruning ──────────────────────────────────────────────────────────────\n\n/**\n * Prune the command tree in place according to the active command profile.\n * Returns the resolved tier so the caller can surface it if needed.\n */\nexport function applyCommandProfile(program: Command): ResolvedCommandProfile {\n const resolved = getActiveCommandProfile();\n pruneChildren(program, [], tierValue(resolved.tier));\n return resolved;\n}\n\nfunction pruneChildren(parent: Command, parentSegs: string[], max: number): void {\n const kept = parent.commands.filter((child) => {\n const segs = [...parentSegs, child.name()];\n return keepCommand(child, segs, max);\n });\n // Commander types `commands` as readonly, but pruning must replace its\n // contents. Mutate the array in place (rather than reassigning the property)\n // so Commander keeps using the same reference for help and dispatch.\n const mutable = parent.commands as Command[];\n mutable.length = 0;\n mutable.push(...kept);\n}\n\nfunction keepCommand(cmd: Command, segs: string[], max: number): boolean {\n if (cmd.commands.length > 0) {\n // Group: prune its descendants first, then keep it only if something\n // survived (or it's an exempt subtree).\n pruneChildren(cmd, segs, max);\n if (cmd.commands.length > 0) return true;\n return isExemptPath(segs);\n }\n // Leaf:\n if (isExemptPath(segs)) return true;\n return tierValue(classifyPath(segs)) <= max;\n}\n","import { Command } from 'commander';\nimport { output, outputError, type OutputOptions } from '../output.js';\nimport {\n COMMAND_TIERS,\n DEFAULT_TIER,\n ENV_VAR,\n getActiveCommandProfile,\n isValidTier,\n setStoredCommandProfile,\n} from '../access.js';\n\nfunction getGlobalOpts(cmd: Command): OutputOptions {\n let root = cmd;\n while (root.parent) root = root.parent;\n return root.opts() as OutputOptions;\n}\n\n/**\n * Hidden admin command to manage the CLI command access profile (permission\n * tier). Registered with `{ hidden: true }` so it never shows in `--help`, but\n * remains invocable in any tier (it is exempt from gating). Changes take effect\n * on the next invocation, since gating happens at startup.\n *\n * suntropy command-profile show the active tier + source\n * suntropy command-profile read lock the CLI to read-only\n * suntropy command-profile write allow read + write\n * suntropy command-profile delete allow everything (default)\n * suntropy command-profile reset clear the stored value (back to default)\n */\nexport function registerCommandProfileCommand(program: Command): void {\n program\n .command('command-profile [tier]', { hidden: true })\n .description('Admin: get/set the command access profile (read | write | delete | reset)')\n .action((tier?: string) => {\n try {\n const global = getGlobalOpts(program);\n\n // No argument → report current state.\n if (!tier) {\n const resolved = getActiveCommandProfile();\n output(\n {\n commandProfile: resolved.tier,\n source: resolved.source,\n ...(resolved.invalidEnv\n ? { warning: `Ignoring invalid ${ENV_VAR}=\"${resolved.invalidEnv}\" (expected: ${COMMAND_TIERS.join(' | ')})` }\n : {}),\n available: COMMAND_TIERS,\n envVar: ENV_VAR,\n },\n global,\n );\n return;\n }\n\n const value = tier.trim().toLowerCase();\n\n if (value === 'reset') {\n setStoredCommandProfile(null);\n const resolved = getActiveCommandProfile();\n output(\n {\n success: true,\n message: `Stored command profile cleared. Effective tier: ${resolved.tier} (${resolved.source}).`,\n commandProfile: resolved.tier,\n source: resolved.source,\n },\n global,\n );\n return;\n }\n\n if (!isValidTier(value)) {\n outputError(new Error(`Invalid tier \"${tier}\". Expected one of: ${COMMAND_TIERS.join(', ')}, or \"reset\".`));\n return;\n }\n\n setStoredCommandProfile(value);\n const envOverride = getActiveCommandProfile();\n const message =\n envOverride.source === 'env'\n ? `Stored command profile set to \"${value}\", but ${ENV_VAR}=\"${process.env[ENV_VAR]}\" overrides it (effective: ${envOverride.tier}). Unset the env var for the stored value to apply.`\n : `Command profile set to \"${value}\". Takes effect on the next command.`;\n output(\n {\n success: true,\n commandProfile: value,\n effectiveTier: envOverride.tier,\n effectiveSource: envOverride.source,\n default: DEFAULT_TIER,\n message,\n },\n global,\n );\n } catch (err) {\n outputError(err);\n }\n });\n}\n","import { createProgram } from '../src/index.js';\n\nconst program = createProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n process.stderr.write(JSON.stringify({ error: true, message: err.message }) + '\\n');\n process.exit(1);\n});\n"],"mappings":"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","names":["Command","writeFileSync","program","hadToken","readFileSync","writeFileSync","join","getGlobalOpts","getGlobalOpts","getGlobalOpts","getGlobalOpts","program","getGlobalOpts","readFileSync","getGlobalOpts","parseData","readFileSync","res","getGlobalOpts","getGlobalOpts","parseData","program","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","getGlobalOpts","getGlobalOpts","program","readFileSync","getGlobalOpts","resolve","readFileSync","program","readFileSync","getGlobalOpts","program","readFileSync","getGlobalOpts","readStdin","resolve","parseData","program","getGlobalOpts","readStdin","resolve","parseData","compactStudyOutput","program","res","getGlobalOpts","readStdin","resolve","parseData","program","getGlobalOpts","program","getGlobalOpts","program","Option","getGlobalOpts","program","Option","axios","readFileSync","getGlobalOpts","axios","readFileSync","chalk","getGlobalOpts","chalk","getGlobalOpts","getGlobalOpts","getGlobalOpts","writeFileSync","getGlobalOpts","writeFileSync","getGlobalOpts","program","getGlobalOpts","program","getGlobalOpts","program","program","Command"]}
|