@kolatts/pncli 1.14.1 → 1.16.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.
@@ -148,9 +148,12 @@ pncli jira create-issue
148
148
  --priority <name> Priority name
149
149
  --assignee <accountId> Assignee account ID
150
150
  --labels <labels> Comma-separated labels
151
- --parent <key> Parent issue key — creates an "is child of" link after
152
- creation
153
- --field <Name=value> Custom field value (repeatable) (default: [])
151
+ --parent <key> Parent issue key — sets fields.parent in the create
152
+ payload
153
+ --field <Name=value> Custom field value; use Name=@file.json to read value
154
+ from file (repeatable) (default: [])
155
+ --fields-file <path> Path to a JSON file mapping field names/IDs to their
156
+ Jira API values
154
157
 
155
158
  pncli jira update-issue
156
159
  --key <issue-key> Issue key
@@ -159,7 +162,10 @@ pncli jira update-issue
159
162
  --priority <name> New priority
160
163
  --assignee <accountId> New assignee account ID
161
164
  --labels <labels> Comma-separated labels
162
- --field <Name=value> Custom field value (repeatable) (default: [])
165
+ --field <Name=value> Custom field value; use Name=@file.json to read value
166
+ from file (repeatable) (default: [])
167
+ --fields-file <path> Path to a JSON file mapping field names/IDs to their
168
+ Jira API values
163
169
 
164
170
  pncli jira transition-issue
165
171
  --key <issue-key> Issue key
@@ -179,6 +185,14 @@ pncli jira search
179
185
  --jql <query> JQL query string
180
186
  --max-results <n> Maximum number of results
181
187
 
188
+ pncli jira add-label
189
+ --key <issue-key> Issue key
190
+ --labels <labels> Comma-separated labels to add
191
+
192
+ pncli jira remove-label
193
+ --key <issue-key> Issue key
194
+ --labels <labels> Comma-separated labels to remove
195
+
182
196
  pncli jira assign
183
197
  --key <issue-key> Issue key
184
198
  --assignee <accountId> Assignee account ID
@@ -188,9 +202,25 @@ pncli jira link-issue
188
202
  --link-type <type> Link type name or ID
189
203
  --target <issue-key> Target issue key
190
204
 
205
+ pncli jira add-attachment
206
+ --key <issue-key> Issue key (e.g. PROJ-123)
207
+ --file <path> Path to the file to upload
208
+
209
+ pncli jira list-attachments
210
+ --key <issue-key> Issue key (e.g. PROJ-123)
211
+
212
+ pncli jira download-attachment
213
+ --key <issue-key> Issue key (e.g. PROJ-123)
214
+ --attachment-id <id> Attachment ID from list-attachments output
215
+ --dir <path> Output directory (default: .pncli relative to cwd)
216
+
191
217
  pncli jira fields
192
- --discover Fetch field metadata from Jira API
193
- --custom-only Show only custom fields (requires --discover)
218
+ --discover Fetch field metadata from Jira API
219
+ --custom-only Show only custom fields (requires --discover)
220
+ --project <key> Project key — fetches allowedValues for select fields via
221
+ createmeta (requires --discover)
222
+ --issue-type <type> Filter allowedValues to a specific issue type (requires
223
+ --project)
194
224
  ```
195
225
 
196
226
  ### Bitbucket
@@ -210,6 +240,9 @@ pncli bitbucket create-pr
210
240
  --target <branch> Target branch (defaults to config)
211
241
  --description <desc> PR description
212
242
  --reviewers <users> Comma-separated reviewer usernames
243
+ --project <key> Bitbucket project key (overrides parent --project; use
244
+ ~username for personal repos)
245
+ --repo <slug> Bitbucket repository slug (overrides parent --repo)
213
246
 
214
247
  pncli bitbucket update-pr
215
248
  --id <pr-id> Pull request ID
@@ -284,6 +317,98 @@ pncli bitbucket get-build-status
284
317
  --commit <sha> Commit SHA
285
318
  ```
