@kolatts/pncli 6.0.0 → 6.2.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 CHANGED
@@ -140,6 +140,7 @@ This project uses Conventional Commits for automatic versioning:
140
140
  | Sonatype IQ | ⚪ Untested | Dependency policy enforcement |
141
141
  | OpenShift | ⚪ Untested | Pods, events, logs, metrics |
142
142
  | LogScale | ⚪ Untested | Log queries, repositories |
143
+ | Elasticsearch | ⚪ Untested | Search, count, indices, cluster health |
143
144
  | Figma | ⚪ Untested | Design files, comments, history |
144
145
  | Split.IO | ⚪ Untested | Feature flags, change requests |
145
146
  | Alation | ⚪ Untested | Catalog metadata, search, documents |
@@ -578,6 +578,8 @@ var ENV_KEYS = {
578
578
  DYNATRACE_PLATFORM_TOKEN: "PNCLI_DYNATRACE_PLATFORM_TOKEN",
579
579
  LOGSCALE_BASE_URL: "PNCLI_LOGSCALE_BASE_URL",
580
580
  LOGSCALE_TOKEN: "PNCLI_LOGSCALE_TOKEN",
581
+ ELASTICSEARCH_BASE_URL: "PNCLI_ELASTICSEARCH_BASE_URL",
582
+ ELASTICSEARCH_API_KEY: "PNCLI_ELASTICSEARCH_API_KEY",
581
583
  SPLITIO_BASE_URL: "PNCLI_SPLITIO_BASE_URL",
582
584
  SPLITIO_ADMIN_API_KEY: "PNCLI_SPLITIO_ADMIN_API_KEY",
583
585
  FIGMA_BASE_URL: "PNCLI_FIGMA_BASE_URL",
@@ -663,6 +665,7 @@ var SECRET_ENV_OVERRIDES = [
663
665
  ["dynatrace.apiToken", [ENV_KEYS.DYNATRACE_API_TOKEN]],
664
666
  ["dynatrace.platformToken", [ENV_KEYS.DYNATRACE_PLATFORM_TOKEN]],
665
667
  ["logscale.token", [ENV_KEYS.LOGSCALE_TOKEN]],
668
+ ["elasticsearch.apiKey", [ENV_KEYS.ELASTICSEARCH_API_KEY]],
666
669
  ["splitio.adminApiKey", [ENV_KEYS.SPLITIO_ADMIN_API_KEY]],
667
670
  ["figma.token", [ENV_KEYS.FIGMA_TOKEN]],
668
671
  ["alation.refreshToken", [ENV_KEYS.ALATION_REFRESH_TOKEN]],
@@ -773,6 +776,10 @@ function loadConfig(opts = {}) {
773
776
  baseUrl: process.env[ENV_KEYS.LOGSCALE_BASE_URL] ?? globalConfig.logscale?.baseUrl,
774
777
  token: process.env[ENV_KEYS.LOGSCALE_TOKEN] ?? globalConfig.logscale?.token
775
778
  },
779
+ elasticsearch: {
780
+ baseUrl: process.env[ENV_KEYS.ELASTICSEARCH_BASE_URL] ?? globalConfig.elasticsearch?.baseUrl,
781
+ apiKey: process.env[ENV_KEYS.ELASTICSEARCH_API_KEY] ?? globalConfig.elasticsearch?.apiKey
782
+ },
776
783
  splitio: {
777
784
  baseUrl: process.env[ENV_KEYS.SPLITIO_BASE_URL] ?? globalConfig.splitio?.baseUrl,
778
785
  adminApiKey: process.env[ENV_KEYS.SPLITIO_ADMIN_API_KEY] ?? globalConfig.splitio?.adminApiKey
@@ -948,6 +955,10 @@ function maskConfig(config) {
948
955
  ...config.logscale,
949
956
  token: config.logscale.token ? "***" : void 0
950
957
  },
958
+ elasticsearch: {
959
+ ...config.elasticsearch,
960
+ apiKey: config.elasticsearch.apiKey ? "***" : void 0
961
+ },
951
962
  splitio: {
952
963
  ...config.splitio,
953
964
  adminApiKey: config.splitio.adminApiKey ? "***" : void 0
@@ -998,4 +1009,4 @@ export {
998
1009
  setRepoConfigValue,
999
1010
  maskConfig
1000
1011
  };
1001
- //# sourceMappingURL=chunk-WDWAPTVC.js.map
1012
+ //# sourceMappingURL=chunk-GHZMFNSX.js.map
@@ -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 ELASTICSEARCH_BASE_URL: 'PNCLI_ELASTICSEARCH_BASE_URL',\n ELASTICSEARCH_API_KEY: 'PNCLI_ELASTICSEARCH_API_KEY',\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 SAUCELABS_BASE_URL: 'PNCLI_SAUCELABS_BASE_URL',\n SAUCELABS_USERNAME: 'PNCLI_SAUCELABS_USERNAME',\n SAUCELABS_ACCESS_KEY: 'PNCLI_SAUCELABS_ACCESS_KEY',\n // The names saucectl, Sauce Connect and Sauce's own CI docs read — see the comment above GITHUB_TOKEN_FALLBACK.\n SAUCELABS_USERNAME_FALLBACK: 'SAUCE_USERNAME',\n SAUCELABS_ACCESS_KEY_FALLBACK: 'SAUCE_ACCESS_KEY',\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 ['elasticsearch.apiKey', [ENV_KEYS.ELASTICSEARCH_API_KEY]],\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 ['saucelabs.accessKey', [ENV_KEYS.SAUCELABS_ACCESS_KEY, ENV_KEYS.SAUCELABS_ACCESS_KEY_FALLBACK]],\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 elasticsearch: {\n baseUrl: process.env[ENV_KEYS.ELASTICSEARCH_BASE_URL] ?? globalConfig.elasticsearch?.baseUrl,\n apiKey: process.env[ENV_KEYS.ELASTICSEARCH_API_KEY] ?? globalConfig.elasticsearch?.apiKey,\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 saucelabs: {\n baseUrl: process.env[ENV_KEYS.SAUCELABS_BASE_URL] ?? globalConfig.saucelabs?.baseUrl,\n username: process.env[ENV_KEYS.SAUCELABS_USERNAME]\n ?? process.env[ENV_KEYS.SAUCELABS_USERNAME_FALLBACK]\n ?? globalConfig.saucelabs?.username,\n accessKey: process.env[ENV_KEYS.SAUCELABS_ACCESS_KEY]\n ?? process.env[ENV_KEYS.SAUCELABS_ACCESS_KEY_FALLBACK]\n ?? globalConfig.saucelabs?.accessKey,\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 elasticsearch: {\n ...config.elasticsearch,\n apiKey: config.elasticsearch.apiKey ? '***' : 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 saucelabs: {\n ...config.saucelabs,\n accessKey: config.saucelabs.accessKey ? '***' : 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', 'accessKey',\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":[]}
@@ -74,6 +74,7 @@ function success(data, service, action, startTime, overrides) {
74
74
  }
75
75
  }
76
76
  function fail(err, service, action, startTime) {
77
+ if (err instanceof PncliError && err.status === 0 && err.message === "dry-run") throw err;
77
78
  const errorDetail = {
78
79
  status: err instanceof PncliError ? err.status : 1,
79
80
  message: err instanceof Error ? err.message : String(err),
@@ -140,4 +141,4 @@ export {
140
141
  debug,
141
142
  warn
142
143
  };
143
- //# sourceMappingURL=chunk-BOFSNQQ2.js.map
144
+ //# sourceMappingURL=chunk-MBJ4ZYL7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/output.ts","../src/lib/exitCodes.ts"],"sourcesContent":["import fs from 'fs';\nimport chalk from 'chalk';\nimport type { Meta, SuccessEnvelope, ErrorEnvelope, ErrorDetail } from '../types/common.js';\nimport { PncliError } from './errors.js';\nimport { ExitCode, exitCodeFromStatus } from './exitCodes.js';\n\nlet globalOptions = { pretty: false, verbose: false, debug: false };\nlet globalUser: { email: string | undefined; userId: string | undefined } = { email: undefined, userId: undefined };\nlet outputFile: string | undefined;\n\nexport function setGlobalOptions(opts: { pretty: boolean; verbose: boolean; debug?: boolean; outputFile?: string }): void {\n globalOptions = { pretty: opts.pretty, verbose: opts.verbose, debug: opts.debug ?? false };\n outputFile = opts.outputFile;\n}\n\nexport function isDebugEnabled(): boolean {\n return globalOptions.debug;\n}\n\nexport function setGlobalUser(user: { email: string | undefined; userId: string | undefined }): void {\n globalUser = user;\n}\n\nfunction buildMeta(service: string, action: string, startTime: number, overrides?: string[]): Meta {\n return {\n service,\n action,\n timestamp: new Date().toISOString(),\n duration_ms: Date.now() - startTime,\n user: (globalUser.email ?? globalUser.userId) ? globalUser : undefined,\n overrides: overrides && overrides.length > 0 ? overrides : undefined\n };\n}\n\nfunction writeToFile(filePath: string, content: string): void {\n try {\n fs.writeFileSync(filePath, content, 'utf8');\n } catch (writeErr) {\n process.stderr.write(\n `Warning: could not write to output file \"${filePath}\": ${(writeErr as NodeJS.ErrnoException).message}\\n`\n );\n process.exitCode = ExitCode.GENERAL_ERROR;\n }\n}\n\nexport function success<T>(data: T, service: string, action: string, startTime: number, overrides?: string[]): void {\n const envelope: SuccessEnvelope<T> = {\n ok: true,\n data,\n meta: buildMeta(service, action, startTime, overrides)\n };\n const out = (globalOptions.pretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope)) + '\\n';\n if (outputFile) {\n writeToFile(outputFile, out);\n } else {\n process.stdout.write(out);\n }\n}\n\nexport function fail(\n err: unknown,\n service: string,\n action: string,\n startTime: number\n): never {\n // The dry-run sentinel is a successful outcome: http.ts already printed the request\n // and set exitCode to SUCCESS. Don't render it as an error envelope or remap status 0.\n if (err instanceof PncliError && err.status === 0 && err.message === 'dry-run') throw err;\n\n const errorDetail: ErrorDetail = {\n status: err instanceof PncliError ? err.status : 1,\n message: err instanceof Error ? err.message : String(err),\n url: err instanceof PncliError ? (err.url ?? null) : null,\n retryAfterSeconds: err instanceof PncliError ? err.retryAfterSeconds : undefined\n };\n\n const envelope: ErrorEnvelope = {\n ok: false,\n error: errorDetail,\n meta: buildMeta(service, action, startTime)\n };\n\n const msg = globalOptions.pretty\n ? chalk.red('✗ Error: ') + errorDetail.message\n : null;\n\n if (msg) process.stderr.write(msg + '\\n');\n\n const output = (globalOptions.pretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope)) + '\\n';\n const exitCode = err instanceof PncliError ? exitCodeFromStatus(err.status) : ExitCode.GENERAL_ERROR;\n if (outputFile) {\n writeToFile(outputFile, output);\n } else {\n try {\n fs.writeSync(process.stdout.fd, output);\n } catch (writeErr) {\n if ((writeErr as NodeJS.ErrnoException).code !== 'EPIPE') throw writeErr;\n }\n }\n process.exitCode = exitCode;\n throw new PncliError(errorDetail.message, errorDetail.status);\n}\n\nexport function writeRawOutput(content: string): void {\n if (outputFile) {\n writeToFile(outputFile, content);\n } else {\n process.stdout.write(content);\n }\n}\n\nexport function log(message: string): void {\n if (globalOptions.verbose) {\n process.stderr.write(\n (globalOptions.pretty ? chalk.gray('▸ ') : '') + message + '\\n'\n );\n }\n}\n\nexport function debug(message: string): void {\n if (globalOptions.debug) {\n process.stderr.write(\n (globalOptions.pretty ? chalk.cyan('⬡ ') : '') + message + '\\n'\n );\n }\n}\n\nexport function warn(message: string): void {\n process.stderr.write(\n (globalOptions.pretty ? chalk.yellow('⚠ ') : '') + message + '\\n'\n );\n}\n","export const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n USAGE_ERROR: 2,\n NETWORK_ERROR: 69, // EX_UNAVAILABLE from sysexits.h\n AUTH_ERROR: 77, // EX_NOPERM from sysexits.h\n CONFIG_ERROR: 78, // EX_CONFIG from sysexits.h\n} as const;\n\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\n\nexport function exitCodeFromStatus(httpStatus: number): ExitCode {\n if (httpStatus === 401 || httpStatus === 403) return ExitCode.AUTH_ERROR;\n if (httpStatus === 0) return ExitCode.NETWORK_ERROR;\n return ExitCode.GENERAL_ERROR;\n}\n"],"mappings":";;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,WAAW;;;ACDX,IAAM,WAAW;AAAA,EACtB,SAAS;AAAA,EACT,eAAe;AAAA,EACf,aAAa;AAAA,EACb,eAAe;AAAA;AAAA,EACf,YAAY;AAAA;AAAA,EACZ,cAAc;AAAA;AAChB;AAIO,SAAS,mBAAmB,YAA8B;AAC/D,MAAI,eAAe,OAAO,eAAe,IAAK,QAAO,SAAS;AAC9D,MAAI,eAAe,EAAG,QAAO,SAAS;AACtC,SAAO,SAAS;AAClB;;;ADTA,IAAI,gBAAgB,EAAE,QAAQ,OAAO,SAAS,OAAO,OAAO,MAAM;AAClE,IAAI,aAAwE,EAAE,OAAO,QAAW,QAAQ,OAAU;AAClH,IAAI;AAEG,SAAS,iBAAiB,MAAyF;AACxH,kBAAgB,EAAE,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,OAAO,KAAK,SAAS,MAAM;AACzF,eAAa,KAAK;AACpB;AAEO,SAAS,iBAA0B;AACxC,SAAO,cAAc;AACvB;AAEO,SAAS,cAAc,MAAuE;AACnG,eAAa;AACf;AAEA,SAAS,UAAU,SAAiB,QAAgB,WAAmB,WAA4B;AACjG,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,aAAa,KAAK,IAAI,IAAI;AAAA,IAC1B,MAAO,WAAW,SAAS,WAAW,SAAU,aAAa;AAAA,IAC7D,WAAW,aAAa,UAAU,SAAS,IAAI,YAAY;AAAA,EAC7D;AACF;AAEA,SAAS,YAAY,UAAkB,SAAuB;AAC5D,MAAI;AACF,OAAG,cAAc,UAAU,SAAS,MAAM;AAAA,EAC5C,SAAS,UAAU;AACjB,YAAQ,OAAO;AAAA,MACb,4CAA4C,QAAQ,MAAO,SAAmC,OAAO;AAAA;AAAA,IACvG;AACA,YAAQ,WAAW,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,QAAW,MAAS,SAAiB,QAAgB,WAAmB,WAA4B;AAClH,QAAM,WAA+B;AAAA,IACnC,IAAI;AAAA,IACJ;AAAA,IACA,MAAM,UAAU,SAAS,QAAQ,WAAW,SAAS;AAAA,EACvD;AACA,QAAM,OAAO,cAAc,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,KAAK,UAAU,QAAQ,KAAK;AACpG,MAAI,YAAY;AACd,gBAAY,YAAY,GAAG;AAAA,EAC7B,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG;AAAA,EAC1B;AACF;AAEO,SAAS,KACd,KACA,SACA,QACA,WACO;AAGP,MAAI,eAAe,cAAc,IAAI,WAAW,KAAK,IAAI,YAAY,UAAW,OAAM;AAEtF,QAAM,cAA2B;AAAA,IAC/B,QAAQ,eAAe,aAAa,IAAI,SAAS;AAAA,IACjD,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD,KAAK,eAAe,aAAc,IAAI,OAAO,OAAQ;AAAA,IACrD,mBAAmB,eAAe,aAAa,IAAI,oBAAoB;AAAA,EACzE;AAEA,QAAM,WAA0B;AAAA,IAC9B,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM,UAAU,SAAS,QAAQ,SAAS;AAAA,EAC5C;AAEA,QAAM,MAAM,cAAc,SACtB,MAAM,IAAI,gBAAW,IAAI,YAAY,UACrC;AAEJ,MAAI,IAAK,SAAQ,OAAO,MAAM,MAAM,IAAI;AAExC,QAAM,UAAU,cAAc,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,KAAK,UAAU,QAAQ,KAAK;AACvG,QAAM,WAAW,eAAe,aAAa,mBAAmB,IAAI,MAAM,IAAI,SAAS;AACvF,MAAI,YAAY;AACd,gBAAY,YAAY,MAAM;AAAA,EAChC,OAAO;AACL,QAAI;AACF,SAAG,UAAU,QAAQ,OAAO,IAAI,MAAM;AAAA,IACxC,SAAS,UAAU;AACjB,UAAK,SAAmC,SAAS,QAAS,OAAM;AAAA,IAClE;AAAA,EACF;AACA,UAAQ,WAAW;AACnB,QAAM,IAAI,WAAW,YAAY,SAAS,YAAY,MAAM;AAC9D;AAEO,SAAS,eAAe,SAAuB;AACpD,MAAI,YAAY;AACd,gBAAY,YAAY,OAAO;AAAA,EACjC,OAAO;AACL,YAAQ,OAAO,MAAM,OAAO;AAAA,EAC9B;AACF;AAEO,SAAS,IAAI,SAAuB;AACzC,MAAI,cAAc,SAAS;AACzB,YAAQ,OAAO;AAAA,OACZ,cAAc,SAAS,MAAM,KAAK,SAAI,IAAI,MAAM,UAAU;AAAA,IAC7D;AAAA,EACF;AACF;AAEO,SAAS,MAAM,SAAuB;AAC3C,MAAI,cAAc,OAAO;AACvB,YAAQ,OAAO;AAAA,OACZ,cAAc,SAAS,MAAM,KAAK,SAAI,IAAI,MAAM,UAAU;AAAA,IAC7D;AAAA,EACF;AACF;AAEO,SAAS,KAAK,SAAuB;AAC1C,UAAQ,OAAO;AAAA,KACZ,cAAc,SAAS,MAAM,OAAO,SAAI,IAAI,MAAM,UAAU;AAAA,EAC/D;AACF;","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  debug,
5
5
  isDebugEnabled,
6
6
  log
7
- } from "./chunk-BOFSNQQ2.js";
7
+ } from "./chunk-MBJ4ZYL7.js";
8
8
  import {
9
9
  PncliError
10
10
  } from "./chunk-HRNOAQDN.js";
@@ -39,7 +39,9 @@ async function buildAdoFetcher(config) {
39
39
 
40
40
  // src/lib/tls.ts
41
41
  import tls from "tls";
42
+ var INSECURE_TLS_WARNING = "warning: NODE_TLS_REJECT_UNAUTHORIZED=0 is set, so pncli will NOT verify server certificates. Anyone on the network path can read or alter requests and responses, including your credentials and any writes. Unset it and trust the proxy or internal CA instead: install its root certificate in the OS store or set NODE_EXTRA_CA_CERTS=/path/to/ca.pem.\n";
42
43
  function configureTls(env = process.env, api = tls) {
44
+ if (env.NODE_TLS_REJECT_UNAUTHORIZED === "0") process.stderr.write(INSECURE_TLS_WARNING);
43
45
  if (env.NODE_USE_SYSTEM_CA !== void 0) return;
44
46
  try {
45
47
  const merged = /* @__PURE__ */ new Set([...api.getCACertificates("default"), ...api.getCACertificates("system")]);
@@ -1313,6 +1315,38 @@ Headers: ${JSON.stringify(safeHeaders, null, 2)}
1313
1315
  const msg = `DRY RUN: ${init.method} ${url}
1314
1316
  Headers: ${JSON.stringify(safeHeaders, null, 2)}
1315
1317
  ` + (opts.body ? `Body: ${JSON.stringify(opts.body, null, 2)}
1318
+ ` : "");
1319
+ fs.writeSync(process.stderr.fd, msg);
1320
+ process.exitCode = ExitCode.SUCCESS;
1321
+ throw new PncliError("dry-run", 0);
1322
+ }
1323
+ return request(url, init, opts.timeoutMs ?? 3e4);
1324
+ }
1325
+ elasticsearchHeaders() {
1326
+ const { apiKey } = this.config.elasticsearch;
1327
+ if (!apiKey) throw new PncliError("Elasticsearch credentials not configured. Run: pncli config init");
1328
+ return {
1329
+ "Authorization": `ApiKey ${apiKey}`,
1330
+ "Content-Type": "application/json",
1331
+ "Accept": "application/json",
1332
+ "Connection": "close"
1333
+ };
1334
+ }
1335
+ async elasticsearch(path, opts = {}) {
1336
+ const baseUrl = this.config.elasticsearch.baseUrl;
1337
+ if (!baseUrl) throw new PncliError("Elasticsearch baseUrl not configured. Run: pncli config init");
1338
+ const url = buildUrl(baseUrl, path, opts.params);
1339
+ const headers = this.elasticsearchHeaders();
1340
+ const init = {
1341
+ method: opts.method ?? "GET",
1342
+ headers,
1343
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
1344
+ };
1345
+ if (this.dryRun) {
1346
+ const safeHeaders = { ...headers, Authorization: "[REDACTED]" };
1347
+ const msg = `DRY RUN: ${init.method} ${url}
1348
+ Headers: ${JSON.stringify(safeHeaders, null, 2)}
1349
+ ` + (opts.body ? `Body: ${JSON.stringify(opts.body, null, 2)}
1316
1350
  ` : "");
1317
1351
  fs.writeSync(process.stderr.fd, msg);
1318
1352
  process.exitCode = ExitCode.SUCCESS;
@@ -1514,4 +1548,4 @@ export {
1514
1548
  HttpClient,
1515
1549
  createHttpClient
1516
1550
  };
1517
- //# sourceMappingURL=chunk-4FR4WGNR.js.map
1551
+ //# sourceMappingURL=chunk-RZV64BWP.js.map