@kolatts/pncli 5.3.0 → 5.4.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/config.ts","../src/types/jira.ts","../src/lib/validate-custom-fields.ts","../src/lib/keychain.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { execSync } from 'child_process';\nimport type { GlobalConfig, RepoConfig, ResolvedConfig, JiraDefaults, BitbucketDefaults, GitHubDefaults, SonarDefaults, SdeDefaults, AdoDefaults, JenkinsDefaults, JenkinsInstanceConfig } from '../types/config.js';\nimport type { CustomFieldDefinition } from '../types/jira.js';\nimport { assertValidCustomFields } from './validate-custom-fields.js';\nimport { resolveKeychainRefs } from './keychain.js';\n\nconst ENV_KEYS = {\n EMAIL: 'PNCLI_EMAIL',\n USERID: 'PNCLI_USERID',\n JIRA_BASE_URL: 'PNCLI_JIRA_BASE_URL',\n JIRA_API_TOKEN: 'PNCLI_JIRA_API_TOKEN',\n BITBUCKET_BASE_URL: 'PNCLI_BITBUCKET_BASE_URL',\n BITBUCKET_PAT: 'PNCLI_BITBUCKET_PAT',\n GITHUB_BASE_URL: 'PNCLI_GITHUB_BASE_URL',\n GITHUB_TOKEN: 'PNCLI_GITHUB_TOKEN',\n // Well-known vars CI platforms provide without any pncli-specific setup.\n GITHUB_TOKEN_FALLBACK: 'GITHUB_TOKEN',\n GITHUB_API_URL_FALLBACK: 'GITHUB_API_URL',\n CONFLUENCE_BASE_URL: 'PNCLI_CONFLUENCE_BASE_URL',\n CONFLUENCE_API_TOKEN: 'PNCLI_CONFLUENCE_API_TOKEN',\n ARTIFACTORY_BASE_URL: 'PNCLI_ARTIFACTORY_BASE_URL',\n ARTIFACTORY_TOKEN: 'PNCLI_ARTIFACTORY_TOKEN',\n ARTIFACTORY_REPO_NPM: 'PNCLI_ARTIFACTORY_REPO_NPM',\n ARTIFACTORY_REPO_NUGET: 'PNCLI_ARTIFACTORY_REPO_NUGET',\n ARTIFACTORY_REPO_MAVEN: 'PNCLI_ARTIFACTORY_REPO_MAVEN',\n SONAR_BASE_URL: 'PNCLI_SONAR_BASE_URL',\n SONAR_TOKEN: 'PNCLI_SONAR_TOKEN',\n // SonarSource's own scanner CLI standard var name — see the comment above GITHUB_TOKEN_FALLBACK.\n SONAR_TOKEN_FALLBACK: 'SONAR_TOKEN',\n SDE_CONNECTION: 'PNCLI_SDE_CONNECTION',\n ADO_BASE_URL: 'PNCLI_ADO_BASE_URL',\n ADO_PAT: 'PNCLI_ADO_PAT',\n // Azure Pipelines' conventional name for $(System.AccessToken) — see the comment above GITHUB_TOKEN_FALLBACK.\n ADO_PAT_FALLBACK: 'SYSTEM_ACCESSTOKEN',\n JENKINS_BASE_URL: 'PNCLI_JENKINS_BASE_URL',\n JENKINS_USERNAME: 'PNCLI_JENKINS_USERNAME',\n JENKINS_API_TOKEN: 'PNCLI_JENKINS_API_TOKEN',\n CHECKMARX_BASE_URL: 'PNCLI_CHECKMARX_BASE_URL',\n CHECKMARX_TENANT_NAME: 'PNCLI_CHECKMARX_TENANT_NAME',\n CHECKMARX_API_KEY: 'PNCLI_CHECKMARX_API_KEY',\n CHECKMARX_CLIENT_ID: 'PNCLI_CHECKMARX_CLIENT_ID',\n CHECKMARX_CLIENT_SECRET: 'PNCLI_CHECKMARX_CLIENT_SECRET',\n CONTRAST_BASE_URL: 'PNCLI_CONTRAST_BASE_URL',\n CONTRAST_ORG_UUID: 'PNCLI_CONTRAST_ORG_UUID',\n CONTRAST_API_KEY: 'PNCLI_CONTRAST_API_KEY',\n CONTRAST_SERVICE_KEY: 'PNCLI_CONTRAST_SERVICE_KEY',\n CONTRAST_USERNAME: 'PNCLI_CONTRAST_USERNAME',\n SONATYPEIQ_BASE_URL: 'PNCLI_SONATYPEIQ_BASE_URL',\n SONATYPEIQ_USER_CODE: 'PNCLI_SONATYPEIQ_USER_CODE',\n SONATYPEIQ_PASSCODE: 'PNCLI_SONATYPEIQ_PASSCODE',\n OPENSHIFT_BASE_URL: 'PNCLI_OPENSHIFT_BASE_URL',\n OPENSHIFT_TOKEN: 'PNCLI_OPENSHIFT_TOKEN',\n DYNATRACE_BASE_URL: 'PNCLI_DYNATRACE_BASE_URL',\n DYNATRACE_API_TOKEN: 'PNCLI_DYNATRACE_API_TOKEN',\n DYNATRACE_PLATFORM_URL: 'PNCLI_DYNATRACE_PLATFORM_URL',\n DYNATRACE_PLATFORM_TOKEN: 'PNCLI_DYNATRACE_PLATFORM_TOKEN',\n LOGSCALE_BASE_URL: 'PNCLI_LOGSCALE_BASE_URL',\n LOGSCALE_TOKEN: 'PNCLI_LOGSCALE_TOKEN',\n SPLITIO_BASE_URL: 'PNCLI_SPLITIO_BASE_URL',\n SPLITIO_ADMIN_API_KEY: 'PNCLI_SPLITIO_ADMIN_API_KEY',\n FIGMA_BASE_URL: 'PNCLI_FIGMA_BASE_URL',\n FIGMA_TOKEN: 'PNCLI_FIGMA_TOKEN',\n ALATION_BASE_URL: 'PNCLI_ALATION_BASE_URL',\n ALATION_REFRESH_TOKEN: 'PNCLI_ALATION_REFRESH_TOKEN',\n ALATION_USER_ID: 'PNCLI_ALATION_USER_ID',\n CONFIG_PATH: 'PNCLI_CONFIG_PATH'\n} as const;\n\nfunction getGlobalConfigPath(overridePath?: string): string {\n if (overridePath) return overridePath;\n const envPath = process.env[ENV_KEYS.CONFIG_PATH];\n if (envPath) return envPath;\n return path.join(os.homedir(), '.pncli', 'config.json');\n}\n\nfunction loadJsonFile<T>(filePath: string): T | null {\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n return JSON.parse(content) as T;\n } catch {\n return null;\n }\n}\n\nfunction getRepoRoot(): string | null {\n try {\n return execSync('git rev-parse --show-toplevel', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();\n } catch {\n return null;\n }\n}\n\nfunction parseSdeConnection(connection: string): { token: string; baseUrl: string } | null {\n const idx = connection.indexOf('@');\n if (idx <= 0) return null;\n const token = connection.slice(0, idx);\n const host = connection.slice(idx + 1);\n const baseUrl = /^https?:\\/\\//i.test(host) ? host : `https://${host}`;\n return { token, baseUrl };\n}\n\nfunction mergeCustomFields(\n global: CustomFieldDefinition[] | undefined,\n repo: CustomFieldDefinition[] | undefined\n): CustomFieldDefinition[] {\n const map = new Map<string, CustomFieldDefinition>();\n if (global != null) {\n assertValidCustomFields(global, { source: 'global config' });\n for (const f of global) map.set(f.id, f);\n }\n if (repo != null) {\n assertValidCustomFields(repo, { source: 'repo config (.pncli.json)', repo: true });\n for (const f of repo) map.set(f.id, f); // repo wins\n }\n return Array.from(map.values());\n}\n\nfunction mergeDefaults(\n global: GlobalConfig['defaults'],\n repo: RepoConfig['defaults']\n): { jira: JiraDefaults; bitbucket: BitbucketDefaults; github: GitHubDefaults; sonar: SonarDefaults; sde: SdeDefaults; ado: AdoDefaults; jenkins: JenkinsDefaults } {\n return {\n jira: { ...global?.jira, ...repo?.jira },\n bitbucket: { ...global?.bitbucket, ...repo?.bitbucket },\n github: { ...global?.github, ...repo?.github },\n sonar: { ...global?.sonar, ...repo?.sonar },\n sde: { ...global?.sde, ...repo?.sde },\n ado: { ...global?.ado, ...repo?.ado },\n jenkins: { ...global?.jenkins, ...repo?.jenkins }\n };\n}\n\n/** Secret fields and the env vars that override them (PNCLI_* first, then the CI fallback). */\nconst SECRET_ENV_OVERRIDES: [string, string[]][] = [\n ['jira.apiToken', [ENV_KEYS.JIRA_API_TOKEN]],\n ['bitbucket.pat', [ENV_KEYS.BITBUCKET_PAT]],\n ['github.token', [ENV_KEYS.GITHUB_TOKEN, ENV_KEYS.GITHUB_TOKEN_FALLBACK]],\n ['confluence.apiToken', [ENV_KEYS.CONFLUENCE_API_TOKEN]],\n ['artifactory.token', [ENV_KEYS.ARTIFACTORY_TOKEN]],\n ['sonar.token', [ENV_KEYS.SONAR_TOKEN, ENV_KEYS.SONAR_TOKEN_FALLBACK]],\n ['ado.pat', [ENV_KEYS.ADO_PAT, ENV_KEYS.ADO_PAT_FALLBACK]],\n ['jenkins.apiToken', [ENV_KEYS.JENKINS_API_TOKEN]],\n ['checkmarx.apiKey', [ENV_KEYS.CHECKMARX_API_KEY]],\n ['checkmarx.clientSecret', [ENV_KEYS.CHECKMARX_CLIENT_SECRET]],\n ['contrast.apiKey', [ENV_KEYS.CONTRAST_API_KEY]],\n ['contrast.serviceKey', [ENV_KEYS.CONTRAST_SERVICE_KEY]],\n ['sonatypeiq.passcode', [ENV_KEYS.SONATYPEIQ_PASSCODE]],\n ['openshift.token', [ENV_KEYS.OPENSHIFT_TOKEN]],\n ['dynatrace.apiToken', [ENV_KEYS.DYNATRACE_API_TOKEN]],\n ['dynatrace.platformToken', [ENV_KEYS.DYNATRACE_PLATFORM_TOKEN]],\n ['logscale.token', [ENV_KEYS.LOGSCALE_TOKEN]],\n ['splitio.adminApiKey', [ENV_KEYS.SPLITIO_ADMIN_API_KEY]],\n ['figma.token', [ENV_KEYS.FIGMA_TOKEN]],\n ['alation.refreshToken', [ENV_KEYS.ALATION_REFRESH_TOKEN]],\n];\n\n/** Config paths whose value an environment variable is currently overriding. */\nexport function envOverriddenSecretPaths(env: NodeJS.ProcessEnv = process.env): Set<string> {\n return new Set(SECRET_ENV_OVERRIDES.filter(([, keys]) => keys.some(k => env[k] !== undefined)).map(([p]) => p));\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n /** Resolve only these `keychain:` config paths (e.g. `github.token`); every other one stays unread. */\n keychainPaths?: string[];\n}\n\nexport function loadConfig(opts: LoadConfigOptions = {}): ResolvedConfig {\n const globalConfigPath = getGlobalConfigPath(opts.configPath);\n // `keychain:<account>` values are swapped for the OS-keychain secret here, below every env var\n // in precedence — env vars are read directly from process.env further down and still win, and a\n // field an env var overrides is not looked up at all.\n const globalConfig = resolveKeychainRefs(loadJsonFile<GlobalConfig>(globalConfigPath) ?? {}, undefined, {\n skipPaths: envOverriddenSecretPaths(),\n ...(opts.keychainPaths ? { onlyPaths: new Set(opts.keychainPaths) } : {})\n });\n\n const repoRoot = getRepoRoot();\n let repoConfig: RepoConfig = {};\n if (repoRoot) {\n repoConfig = loadJsonFile<RepoConfig>(path.join(repoRoot, '.pncli.json')) ?? {};\n }\n\n const mergedDefaults = mergeDefaults(globalConfig.defaults, repoConfig.defaults);\n\n return {\n user: {\n email: process.env[ENV_KEYS.EMAIL] ?? globalConfig.user?.email,\n userId: process.env[ENV_KEYS.USERID] ?? globalConfig.user?.userId\n },\n jira: {\n baseUrl: process.env[ENV_KEYS.JIRA_BASE_URL] ?? globalConfig.jira?.baseUrl,\n apiToken: process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,\n customFields: mergeCustomFields(globalConfig.jira?.customFields, repoConfig.jira?.customFields)\n },\n bitbucket: {\n baseUrl: process.env[ENV_KEYS.BITBUCKET_BASE_URL] ?? globalConfig.bitbucket?.baseUrl,\n pat: process.env[ENV_KEYS.BITBUCKET_PAT] ?? globalConfig.bitbucket?.pat\n },\n github: {\n baseUrl: process.env[ENV_KEYS.GITHUB_BASE_URL] ?? process.env[ENV_KEYS.GITHUB_API_URL_FALLBACK] ?? globalConfig.github?.baseUrl,\n token: process.env[ENV_KEYS.GITHUB_TOKEN] ?? process.env[ENV_KEYS.GITHUB_TOKEN_FALLBACK] ?? globalConfig.github?.token\n },\n confluence: {\n baseUrl: process.env[ENV_KEYS.CONFLUENCE_BASE_URL] ?? globalConfig.confluence?.baseUrl,\n apiToken: process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken\n ?? process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,\n apiTokenExplicit: !!(\n process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken\n )\n },\n artifactory: {\n baseUrl: process.env[ENV_KEYS.ARTIFACTORY_BASE_URL] ?? globalConfig.artifactory?.baseUrl,\n token: process.env[ENV_KEYS.ARTIFACTORY_TOKEN] ?? globalConfig.artifactory?.token,\n npmRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_NPM] ?? globalConfig.artifactory?.npmRepo,\n nugetRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_NUGET] ?? globalConfig.artifactory?.nugetRepo,\n mavenRepo: process.env[ENV_KEYS.ARTIFACTORY_REPO_MAVEN] ?? globalConfig.artifactory?.mavenRepo\n },\n sonar: {\n baseUrl: process.env[ENV_KEYS.SONAR_BASE_URL] ?? globalConfig.sonar?.baseUrl,\n token: process.env[ENV_KEYS.SONAR_TOKEN] ?? process.env[ENV_KEYS.SONAR_TOKEN_FALLBACK] ?? globalConfig.sonar?.token\n },\n sde: (() => {\n const raw = process.env[ENV_KEYS.SDE_CONNECTION] ?? globalConfig.sde?.connection;\n const parsed = raw ? parseSdeConnection(raw) : null;\n return { baseUrl: parsed?.baseUrl, token: parsed?.token };\n })(),\n ado: {\n baseUrl: process.env[ENV_KEYS.ADO_BASE_URL] ?? globalConfig.ado?.baseUrl,\n pat: process.env[ENV_KEYS.ADO_PAT] ?? process.env[ENV_KEYS.ADO_PAT_FALLBACK] ?? globalConfig.ado?.pat,\n fieldAliases: globalConfig.ado?.fieldAliases ?? {},\n discoveredFields: globalConfig.ado?.discoveredFields ?? [],\n discoveredTypes: globalConfig.ado?.discoveredTypes ?? []\n },\n jenkins: {\n baseUrl: repoConfig.defaults?.jenkins?.baseUrl ?? process.env[ENV_KEYS.JENKINS_BASE_URL] ?? globalConfig.jenkins?.baseUrl,\n username: process.env[ENV_KEYS.JENKINS_USERNAME] ?? globalConfig.jenkins?.username,\n apiToken: process.env[ENV_KEYS.JENKINS_API_TOKEN] ?? globalConfig.jenkins?.apiToken\n },\n jenkinsInstances: (Array.isArray(globalConfig.jenkinsInstances) ? globalConfig.jenkinsInstances : []) as JenkinsInstanceConfig[],\n checkmarx: {\n baseUrl: process.env[ENV_KEYS.CHECKMARX_BASE_URL] ?? globalConfig.checkmarx?.baseUrl,\n tenantName: process.env[ENV_KEYS.CHECKMARX_TENANT_NAME] ?? globalConfig.checkmarx?.tenantName,\n apiKey: process.env[ENV_KEYS.CHECKMARX_API_KEY] ?? globalConfig.checkmarx?.apiKey,\n clientId: process.env[ENV_KEYS.CHECKMARX_CLIENT_ID] ?? globalConfig.checkmarx?.clientId,\n clientSecret: process.env[ENV_KEYS.CHECKMARX_CLIENT_SECRET] ?? globalConfig.checkmarx?.clientSecret,\n },\n contrast: {\n baseUrl: process.env[ENV_KEYS.CONTRAST_BASE_URL] ?? globalConfig.contrast?.baseUrl,\n orgUuid: process.env[ENV_KEYS.CONTRAST_ORG_UUID] ?? globalConfig.contrast?.orgUuid,\n apiKey: process.env[ENV_KEYS.CONTRAST_API_KEY] ?? globalConfig.contrast?.apiKey,\n serviceKey: process.env[ENV_KEYS.CONTRAST_SERVICE_KEY] ?? globalConfig.contrast?.serviceKey,\n username: process.env[ENV_KEYS.CONTRAST_USERNAME] ?? globalConfig.contrast?.username,\n },\n sonatypeiq: {\n baseUrl: process.env[ENV_KEYS.SONATYPEIQ_BASE_URL] ?? globalConfig.sonatypeiq?.baseUrl,\n userCode: process.env[ENV_KEYS.SONATYPEIQ_USER_CODE] ?? globalConfig.sonatypeiq?.userCode,\n passcode: process.env[ENV_KEYS.SONATYPEIQ_PASSCODE] ?? globalConfig.sonatypeiq?.passcode,\n },\n openshift: {\n baseUrl: process.env[ENV_KEYS.OPENSHIFT_BASE_URL] ?? globalConfig.openshift?.baseUrl,\n token: process.env[ENV_KEYS.OPENSHIFT_TOKEN] ?? globalConfig.openshift?.token,\n defaultEnvironment: globalConfig.openshift?.defaultEnvironment,\n defaultInstance: globalConfig.openshift?.defaultInstance,\n environments: (typeof globalConfig.openshift?.environments === 'object' && globalConfig.openshift.environments !== null)\n ? globalConfig.openshift.environments\n : {},\n },\n dynatrace: {\n baseUrl: process.env[ENV_KEYS.DYNATRACE_BASE_URL] ?? globalConfig.dynatrace?.baseUrl,\n apiToken: process.env[ENV_KEYS.DYNATRACE_API_TOKEN] ?? globalConfig.dynatrace?.apiToken,\n platformUrl: process.env[ENV_KEYS.DYNATRACE_PLATFORM_URL] ?? globalConfig.dynatrace?.platformUrl,\n platformToken: process.env[ENV_KEYS.DYNATRACE_PLATFORM_TOKEN] ?? globalConfig.dynatrace?.platformToken,\n defaultEnvironment: globalConfig.dynatrace?.defaultEnvironment,\n environments: (typeof globalConfig.dynatrace?.environments === 'object' && globalConfig.dynatrace.environments !== null)\n ? globalConfig.dynatrace.environments\n : {},\n },\n logscale: {\n baseUrl: process.env[ENV_KEYS.LOGSCALE_BASE_URL] ?? globalConfig.logscale?.baseUrl,\n token: process.env[ENV_KEYS.LOGSCALE_TOKEN] ?? globalConfig.logscale?.token,\n },\n splitio: {\n baseUrl: process.env[ENV_KEYS.SPLITIO_BASE_URL] ?? globalConfig.splitio?.baseUrl,\n adminApiKey: process.env[ENV_KEYS.SPLITIO_ADMIN_API_KEY] ?? globalConfig.splitio?.adminApiKey,\n },\n figma: {\n baseUrl: process.env[ENV_KEYS.FIGMA_BASE_URL] ?? globalConfig.figma?.baseUrl,\n token: process.env[ENV_KEYS.FIGMA_TOKEN] ?? globalConfig.figma?.token,\n },\n alation: {\n baseUrl: process.env[ENV_KEYS.ALATION_BASE_URL] ?? globalConfig.alation?.baseUrl,\n refreshToken: process.env[ENV_KEYS.ALATION_REFRESH_TOKEN] ?? globalConfig.alation?.refreshToken,\n userId: process.env[ENV_KEYS.ALATION_USER_ID] ?? globalConfig.alation?.userId,\n },\n defaults: mergedDefaults\n };\n}\n\nexport function normalizeBaseUrl(raw: string): string {\n const trimmed = raw.trim();\n if (!trimmed) return trimmed;\n return /^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`;\n}\n\nexport function writeGlobalConfig(config: GlobalConfig, configPath?: string): void {\n const filePath = getGlobalConfigPath(configPath);\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n', 'utf8');\n}\n\nexport function writeRepoConfig(config: RepoConfig): void {\n const repoRoot = getRepoRoot();\n const targetDir = repoRoot ?? process.cwd();\n fs.writeFileSync(path.join(targetDir, '.pncli.json'), JSON.stringify(config, null, 2) + '\\n', 'utf8');\n}\n\nfunction parseConfigValue(value: string): unknown {\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed;\n }\n } catch {\n // not valid JSON — fall through to raw string\n }\n return value;\n}\n\nexport function setConfigValue(key: string, value: string, configPath?: string): void {\n const filePath = getGlobalConfigPath(configPath);\n const existing = loadJsonFile<GlobalConfig>(filePath) ?? {};\n\n const parts = key.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = existing;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {};\n }\n current = current[part];\n }\n current[parts[parts.length - 1]!] = parseConfigValue(value);\n\n writeGlobalConfig(existing, configPath);\n}\n\nexport function setRepoConfigValue(key: string, value: string): void {\n const repoRoot = getRepoRoot();\n const targetDir = repoRoot ?? process.cwd();\n const filePath = path.join(targetDir, '.pncli.json');\n const existing = loadJsonFile<RepoConfig>(filePath) ?? {};\n\n const parts = key.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = existing;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]!;\n if (typeof current[part] !== 'object' || current[part] === null) {\n current[part] = {};\n }\n current = current[part];\n }\n current[parts[parts.length - 1]!] = parseConfigValue(value);\n\n writeRepoConfig(existing);\n}\n\nexport function maskConfig(config: ResolvedConfig): unknown {\n return {\n ...config,\n jira: {\n ...config.jira,\n apiToken: config.jira.apiToken ? '***' : undefined,\n customFields: config.jira.customFields\n },\n bitbucket: {\n ...config.bitbucket,\n pat: config.bitbucket.pat ? '***' : undefined\n },\n github: {\n ...config.github,\n token: config.github.token ? '***' : undefined\n },\n confluence: {\n ...config.confluence,\n apiToken: config.confluence.apiToken ? '***' : undefined\n },\n artifactory: {\n ...config.artifactory,\n token: config.artifactory.token ? '***' : undefined\n },\n sonar: {\n ...config.sonar,\n token: config.sonar.token ? '***' : undefined\n },\n sde: {\n baseUrl: config.sde.baseUrl,\n token: config.sde.token ? '***' : undefined\n },\n ado: {\n ...config.ado,\n pat: config.ado.pat ? '***' : undefined\n },\n jenkins: {\n ...config.jenkins,\n apiToken: config.jenkins.apiToken ? '***' : undefined\n },\n jenkinsInstances: config.jenkinsInstances.map(inst => ({\n ...inst,\n apiToken: inst.apiToken ? '***' : undefined\n })),\n checkmarx: {\n ...config.checkmarx,\n apiKey: config.checkmarx.apiKey ? '***' : undefined,\n clientSecret: config.checkmarx.clientSecret ? '***' : undefined\n },\n contrast: {\n ...config.contrast,\n apiKey: config.contrast.apiKey ? '***' : undefined,\n serviceKey: config.contrast.serviceKey ? '***' : undefined\n },\n sonatypeiq: {\n ...config.sonatypeiq,\n passcode: config.sonatypeiq.passcode ? '***' : undefined\n },\n openshift: {\n ...config.openshift,\n token: config.openshift.token ? '***' : undefined,\n environments: Object.fromEntries(\n Object.entries(config.openshift.environments).map(([envName, envCfg]) => [\n envName,\n {\n instances: Object.fromEntries(\n Object.entries(envCfg.instances ?? {}).map(([instName, instCfg]) => [\n instName,\n { ...instCfg, token: instCfg.token ? '***' : undefined }\n ])\n )\n }\n ])\n )\n },\n dynatrace: {\n ...config.dynatrace,\n apiToken: config.dynatrace.apiToken ? '***' : undefined,\n platformToken: config.dynatrace.platformToken ? '***' : undefined,\n environments: Object.fromEntries(\n Object.entries(config.dynatrace.environments).map(([name, env]) => [\n name,\n {\n ...env,\n apiToken: env.apiToken ? '***' : undefined,\n platformToken: env.platformToken ? '***' : undefined\n }\n ])\n )\n },\n logscale: {\n ...config.logscale,\n token: config.logscale.token ? '***' : undefined\n },\n splitio: {\n ...config.splitio,\n adminApiKey: config.splitio.adminApiKey ? '***' : undefined\n },\n figma: {\n ...config.figma,\n token: config.figma.token ? '***' : undefined\n },\n alation: {\n ...config.alation,\n refreshToken: config.alation.refreshToken ? '***' : undefined\n }\n };\n}\n\nexport { getGlobalConfigPath, loadJsonFile };\n","// Phase 3 — Jira Data Cloud types\n\nexport const CUSTOM_FIELD_TYPES = [\n 'string',\n 'number',\n 'date',\n 'datetime',\n 'select',\n 'multi-select',\n 'option-id',\n 'cascading-select',\n 'user',\n 'labels',\n 'url',\n 'textarea'\n] as const;\n\nexport type CustomFieldType = (typeof CUSTOM_FIELD_TYPES)[number];\n\nexport interface CustomFieldDefinition {\n id: string;\n name: string;\n /** Drives how a `--field` value is shaped for Jira's API. Omitted = raw string. */\n type?: CustomFieldType;\n description?: string;\n examples?: string[];\n}\n\nexport interface CustomFieldMap {\n byName: Map<string, CustomFieldDefinition>;\n byId: Map<string, CustomFieldDefinition>;\n}\n\nexport interface JiraUser {\n name: string;\n displayName: string;\n}\n\nexport interface JiraFieldInfo {\n id: string;\n name: string;\n custom: boolean;\n schema?: { type: string; custom?: string };\n allowedValues?: Array<{ id: string; value?: string; name?: string; children?: Array<{ id: string; value: string }> }>;\n /** Suggested pncli config type inferred from the Jira field schema. */\n pncliType?: CustomFieldType;\n}\n\nexport interface JiraIssue {\n id: string;\n key: string;\n fields: {\n summary: string;\n description?: unknown;\n status: { name: string };\n priority?: { name: string };\n assignee?: JiraUser | null;\n reporter?: JiraUser;\n labels?: string[];\n issuetype: { name: string };\n project: { key: string; name: string };\n created: string;\n updated: string;\n [key: string]: unknown;\n };\n}\n\nexport interface JiraTransition {\n id: string;\n name: string;\n to: { name: string };\n}\n\nexport interface JiraComment {\n id: string;\n author: JiraUser;\n body: unknown;\n created: string;\n updated: string;\n}\n\nexport interface JiraSearchResult {\n issues: JiraIssue[];\n total: number;\n startAt: number;\n maxResults: number;\n}\n\nexport interface JiraAttachment {\n id: string;\n filename: string;\n author: JiraUser;\n created: string;\n size: number;\n mimeType: string;\n content: string;\n}\n\nexport interface JiraBoard {\n id: number;\n name: string;\n type: string;\n}\n\nexport interface JiraSprint {\n id: number;\n name: string;\n state: string;\n startDate?: string;\n endDate?: string;\n goal?: string;\n}\n\nexport interface JiraWorklog {\n id: string;\n author: JiraUser;\n comment?: unknown;\n started: string;\n timeSpent: string;\n timeSpentSeconds: number;\n created: string;\n updated: string;\n}\n","import { PncliError } from './errors.js';\nimport { CUSTOM_FIELD_TYPES } from '../types/jira.js';\nimport type { CustomFieldDefinition } from '../types/jira.js';\n\nexport interface ValidateCustomFieldsOptions {\n /** Where the value came from, for the error message — e.g. `global config`. */\n source?: string;\n /** Append `--repo` to the suggested fix, for values read from `.pncli.json`. */\n repo?: boolean;\n}\n\nconst EXAMPLE = '[{\"id\":\"customfield_10032\",\"name\":\"Epic Link\",\"type\":\"select\"}]';\n\n/**\n * Validates `jira.customFields` before it's indexed or merged. The value comes straight\n * off disk (or a `config set` value that fell back to a raw string when JSON.parse failed —\n * e.g. mangled shell quoting), so it isn't guaranteed to match CustomFieldDefinition at\n * runtime even though the type says it does. Shared by `loadConfig` (which names the\n * offending config file) and `buildFieldMap` (which doesn't know where the value came from).\n */\nexport function assertValidCustomFields(\n fields: unknown,\n opts: ValidateCustomFieldsOptions = {}\n): asserts fields is CustomFieldDefinition[] {\n const where = opts.source ? `in ${opts.source}` : 'config';\n const fix = (value: string) => `Fix with: pncli config set jira.customFields '${value}'${opts.repo ? ' --repo' : ''}`;\n\n if (!Array.isArray(fields)) {\n throw new PncliError(\n `Invalid jira.customFields ${where}: expected an array, got ${JSON.stringify(fields)}. ${fix('[]')}`,\n 1\n );\n }\n for (const f of fields) {\n const entry = f as { id?: unknown; name?: unknown; type?: unknown } | null;\n if (typeof entry !== 'object' || entry === null || typeof entry.id !== 'string' || typeof entry.name !== 'string') {\n throw new PncliError(\n `Invalid jira.customFields ${where}: each entry must be an object with string \"id\" and \"name\" fields. Got: ${JSON.stringify(f)}. ${fix(EXAMPLE)}`,\n 1\n );\n }\n // `type` is optional (omitted = raw string, per skills/pncli/jira.md), but when present it\n // must be a known CustomFieldType — otherwise formatFieldValue silently falls through.\n if (entry.type !== undefined && (typeof entry.type !== 'string' || !(CUSTOM_FIELD_TYPES as readonly string[]).includes(entry.type))) {\n throw new PncliError(\n `Invalid jira.customFields ${where}: entry \"${entry.name}\" has unknown \"type\" ${JSON.stringify(entry.type)}; expected one of ${CUSTOM_FIELD_TYPES.join(', ')}. ${fix(EXAMPLE)}`,\n 1\n );\n }\n }\n}\n","import { spawnSync } from 'child_process';\n\n/**\n * OS keychain storage for pncli secrets.\n *\n * Any string value in the global config can be a reference of the form `keychain:<account>`\n * instead of the secret itself. `loadConfig` resolves those references through the platform's\n * own credential store, so a token never has to sit in plaintext in `~/.pncli/config.json`:\n *\n * macOS → login Keychain, via the built-in `security` tool\n * Windows → Credential Manager, via the built-in Windows PowerShell and advapi32\n * Linux → Secret Service (GNOME Keyring / KWallet), via `secret-tool` (libsecret-tools)\n *\n * This is opt-in storage, never a requirement: plaintext config and `PNCLI_*` env vars keep\n * working exactly as before, and env vars still win over anything stored here. Secrets always\n * travel to the helper process over stdin, never argv, because argv is visible to every other\n * process on the machine.\n */\n\nexport const KEYCHAIN_PREFIX = 'keychain:';\nexport const KEYCHAIN_SERVICE = 'pncli';\n\n/** Account names are config-path-like: `github.token`, `marketplaces.internal-ai.token`. */\nconst ACCOUNT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\n\nexport type KeychainBackendName = 'macos' | 'windows' | 'linux' | 'none';\n\nexport interface RunResult {\n status: number | null;\n stdout: string;\n stderr: string;\n error?: Error;\n}\n\n/** Spawns a helper process. Injected so tests can assert the exact invocation without a real keychain. */\nexport type Runner = (command: string, args: string[], input?: string) => RunResult;\n\nexport const defaultRunner: Runner = (command, args, input) => {\n const r = spawnSync(command, args, { input, encoding: 'utf8', windowsHide: true, timeout: 30_000 });\n return { status: r.status, stdout: r.stdout ?? '', stderr: r.stderr ?? '', error: r.error };\n};\n\nexport interface KeychainBackend {\n name: KeychainBackendName;\n /** Human-readable name of the store, for status output. */\n store: string;\n available(): boolean;\n /** Returns a map of account → secret (null when the account has no entry). */\n getMany(accounts: string[]): Record<string, string | null>;\n set(account: string, secret: string): void;\n /** Returns false when there was nothing to delete. */\n delete(account: string): boolean;\n}\n\nexport class KeychainError extends Error {}\n\n/**\n * Some accounts in a batch lookup failed (locked item, access denied) while others were read. The\n * readable ones are in `partial`, so one bad entry never takes every other reference down with it.\n */\nexport class KeychainBatchError extends KeychainError {\n constructor(public partial: Record<string, string | null>, public errors: Record<string, string>) {\n super(Object.entries(errors).map(([a, e]) => `${a}: ${e}`).join('; '));\n }\n}\n\n/** Runs a per-account lookup, collecting failures instead of stopping at the first one. */\nfunction lookupEach(accounts: string[], lookup: (account: string) => string | null): Record<string, string | null> {\n const out: Record<string, string | null> = {};\n const errors: Record<string, string> = {};\n for (const account of accounts) {\n try {\n out[account] = lookup(account);\n } catch (err) {\n errors[account] = err instanceof Error ? err.message : String(err);\n }\n }\n if (Object.keys(errors).length > 0) throw new KeychainBatchError(out, errors);\n return out;\n}\n\nexport function isKeychainRef(value: unknown): value is string {\n return typeof value === 'string' && value.startsWith(KEYCHAIN_PREFIX);\n}\n\nexport function keychainRef(account: string): string {\n assertValidAccount(account);\n return `${KEYCHAIN_PREFIX}${account}`;\n}\n\nexport function accountFromRef(ref: string): string {\n const account = ref.slice(KEYCHAIN_PREFIX.length);\n assertValidAccount(account);\n return account;\n}\n\nexport function assertValidAccount(account: string): void {\n if (!ACCOUNT_PATTERN.test(account)) {\n throw new KeychainError(`Invalid keychain account name \"${account}\" — use letters, digits, '.', '_' or '-' (max 128 chars).`);\n }\n}\n\nfunction assertStorableSecret(secret: string): void {\n if (!secret) throw new KeychainError('Refusing to store an empty secret.');\n if (/[\\r\\n]/.test(secret)) throw new KeychainError('Secrets containing newlines cannot be stored in the keychain.');\n}\n\nfunction failure(backend: string, action: string, r: RunResult): KeychainError {\n const detail = r.error?.message ?? (r.stderr.trim() || `exit code ${r.status}`);\n return new KeychainError(`${backend}: could not ${action}: ${detail}`);\n}\n\n// ─── macOS ──────────────────────────────────────────────────────────────────\n\nexport function macosBackend(run: Runner = defaultRunner): KeychainBackend {\n return {\n name: 'macos',\n store: 'macOS login Keychain',\n available() {\n const r = run('security', ['help']);\n return !r.error;\n },\n getMany(accounts) {\n return lookupEach(accounts, account => {\n assertValidAccount(account);\n const r = run('security', ['find-generic-password', '-s', KEYCHAIN_SERVICE, '-a', account, '-w']);\n // 44 = errSecItemNotFound\n if (r.status === 44) return null;\n if (r.status !== 0) throw failure('macOS Keychain', `read \"${account}\"`, r);\n return r.stdout.replace(/\\r?\\n$/, '');\n });\n },\n set(account, secret) {\n assertValidAccount(account);\n assertStorableSecret(secret);\n // `security -i` reads commands from stdin, so the secret never appears in argv. Hex (-X)\n // sidesteps security's quoting rules for secrets containing quotes or backslashes.\n const hex = Buffer.from(secret, 'utf8').toString('hex');\n const r = run('security', ['-i'], `add-generic-password -U -s ${KEYCHAIN_SERVICE} -a ${account} -l \"pncli ${account}\" -X ${hex}\\n`);\n if (r.status !== 0 || /error/i.test(r.stderr)) throw failure('macOS Keychain', `store \"${account}\"`, r);\n },\n delete(account) {\n assertValidAccount(account);\n const r = run('security', ['delete-generic-password', '-s', KEYCHAIN_SERVICE, '-a', account]);\n if (r.status === 44) return false;\n if (r.status !== 0) throw failure('macOS Keychain', `delete \"${account}\"`, r);\n return true;\n },\n };\n}\n\n// ─── Windows ────────────────────────────────────────────────────────────────\n\n/**\n * Windows Credential Manager has no built-in CLI that can read a secret back (`cmdkey` only\n * writes and lists), so this goes through advapi32 from the Windows PowerShell that ships with\n * every Windows install. All data — targets and secrets — is passed as JSON on stdin; the script\n * text is constant, so nothing user-controlled is ever interpolated into PowerShell.\n */\nexport const WINDOWS_CREDMAN_SCRIPT = String.raw`\n$ErrorActionPreference = 'Stop'\n# Redirected console streams default to the OEM code page; secrets are UTF-8 JSON both ways.\n[Console]::InputEncoding = New-Object System.Text.UTF8Encoding $false\n[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\npublic static class PncliCredMan {\n [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\n private struct CREDENTIAL {\n public int Flags; public int Type; public string TargetName; public string Comment;\n public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;\n public int CredentialBlobSize; public IntPtr CredentialBlob; public int Persist;\n public int AttributeCount; public IntPtr Attributes; public string TargetAlias; public string UserName;\n }\n [DllImport(\"advapi32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n private static extern bool CredReadW(string target, int type, int flags, out IntPtr cred);\n [DllImport(\"advapi32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n private static extern bool CredWriteW(ref CREDENTIAL cred, int flags);\n [DllImport(\"advapi32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n private static extern bool CredDeleteW(string target, int type, int flags);\n [DllImport(\"advapi32.dll\")]\n private static extern void CredFree(IntPtr cred);\n [DllImport(\"advapi32.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n private static extern bool CredEnumerateW(string filter, int flags, out int count, out IntPtr creds);\n private const int NotFound = 1168;\n public static string Read(string target) {\n IntPtr p;\n if (!CredReadW(target, 1, 0, out p)) {\n int err = Marshal.GetLastWin32Error();\n if (err == NotFound) return null;\n throw new System.ComponentModel.Win32Exception(err);\n }\n try {\n CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(p, typeof(CREDENTIAL));\n if (c.CredentialBlobSize == 0) return \"\";\n byte[] bytes = new byte[c.CredentialBlobSize];\n Marshal.Copy(c.CredentialBlob, bytes, 0, c.CredentialBlobSize);\n return Encoding.UTF8.GetString(bytes);\n } finally { CredFree(p); }\n }\n public static void Write(string target, string user, string secret) {\n byte[] bytes = Encoding.UTF8.GetBytes(secret);\n CREDENTIAL c = new CREDENTIAL();\n c.Type = 1; c.TargetName = target; c.UserName = user; c.Persist = 2;\n c.CredentialBlobSize = bytes.Length;\n c.CredentialBlob = Marshal.AllocHGlobal(bytes.Length);\n try {\n Marshal.Copy(bytes, 0, c.CredentialBlob, bytes.Length);\n if (!CredWriteW(ref c, 0)) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());\n } finally { Marshal.FreeHGlobal(c.CredentialBlob); }\n }\n // Git Credential Manager writes UTF-16LE blobs; pncli and git-credential-wincred write UTF-8.\n // Tokens are ASCII, so \"every odd byte is zero\" reliably identifies UTF-16.\n private static string Decode(byte[] bytes) {\n bool utf16 = bytes.Length % 2 == 0 && bytes.Length > 0;\n for (int i = 1; utf16 && i < bytes.Length; i += 2) if (bytes[i] != 0) utf16 = false;\n return utf16 ? Encoding.Unicode.GetString(bytes) : Encoding.UTF8.GetString(bytes);\n }\n // Flattened [target, user, secret] triples for every credential matching the filter (e.g. \"git:*\").\n public static string[] List(string filter) {\n int count; IntPtr list;\n if (!CredEnumerateW(filter, 0, out count, out list)) {\n int err = Marshal.GetLastWin32Error();\n if (err == NotFound) return new string[0];\n throw new System.ComponentModel.Win32Exception(err);\n }\n try {\n string[] outp = new string[count * 3];\n for (int i = 0; i < count; i++) {\n IntPtr item = Marshal.ReadIntPtr(list, i * IntPtr.Size);\n CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(item, typeof(CREDENTIAL));\n string secret = \"\";\n if (c.CredentialBlobSize > 0) {\n byte[] bytes = new byte[c.CredentialBlobSize];\n Marshal.Copy(c.CredentialBlob, bytes, 0, c.CredentialBlobSize);\n secret = Decode(bytes);\n }\n outp[i * 3] = c.TargetName; outp[i * 3 + 1] = c.UserName; outp[i * 3 + 2] = secret;\n }\n return outp;\n } finally { CredFree(list); }\n }\n public static bool Delete(string target) {\n if (CredDeleteW(target, 1, 0)) return true;\n int err = Marshal.GetLastWin32Error();\n if (err == NotFound) return false;\n throw new System.ComponentModel.Win32Exception(err);\n }\n}\n'@\n$req = [Console]::In.ReadToEnd() | ConvertFrom-Json\nswitch ($req.op) {\n 'get' {\n $out = @{}\n foreach ($t in $req.targets) { $out[$t] = [PncliCredMan]::Read($t) }\n [Console]::Out.Write((ConvertTo-Json -InputObject $out -Compress))\n }\n 'set' { [PncliCredMan]::Write($req.target, $req.user, $req.secret); [Console]::Out.Write('{\"ok\":true}') }\n 'delete' { $d = [PncliCredMan]::Delete($req.target); [Console]::Out.Write((ConvertTo-Json -InputObject @{ deleted = $d } -Compress)) }\n 'list' {\n $flat = [PncliCredMan]::List($req.filter)\n $items = @()\n for ($i = 0; $i -lt $flat.Length; $i += 3) { $items += @{ target = $flat[$i]; user = $flat[$i + 1]; secret = $flat[$i + 2] } }\n [Console]::Out.Write((ConvertTo-Json -InputObject @($items) -Compress -Depth 3))\n }\n 'ping' { [Console]::Out.Write('{\"ok\":true}') }\n}\n`;\n\nexport interface StoredCredential {\n target: string;\n user: string;\n /** Returned to the caller for fingerprinting and validation only — never printed. */\n secret: string;\n}\n\n/**\n * Every Windows Credential Manager entry whose target matches `filter` (e.g. `git:*`, which covers\n * what Git Credential Manager and git-credential-wincred store). Read-only.\n */\nexport function windowsListCredentials(filter: string, run: Runner = defaultRunner): StoredCredential[] {\n const encoded = Buffer.from(WINDOWS_CREDMAN_SCRIPT, 'utf16le').toString('base64');\n const r = run('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', encoded], JSON.stringify({ op: 'list', filter }));\n if (r.status !== 0) throw failure('Windows Credential Manager', 'list credentials', r);\n const parsed: unknown = JSON.parse(r.stdout.trim() || '[]');\n const items = Array.isArray(parsed) ? parsed : [parsed];\n return items\n .filter((x): x is { target?: unknown; user?: unknown; secret?: unknown } => !!x && typeof x === 'object')\n .map(x => ({ target: String(x.target ?? ''), user: String(x.user ?? ''), secret: String(x.secret ?? '') }));\n}\n\nexport function windowsTarget(account: string): string {\n return `${KEYCHAIN_SERVICE}:${account}`;\n}\n\nexport function windowsBackend(run: Runner = defaultRunner): KeychainBackend {\n const encoded = Buffer.from(WINDOWS_CREDMAN_SCRIPT, 'utf16le').toString('base64');\n const invoke = (payload: object, action: string): unknown => {\n const r = run('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', encoded], JSON.stringify(payload));\n if (r.status !== 0) throw failure('Windows Credential Manager', action, r);\n try {\n return JSON.parse(r.stdout.trim() || '{}');\n } catch {\n throw new KeychainError(`Windows Credential Manager: unexpected output while trying to ${action}.`);\n }\n };\n return {\n name: 'windows',\n store: 'Windows Credential Manager',\n available() {\n try { invoke({ op: 'ping' }, 'start PowerShell'); return true; } catch { return false; }\n },\n getMany(accounts) {\n accounts.forEach(assertValidAccount);\n if (accounts.length === 0) return {};\n const raw = invoke({ op: 'get', targets: accounts.map(windowsTarget) }, 'read credentials') as Record<string, string | null>;\n return Object.fromEntries(accounts.map(a => [a, raw[windowsTarget(a)] ?? null]));\n },\n set(account, secret) {\n assertValidAccount(account);\n assertStorableSecret(secret);\n invoke({ op: 'set', target: windowsTarget(account), user: account, secret }, `store \"${account}\"`);\n },\n delete(account) {\n assertValidAccount(account);\n const r = invoke({ op: 'delete', target: windowsTarget(account) }, `delete \"${account}\"`) as { deleted?: boolean };\n return !!r.deleted;\n },\n };\n}\n\n// ─── Linux ──────────────────────────────────────────────────────────────────\n\nexport function linuxBackend(run: Runner = defaultRunner): KeychainBackend {\n return {\n name: 'linux',\n store: 'Secret Service (secret-tool)',\n available() {\n const r = run('secret-tool', ['--version']);\n return !r.error;\n },\n getMany(accounts) {\n return lookupEach(accounts, account => {\n assertValidAccount(account);\n const r = run('secret-tool', ['lookup', 'service', KEYCHAIN_SERVICE, 'account', account]);\n if (r.error) throw failure('Secret Service', `read \"${account}\"`, r);\n // secret-tool exits 1 with empty output when nothing matches.\n if (r.status !== 0) return null;\n return r.stdout.replace(/\\r?\\n$/, '');\n });\n },\n set(account, secret) {\n assertValidAccount(account);\n assertStorableSecret(secret);\n const r = run('secret-tool', ['store', `--label=pncli ${account}`, 'service', KEYCHAIN_SERVICE, 'account', account], secret);\n if (r.status !== 0) throw failure('Secret Service', `store \"${account}\"`, r);\n },\n delete(account) {\n assertValidAccount(account);\n const existing = this.getMany([account])[account];\n if (existing === null) return false;\n const r = run('secret-tool', ['clear', 'service', KEYCHAIN_SERVICE, 'account', account]);\n if (r.status !== 0) throw failure('Secret Service', `delete \"${account}\"`, r);\n return true;\n },\n };\n}\n\n// ─── Selection ──────────────────────────────────────────────────────────────\n\nexport function noneBackend(): KeychainBackend {\n const unsupported = (): never => {\n throw new KeychainError(`No OS keychain backend is available on ${process.platform}. Set PNCLI_KEYCHAIN_BACKEND to macos, windows, or linux if one should be.`);\n };\n return { name: 'none', store: 'none', available: () => false, getMany: unsupported, set: unsupported, delete: unsupported };\n}\n\n/**\n * Picks the backend for this platform. `PNCLI_KEYCHAIN_BACKEND` overrides it — `none` disables\n * keychain resolution entirely (useful on a CI runner that inherits a developer config).\n */\nexport function getKeychainBackend(run: Runner = defaultRunner, platform: NodeJS.Platform = process.platform): KeychainBackend {\n const override = (process.env.PNCLI_KEYCHAIN_BACKEND || undefined) as KeychainBackendName | undefined;\n const name: KeychainBackendName = override\n ?? (platform === 'darwin' ? 'macos' : platform === 'win32' ? 'windows' : platform === 'linux' ? 'linux' : 'none');\n switch (name) {\n case 'macos': return macosBackend(run);\n case 'windows': return windowsBackend(run);\n case 'linux': return linuxBackend(run);\n case 'none': return noneBackend();\n default: throw new KeychainError(`Unknown PNCLI_KEYCHAIN_BACKEND \"${String(override)}\" — use macos, windows, linux, or none.`);\n }\n}\n\n// ─── Config integration ─────────────────────────────────────────────────────\n\n/** Leaf field names in the config that hold secrets. Used by `config keychain migrate` and doctor. */\nexport const SECRET_FIELD_NAMES = new Set([\n 'token', 'apiToken', 'pat', 'apiKey', 'clientSecret', 'serviceKey', 'passcode',\n 'refreshToken', 'adminApiKey', 'platformToken', 'password', 'connection',\n]);\n\nexport interface ConfigSecretLocation {\n /** Path segments from the config root, e.g. ['marketplaces', 0, 'token']. */\n path: (string | number)[];\n value: string;\n}\n\n/**\n * Walks a parsed config object and returns every string leaf matching `predicate`. Arrays are\n * walked by index so `marketplaces[]` and `jenkinsInstances[]` entries are covered.\n */\nexport function findConfigStrings(\n root: unknown,\n predicate: (key: string | number, value: string) => boolean,\n prefix: (string | number)[] = []\n): ConfigSecretLocation[] {\n const found: ConfigSecretLocation[] = [];\n if (Array.isArray(root)) {\n root.forEach((item, i) => found.push(...findConfigStrings(item, predicate, [...prefix, i])));\n } else if (root && typeof root === 'object') {\n for (const [key, value] of Object.entries(root as Record<string, unknown>)) {\n if (typeof value === 'string') {\n if (predicate(key, value)) found.push({ path: [...prefix, key], value });\n } else {\n found.push(...findConfigStrings(value, predicate, [...prefix, key]));\n }\n }\n }\n return found;\n}\n\n/** Deletes keychain entries that no remaining reference in `config` points at. Returns the accounts deleted. */\nexport function purgeEntries(config: unknown, backend: KeychainBackend, accounts: string[]): string[] {\n const stillReferenced = new Set(findKeychainRefs(config).map(r => r.value.slice(KEYCHAIN_PREFIX.length)));\n const purged: string[] = [];\n for (const account of new Set(accounts)) {\n if (stillReferenced.has(account)) continue;\n if (backend.delete(account)) purged.push(account);\n }\n return purged;\n}\n\n/** Every `keychain:` reference in a config object. */\nexport function findKeychainRefs(root: unknown): ConfigSecretLocation[] {\n return findConfigStrings(root, (_k, v) => isKeychainRef(v));\n}\n\n/** Every plaintext secret (a secret-named field that is not already a keychain reference). */\nexport function findPlaintextSecrets(root: unknown): ConfigSecretLocation[] {\n return findConfigStrings(root, (k, v) => typeof k === 'string' && SECRET_FIELD_NAMES.has(k) && v.length > 0 && !isKeychainRef(v));\n}\n\n/**\n * Suggested keychain account for a config path. Array entries use a `name` field when the entry\n * has one (`marketplaces.internal-ai.token`), so the account survives reordering the array.\n */\nexport function accountForPath(root: unknown, segments: (string | number)[]): string {\n const parts: string[] = [];\n let node: unknown = root;\n for (const seg of segments) {\n if (typeof seg === 'number') {\n const entry = Array.isArray(node) ? node[seg] : undefined;\n const name = entry && typeof entry === 'object' ? (entry as { name?: unknown }).name : undefined;\n parts.push(typeof name === 'string' && /^[A-Za-z0-9._-]+$/.test(name) ? name : String(seg));\n } else {\n parts.push(seg);\n }\n node = node && typeof node === 'object' ? (node as Record<string | number, unknown>)[seg] : undefined;\n }\n return parts.join('.');\n}\n\nexport function setAtPath(root: Record<string, unknown>, segments: (string | number)[], value: unknown): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let node: any = root;\n for (const seg of segments.slice(0, -1)) node = node[seg];\n node[segments[segments.length - 1]!] = value;\n}\n\nexport interface UnresolvedRef {\n path: string;\n account: string;\n reason: string;\n}\n\nconst resolvedCache = new Map<string, string | null>();\nlet lastUnresolved: UnresolvedRef[] = [];\nlet warnedUnresolved = false;\n\n/** Refs the most recent resolution pass could not satisfy. Read by doctor. */\nexport function getUnresolvedKeychainRefs(): UnresolvedRef[] {\n return lastUnresolved;\n}\n\n/** Test hook: forget cached lookups between tests. */\nexport function resetKeychainCache(): void {\n resolvedCache.clear();\n lastUnresolved = [];\n warnedUnresolved = false;\n}\n\n/**\n * Returns a deep copy of `config` with every `keychain:` reference replaced by the stored secret.\n * One backend call covers all refs (a single PowerShell start on Windows), and results are cached\n * for the life of the process because `loadConfig` runs many times per command.\n *\n * A reference that cannot be resolved becomes `undefined` — the same as an unset key — so the\n * service that needs it reports \"not configured\" instead of sending the literal `keychain:...`\n * string as a credential. A single stderr warning names the refs; doctor reports them in detail.\n */\nexport function resolveKeychainRefs<T>(config: T, backend?: KeychainBackend, opts: { skipPaths?: Set<string>; onlyPaths?: Set<string> } = {}): T {\n const all = findKeychainRefs(config);\n if (all.length === 0) return config;\n\n const copy = JSON.parse(JSON.stringify(config)) as Record<string, unknown>;\n // A field an env var overrides is never used, so never ask the OS store for it — no process spawn\n // on a CI runner that inherited a developer's config, and no warning about a value nobody reads.\n const refs = all.filter(r => {\n const key = r.path.join('.');\n // onlyPaths: the caller reads just these fields, so no other reference is looked up.\n if (!opts.skipPaths?.has(key) && (!opts.onlyPaths || opts.onlyPaths.has(key))) return true;\n setAtPath(copy, r.path, undefined);\n return false;\n });\n if (refs.length === 0) return copy as T;\n const unresolved: UnresolvedRef[] = [];\n const accounts = new Map<string, (string | number)[][]>();\n for (const ref of refs) {\n try {\n const account = accountFromRef(ref.value);\n accounts.set(account, [...(accounts.get(account) ?? []), ref.path]);\n } catch (err) {\n unresolved.push({ path: ref.path.join('.'), account: ref.value.slice(KEYCHAIN_PREFIX.length), reason: (err as Error).message });\n setAtPath(copy, ref.path, undefined);\n }\n }\n\n const activeBackend = backend ?? getKeychainBackend();\n if (activeBackend.name === 'none') {\n // PNCLI_KEYCHAIN_BACKEND=none (or an unsupported platform): references are ignored on purpose,\n // so no warning — doctor still lists them.\n for (const [account, paths] of accounts) {\n for (const p of paths) {\n setAtPath(copy, p, undefined);\n unresolved.push({ path: p.join('.'), account, reason: 'keychain disabled (PNCLI_KEYCHAIN_BACKEND=none or unsupported platform)' });\n }\n }\n lastUnresolved = unresolved;\n return copy as T;\n }\n\n const missing = [...accounts.keys()].filter(a => !resolvedCache.has(a));\n if (missing.length > 0) {\n let failed: Record<string, string> = {};\n try {\n const found = activeBackend.getMany(missing);\n for (const a of missing) resolvedCache.set(a, found[a] ?? null);\n } catch (err) {\n if (err instanceof KeychainBatchError) {\n // Keep what was readable; only the accounts that actually failed are unresolved.\n for (const a of missing) if (!(a in err.errors)) resolvedCache.set(a, err.partial[a] ?? null);\n failed = err.errors;\n } else {\n failed = Object.fromEntries(missing.map(a => [a, (err as Error).message]));\n }\n }\n for (const [account, paths] of accounts) {\n if (resolvedCache.has(account) || !(account in failed)) continue;\n for (const p of paths) unresolved.push({ path: p.join('.'), account, reason: failed[account]! });\n }\n }\n\n for (const [account, paths] of accounts) {\n const secret = resolvedCache.get(account);\n for (const p of paths) {\n if (secret != null) {\n setAtPath(copy, p, secret);\n } else {\n setAtPath(copy, p, undefined);\n if (resolvedCache.has(account)) unresolved.push({ path: p.join('.'), account, reason: 'no entry in the keychain' });\n }\n }\n }\n\n lastUnresolved = unresolved;\n if (unresolved.length > 0 && !warnedUnresolved) {\n warnedUnresolved = true;\n process.stderr.write(`Warning: ${unresolved.length} keychain reference(s) could not be resolved (${unresolved.map(u => u.path).join(', ')}). Run: pncli doctor\\n`);\n }\n return copy as T;\n}\n\n/**\n * Stores a secret and reads it back before returning — the caller only then points config at it,\n * so a backend that silently drops writes can never leave a reference that resolves to nothing.\n */\nexport function storeVerified(backend: KeychainBackend, account: string, secret: string): void {\n backend.set(account, secret);\n let readBack: string | null | undefined;\n try {\n readBack = backend.getMany([account])[account];\n } catch (err) {\n throw new KeychainError(`Stored \"${account}\" but could not read it back to verify: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (readBack !== secret) throw new KeychainError(`Stored \"${account}\" but reading it back did not return the same secret — config was not changed.`);\n}\n\n/** Resolves a single value that may be a keychain reference (e.g. a marketplace token read from raw config). */\nexport function resolveSecretValue(value: string | undefined, backend?: KeychainBackend): string | undefined {\n if (!isKeychainRef(value)) return value;\n const resolved = resolveKeychainRefs({ v: value }, backend);\n return resolved.v;\n}\n"],"mappings":"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","names":[]}