286
319
 
320
+ ### Github
321
+
322
+ ```
323
+ pncli github list-prs
324
+ --state <state> PR state (choices: "open", "closed", "all", default: "open")
325
+ --head <branch> Filter by head branch (user:branch)
326
+ --base <branch> Filter by base branch
327
+
328
+ pncli github get-pr
329
+ --number <n> Pull request number
330
+
331
+ pncli github create-pr
332
+ --title <title> PR title
333
+ --head <branch> Source branch (or user:branch for forks)
334
+ --base <branch> Target branch (defaults to config or main)
335
+ --body <body> PR description
336
+ --draft Create as draft PR
337
+ --owner <owner> GitHub owner (overrides parent --owner)
338
+ --repo <repo> GitHub repository name (overrides parent --repo)
339
+
340
+ pncli github update-pr
341
+ --number <n> Pull request number
342
+ --title <title> New title
343
+ --body <body> New description
344
+ --base <branch> New base branch
345
+
346
+ pncli github merge-pr
347
+ --number <n> Pull request number
348
+ --method <method> Merge method (choices: "merge", "squash", "rebase",
349
+ default: "merge")
350
+ --commit-title <title> Commit title for merge/squash
351
+ --commit-message <msg> Commit message for merge/squash
352
+
353
+ pncli github close-pr
354
+ --number <n> Pull request number
355
+
356
+ pncli github list-comments
357
+ --number <n> Pull request number
358
+
359
+ pncli github add-comment
360
+ --number <n> Pull request number
361
+ --body <text> Comment text
362
+
363
+ pncli github list-review-comments
364
+ --number <n> Pull request number
365
+
366
+ pncli github add-inline-comment
367
+ --number <n> Pull request number
368
+ --commit <sha> Commit SHA the comment is on
369
+ --file <path> File path
370
+ --line <n> Line number
371
+ --body <text> Comment text
372
+ --side <side> Comment side (choices: "LEFT", "RIGHT", default: "RIGHT")
373
+
374
+ pncli github reply-comment
375
+ --number <n> Pull request number
376
+ --comment-id <id> Review comment ID to reply to
377
+ --body <text> Reply text
378
+
379
+ pncli github delete-comment
380
+ --comment-id <id> Comment ID
381
+
382
+ pncli github delete-review-comment
383
+ --comment-id <id> Review comment ID
384
+
385
+ pncli github diff
386
+ --number <n> Pull request number
387
+
388
+ pncli github list-files
389
+ --number <n> Pull request number
390
+
391
+ pncli github list-reviews
392
+ --number <n> Pull request number
393
+
394
+ pncli github approve
395
+ --number <n> Pull request number
396
+ --body <text> Review body text
397
+
398
+ pncli github request-changes
399
+ --number <n> Pull request number
400
+ --body <text> Review feedback text
401
+
402
+ pncli github list-reviewers
403
+ --number <n> Pull request number
404
+
405
+ pncli github get-status
406
+ --ref <ref> Git ref (branch, tag, or commit SHA)
407
+
408
+ pncli github list-checks
409
+ --ref <ref> Git ref (branch, tag, or commit SHA)
410
+ ```
411
+
287
412
  ### Confluence
288
413
 
289
414
  ```
@@ -298,7 +423,7 @@ pncli confluence get-page-by-title
298
423
 
299
424
  pncli confluence list-pages
300
425
  --space <key> Space key
301
- --limit <n> Max results per page (default: all)
426
+ --limit <n> Max total pages to return (default: all)
302
427
  --start <n> Offset for first result
303
428
 
304
429
  pncli confluence get-page-children
@@ -352,7 +477,7 @@ pncli confluence remove-label
352
477
 
353
478
  pncli confluence list-spaces
354
479
  --type <type> Space type: global or personal
355
- --limit <n> Max results (default: all)
480
+ --limit <n> Max total spaces to return (default: all)
356
481
 
357
482
  pncli confluence get-space
358
483
  --key <space-key> Space key
@@ -605,6 +730,27 @@ pncli ado work add-comment
605
730
  --id <n> Work item ID
606
731
  --body <text> Comment text
607
732
 
733
+ pncli ado work add-tag
734
+ --id <n> Work item ID
735
+ --tags <tags> Semicolon- or comma-separated tags to add
736
+
737
+ pncli ado work remove-tag
738
+ --id <n> Work item ID
739
+ --tags <tags> Semicolon- or comma-separated tags to remove
740
+
741
+ pncli ado work list-attachments
742
+ --id <n> Work item ID
743
+
744
+ pncli ado work add-attachment
745
+ --id <n> Work item ID
746
+ --file <path> Path to the file to upload
747
+ --comment <text> Optional comment for the attachment
748
+
749
+ pncli ado work download-attachment
750
+ --id <n> Work item ID
751
+ --attachment-id <guid> Attachment ID from work list-attachments output
752
+ --dir <path> Output directory (default: .pncli relative to cwd)
753
+
608
754
  pncli ado work types
609
755
  --discover Fetch from server (always true for this command)
610
756
  --save Save discovered types to ~/.pncli/config.json
@@ -723,6 +869,8 @@ pncli ado pipeline run
723
869
 
724
870
  pncli ado pipeline list-runs
725
871
  --definition <id> Filter by definition ID
872
+ --name <name> Filter by pipeline name (resolved to definition ID; use
873
+ pipeline list to see names)
726
874
  --branch <ref> Filter by branch name
727
875
  --status <filter> Filter by status (inProgress|completed|cancelling|...)
728
876
  --top <n> Maximum results (default: "50")
@@ -734,20 +882,24 @@ pncli ado pipeline cancel-run
734
882
  --id <n> Build ID
735
883
 
736
884
  pncli ado pipeline logs
737
- --id <n> Build ID
738
- --log-id <n> Specific log ID (omit to list all logs)
885
+ --build-id <n> Build (run) ID — from pipeline list-runs or get-run
886
+ --id <n> Build (run) ID — alias for --build-id (kept for backwards
887
+ compatibility)
888
+ --log-id <n> Specific log ID (omit to list all logs)
739
889
  ```
740
890
 
741
891
  ### Jenkins
742
892
 
743
893
  ```
744
894
  pncli jenkins pipeline list
895
+ --folder <name> Folder name to enumerate (supports nested folders:
896
+ parentFolder/childFolder)
745
897
 
746
898
  pncli jenkins pipeline get
747
- --name <job> Job name
899
+ --name <job> Job name (use folder/job for folder-scoped jobs)
748
900
 
749
901
  pncli jenkins pipeline run
750
- --name <job> Job name
902
+ --name <job> Job name (use folder/job for folder-scoped jobs)
751
903
  --parameter <k=v> Build parameter (repeatable) (default: [])
752
904
  --wait Wait for the build to complete before returning
753
905
  --timeout <s> Max wait time in seconds per phase (queue-wait and
@@ -756,15 +908,15 @@ pncli jenkins pipeline run
756
908
  --poll <s> Poll interval in seconds (default 10) (default: "10")
757
909
 
758
910
  pncli jenkins pipeline list-runs
759
- --name <job> Job name
911
+ --name <job> Job name (use folder/job for folder-scoped jobs)
760
912
  --top <n> Maximum number of builds to return (default 25) (default: "25")
761
913
 
762
914
  pncli jenkins pipeline get-run
763
- --name <job> Job name
915
+ --name <job> Job name (use folder/job for folder-scoped jobs)
764
916
  --number <n> Build number
765
917
 
766
918
  pncli jenkins pipeline logs
767
- --name <job> Job name
919
+ --name <job> Job name (use folder/job for folder-scoped jobs)
768
920
  --number <n> Build number
769
921
  ```
770
922
 
@@ -795,6 +947,8 @@ pncli artifactory search
795
947
  --properties Include artifact properties in results (default: false)
796
948
 
797
949
  pncli artifactory builds
950
+ --timeout <s> Request timeout in seconds (default 60; increase for large
951
+ Artifactory instances) (default: "60")
798
952
 
799
953
  pncli artifactory build-runs
800
954
 
@@ -946,12 +1100,51 @@ pncli skills list
946
1100
  --target <dir> Override skills directory to scan
947
1101
 
948
1102
  pncli skills marketplace setup
949
- --branch <branch> Branch to clone (default: "master")
950
- --token <token> Bitbucket HTTP access token for authenticated clone and
951
- pull
1103
+ --branch <branch> Branch to clone (default: remote HEAD)
1104
+ --token <token> HTTP access token for authenticated clone and pull (GitHub
1105
+ PAT or Bitbucket token)
1106
+ --agent <agent> Target agent host for plugin install: github-copilot |
1107
+ claude-code (default: github-copilot)
1108
+ --claude Shorthand for --agent claude-code
952
1109
 
953
1110
  pncli skills marketplace sync
954
- --claude Install to ~/.claude/skills instead of ~/.agents/skills
1111
+ --agent <agent> Target agent host: github-copilot | claude-code (default:
1112
+ github-copilot)
1113
+ --claude Shorthand for --agent claude-code
1114
+ --force Force reinstall even if the marketplace repo has no new
1115
+ changes
1116
+ ```
1117
+
1118
+ ### Jwt
1119
+
1120
+ ```
1121
+ pncli jwt decode
1122
+ ```
1123
+
1124
+ ### Openshift
1125
+
1126
+ ```
1127
+ pncli openshift pods
1128
+ --namespace <ns> Kubernetes namespace
1129
+ --label-selector <selector> Label selector (e.g. app=my-app)
1130
+
1131
+ pncli openshift events
1132
+ --namespace <ns> Kubernetes namespace
1133
+ --field-selector <selector> Additional field selector (e.g.
1134
+ involvedObject.name=my-pod)
1135
+ --all Include Normal events in addition to Warning
1136
+ events (default: false)
1137
+
1138
+ pncli openshift logs
1139
+ --namespace <ns> Kubernetes namespace
1140
+ --pod <name> Pod name
1141
+ --container <name> Container name (defaults to first container)
1142
+ --lines <n> Number of most-recent lines to return (default: "100")
1143
+ --previous Return logs from the previous container instance (default:
1144
+ false)
1145
+
1146
+ pncli openshift pod-metrics
1147
+ --namespace <ns> Kubernetes namespace
955
1148
  ```
956
1149
 
957
1150
  <!-- COMMAND-REFERENCE:END -->
@@ -12,6 +12,8 @@ var ENV_KEYS = {
12
12
  JIRA_API_TOKEN: "PNCLI_JIRA_API_TOKEN",
13
13
  BITBUCKET_BASE_URL: "PNCLI_BITBUCKET_BASE_URL",
14
14
  BITBUCKET_PAT: "PNCLI_BITBUCKET_PAT",
15
+ GITHUB_BASE_URL: "PNCLI_GITHUB_BASE_URL",
16
+ GITHUB_TOKEN: "PNCLI_GITHUB_TOKEN",
15
17
  CONFLUENCE_BASE_URL: "PNCLI_CONFLUENCE_BASE_URL",
16
18
  CONFLUENCE_API_TOKEN: "PNCLI_CONFLUENCE_API_TOKEN",
17
19
  ARTIFACTORY_BASE_URL: "PNCLI_ARTIFACTORY_BASE_URL",
@@ -89,6 +91,7 @@ function mergeDefaults(global, repo) {
89
91
  return {
90
92
  jira: { ...global?.jira, ...repo?.jira },
91
93
  bitbucket: { ...global?.bitbucket, ...repo?.bitbucket },
94
+ github: { ...global?.github, ...repo?.github },
92
95
  sonar: { ...global?.sonar, ...repo?.sonar },
93
96
  sde: { ...global?.sde, ...repo?.sde },
94
97
  ado: { ...global?.ado, ...repo?.ado },
@@ -118,6 +121,10 @@ function loadConfig(opts = {}) {
118
121
  baseUrl: process.env[ENV_KEYS.BITBUCKET_BASE_URL] ?? globalConfig.bitbucket?.baseUrl,
119
122
  pat: process.env[ENV_KEYS.BITBUCKET_PAT] ?? globalConfig.bitbucket?.pat
120
123
  },
124
+ github: {
125
+ baseUrl: process.env[ENV_KEYS.GITHUB_BASE_URL] ?? globalConfig.github?.baseUrl,
126
+ token: process.env[ENV_KEYS.GITHUB_TOKEN] ?? globalConfig.github?.token
127
+ },
121
128
  confluence: {
122
129
  baseUrl: process.env[ENV_KEYS.CONFLUENCE_BASE_URL] ?? globalConfig.confluence?.baseUrl,
123
130
  apiToken: process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken ?? process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,
@@ -244,6 +251,10 @@ function maskConfig(config) {
244
251
  ...config.bitbucket,
245
252
  pat: config.bitbucket.pat ? "***" : void 0
246
253
  },
254
+ github: {
255
+ ...config.github,
256
+ token: config.github.token ? "***" : void 0
257
+ },
247
258
  confluence: {
248
259
  ...config.confluence,
249
260
  apiToken: config.confluence.apiToken ? "***" : void 0
@@ -308,4 +319,4 @@ export {
308
319
  setRepoConfigValue,
309
320
  maskConfig
310
321
  };
311
- //# sourceMappingURL=chunk-CFUUOW7B.js.map
322
+ //# sourceMappingURL=chunk-P5NWDQ2B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/config.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, UdeployDefaults } from '../types/config.js';\nimport type { CustomFieldDefinition } from '../types/jira.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 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 SDE_CONNECTION: 'PNCLI_SDE_CONNECTION',\n ADO_BASE_URL: 'PNCLI_ADO_BASE_URL',\n ADO_PAT: 'PNCLI_ADO_PAT',\n JENKINS_BASE_URL: 'PNCLI_JENKINS_BASE_URL',\n JENKINS_USERNAME: 'PNCLI_JENKINS_USERNAME',\n JENKINS_API_TOKEN: 'PNCLI_JENKINS_API_TOKEN',\n UDEPLOY_BASE_URL: 'PNCLI_UDEPLOY_BASE_URL',\n UDEPLOY_PAT: 'PNCLI_UDEPLOY_PAT',\n UDEPLOY_USERNAME: 'PNCLI_UDEPLOY_USERNAME',\n UDEPLOY_PASSWORD: 'PNCLI_UDEPLOY_PASSWORD',\n CHECKMARX_BASE_URL: 'PNCLI_CHECKMARX_BASE_URL',\n CHECKMARX_USERNAME: 'PNCLI_CHECKMARX_USERNAME',\n CHECKMARX_PASSWORD: 'PNCLI_CHECKMARX_PASSWORD',\n SERVICENOW_BASE_URL: 'PNCLI_SERVICENOW_BASE_URL',\n SERVICENOW_USERNAME: 'PNCLI_SERVICENOW_USERNAME',\n SERVICENOW_PASSWORD: 'PNCLI_SERVICENOW_PASSWORD',\n SERVICENOW_API_TOKEN: 'PNCLI_SERVICENOW_API_TOKEN',\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 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 for (const f of global ?? []) map.set(f.id, f);\n for (const f of repo ?? []) map.set(f.id, f); // repo wins\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; udeploy: UdeployDefaults } {\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 udeploy: { ...global?.udeploy, ...repo?.udeploy }\n };\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n}\n\nexport function loadConfig(opts: LoadConfigOptions = {}): ResolvedConfig {\n const globalConfigPath = getGlobalConfigPath(opts.configPath);\n const globalConfig = loadJsonFile<GlobalConfig>(globalConfigPath) ?? {};\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] ?? globalConfig.github?.baseUrl,\n token: process.env[ENV_KEYS.GITHUB_TOKEN] ?? 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] ?? 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] ?? globalConfig.ado?.pat,\n fieldAliases: globalConfig.ado?.fieldAliases ?? {},\n discoveredFields: globalConfig.ado?.discoveredFields ?? [],\n discoveredTypes: globalConfig.ado?.discoveredTypes ?? []\n },\n jenkins: {\n 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 udeploy: {\n baseUrl: process.env[ENV_KEYS.UDEPLOY_BASE_URL] ?? globalConfig.udeploy?.baseUrl,\n pat: process.env[ENV_KEYS.UDEPLOY_PAT] ?? globalConfig.udeploy?.pat,\n username: process.env[ENV_KEYS.UDEPLOY_USERNAME] ?? globalConfig.udeploy?.username,\n password: process.env[ENV_KEYS.UDEPLOY_PASSWORD] ?? globalConfig.udeploy?.password,\n },\n checkmarx: {\n baseUrl: process.env[ENV_KEYS.CHECKMARX_BASE_URL] ?? globalConfig.checkmarx?.baseUrl,\n username: process.env[ENV_KEYS.CHECKMARX_USERNAME] ?? globalConfig.checkmarx?.username,\n password: process.env[ENV_KEYS.CHECKMARX_PASSWORD] ?? globalConfig.checkmarx?.password,\n },\n servicenow: {\n baseUrl: process.env[ENV_KEYS.SERVICENOW_BASE_URL] ?? globalConfig.servicenow?.baseUrl,\n username: process.env[ENV_KEYS.SERVICENOW_USERNAME] ?? globalConfig.servicenow?.username,\n password: process.env[ENV_KEYS.SERVICENOW_PASSWORD] ?? globalConfig.servicenow?.password,\n apiToken: process.env[ENV_KEYS.SERVICENOW_API_TOKEN] ?? globalConfig.servicenow?.apiToken,\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 },\n defaults: mergedDefaults\n };\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\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]!] = 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]!] = 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 udeploy: {\n ...config.udeploy,\n pat: config.udeploy.pat ? '***' : undefined,\n password: config.udeploy.password ? '***' : undefined\n },\n checkmarx: {\n ...config.checkmarx,\n password: config.checkmarx.password ? '***' : undefined\n },\n servicenow: {\n ...config.servicenow,\n password: config.servicenow.password ? '***' : undefined,\n apiToken: config.servicenow.apiToken ? '***' : 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 }\n };\n}\n\nexport { getGlobalConfigPath, loadJsonFile };\n"],"mappings":"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","names":[]}
@@ -36,13 +36,16 @@ function exitCodeFromStatus(httpStatus) {
36
36
  // src/lib/output.ts
37
37
  import fs from "fs";
38
38
  import chalk from "chalk";
39
- var globalOptions = { pretty: false, verbose: false };
39
+ var globalOptions = { pretty: false, verbose: false, debug: false };
40
40
  var globalUser = { email: void 0, userId: void 0 };
41
41
  var outputFile;
42
42
  function setGlobalOptions(opts) {
43
- globalOptions = { pretty: opts.pretty, verbose: opts.verbose };
43
+ globalOptions = { pretty: opts.pretty, verbose: opts.verbose, debug: opts.debug ?? false };
44
44
  outputFile = opts.outputFile;
45
45
  }
46
+ function isDebugEnabled() {
47
+ return globalOptions.debug;
48
+ }
46
49
  function setGlobalUser(user) {
47
50
  globalUser = user;
48
51
  }
@@ -120,6 +123,13 @@ function log(message) {
120
123
  );
121
124
  }
122
125
  }
126
+ function debug(message) {
127
+ if (globalOptions.debug) {
128
+ process.stderr.write(
129
+ (globalOptions.pretty ? chalk.cyan("\u2B21 ") : "") + message + "\n"
130
+ );
131
+ }
132
+ }
123
133
  function warn(message) {
124
134
  process.stderr.write(
125
135
  (globalOptions.pretty ? chalk.yellow("\u26A0 ") : "") + message + "\n"
@@ -212,6 +222,21 @@ function buildCheckmarxFetcher(config) {
212
222
  }
213
223
 
214
224
  // src/lib/http.ts
225
+ var SENSITIVE_HEADERS = /* @__PURE__ */ new Set(["authorization", "api-key"]);
226
+ function redactHeaders(headers) {
227
+ if (!headers) return {};
228
+ let entries;
229
+ if (headers instanceof Headers) {
230
+ entries = [...headers.entries()];
231
+ } else if (Array.isArray(headers)) {
232
+ entries = headers;
233
+ } else {
234
+ entries = Object.entries(headers);
235
+ }
236
+ return Object.fromEntries(
237
+ entries.map(([k, v]) => [k, SENSITIVE_HEADERS.has(k.toLowerCase()) ? "[REDACTED]" : v])
238
+ );
239
+ }
215
240
  function buildUrl(base, path, params) {
216
241
  const url = new URL(path, base.endsWith("/") ? base : base + "/");
217
242
  if (params) {
@@ -234,17 +259,26 @@ async function fetchWithTimeout(url, init, timeoutMs, fetcher = fetch) {
234
259
  }
235
260
  async function request(url, init, timeoutMs, fetcher = fetch) {
236
261
  let lastError;
262
+ if (isDebugEnabled()) {
263
+ const method = (init.method ?? "GET").toUpperCase();
264
+ const safeHeaders = redactHeaders(init.headers);
265
+ debug(`\u2192 ${method} ${url}`);
266
+ debug(` Headers: ${JSON.stringify(safeHeaders)}`);
267
+ }
237
268
  for (let attempt = 0; attempt < 3; attempt++) {
238
269
  let response;
270
+ const reqStart = Date.now();
239
271
  try {
240
272
  response = await fetchWithTimeout(url, init, timeoutMs, fetcher);
241
273
  } catch (err) {
274
+ debug(` Error: ${err instanceof Error ? err.message : String(err)}`);
242
275
  throw new PncliError(
243
276
  `Request failed: ${err instanceof Error ? err.message : String(err)}`,
244
277
  0,
245
278
  url
246
279
  );
247
280
  }
281
+ debug(`\u2190 ${response.status} ${response.statusText} (${Date.now() - reqStart}ms)`);
248
282
  if (response.status === 429) {
249
283
  const retryAfter = response.headers.get("Retry-After");
250
284
  const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1e3 : (attempt + 1) * 1e3;
@@ -322,6 +356,17 @@ var HttpClient = class {
322
356
  "Connection": "close"
323
357
  };
324
358
  }
359
+ githubHeaders() {
360
+ const { token } = this.config.github;
361
+ if (!token) throw new PncliError("GitHub credentials not configured. Run: pncli config init");
362
+ return {
363
+ "Authorization": `Bearer ${token}`,
364
+ "Content-Type": "application/json",
365
+ "Accept": "application/vnd.github+json",
366
+ "X-GitHub-Api-Version": "2022-11-28",
367
+ "Connection": "close"
368
+ };
369
+ }
325
370
  async jira(path, opts = {}) {
326
371
  const baseUrl = this.config.jira.baseUrl;
327
372
  if (!baseUrl) throw new PncliError("Jira baseUrl not configured. Run: pncli config init");
@@ -423,6 +468,71 @@ Body: <multipart/form-data>
423
468
  }
424
469
  return request(url, { method: "POST", headers, body: formData }, opts.timeoutMs ?? 6e4);
425
470
  }
471
+ async github(path, opts = {}) {
472
+ const baseUrl = this.config.github.baseUrl;
473
+ if (!baseUrl) throw new PncliError("GitHub baseUrl not configured. Run: pncli config init");
474
+ const url = buildUrl(baseUrl, path, opts.params);
475
+ const headers = this.githubHeaders();
476
+ const init = {
477
+ method: opts.method ?? "GET",
478
+ headers,
479
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
480
+ };
481
+ if (this.dryRun) {
482
+ const safeHeaders = { ...headers, Authorization: "[REDACTED]" };
483
+ const msg = `DRY RUN: ${init.method} ${url}
484
+ Headers: ${JSON.stringify(safeHeaders, null, 2)}
485
+ ` + (opts.body ? `Body: ${JSON.stringify(opts.body, null, 2)}
486
+ ` : "");
487
+ fs2.writeSync(process.stderr.fd, msg);
488
+ process.exitCode = ExitCode.SUCCESS;
489
+ throw new PncliError("dry-run", 0);
490
+ }
491
+ return request(url, init, opts.timeoutMs ?? 3e4);
492
+ }
493
+ async githubText(path, opts = {}) {
494
+ const baseUrl = this.config.github.baseUrl;
495
+ if (!baseUrl) throw new PncliError("GitHub baseUrl not configured. Run: pncli config init");
496
+ const url = buildUrl(baseUrl, path, opts.params);
497
+ const headers = {
498
+ ...this.githubHeaders(),
499
+ "Accept": "application/vnd.github.v3.diff"
500
+ };
501
+ if (this.dryRun) {
502
+ const safeHeaders = { ...headers, Authorization: "[REDACTED]" };
503
+ fs2.writeSync(process.stderr.fd, `DRY RUN: ${opts.method ?? "GET"} ${url}
504
+ Headers: ${JSON.stringify(safeHeaders, null, 2)}
505
+ `);
506
+ process.exitCode = ExitCode.SUCCESS;
507
+ throw new PncliError("dry-run", 0);
508
+ }
509
+ const response = await fetchWithTimeout(url, {
510
+ method: opts.method ?? "GET",
511
+ headers
512
+ }, opts.timeoutMs ?? 3e4);
513
+ if (!response.ok) {
514
+ let message = `HTTP ${response.status} ${response.statusText}`;
515
+ try {
516
+ const parsed = JSON.parse(await response.text());
517
+ if (parsed.message) message = String(parsed.message);
518
+ } catch {
519
+ }
520
+ throw new PncliError(message, response.status, url);
521
+ }
522
+ return response.text();
523
+ }
524
+ async githubPaginate(fetchPage) {
525
+ const results = [];
526
+ let page = 1;
527
+ const perPage = 100;
528
+ while (true) {
529
+ const items = await fetchPage(page, perPage);
530
+ results.push(...items);
531
+ if (items.length < perPage) break;
532
+ page++;
533
+ }
534
+ return results;
535
+ }
426
536
  async bitbucket(path, opts = {}) {
427
537
  const baseUrl = this.config.bitbucket.baseUrl;
428
538
  if (!baseUrl) throw new PncliError("Bitbucket baseUrl not configured. Run: pncli config init");
@@ -1030,7 +1140,7 @@ Headers: ${JSON.stringify(safeHeaders, null, 2)}
1030
1140
  const url = buildUrl(baseUrl, path, params);
1031
1141
  const headers = {
1032
1142
  "Authorization": this.openshiftHeaders()["Authorization"],
1033
- "Accept": "text/plain",
1143
+ "Accept": "*/*",
1034
1144
  "Connection": "close"
1035
1145
  };
1036
1146
  if (this.dryRun) {
@@ -1091,4 +1201,4 @@ export {
1091
1201
  HttpClient,
1092
1202
  createHttpClient
1093
1203
  };
1094
- //# sourceMappingURL=chunk-BNMFIGXF.js.map
1204
+ //# sourceMappingURL=chunk-XPPEXJBP.js.map