@kolatts/pncli 1.15.0 → 1.17.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,37 @@ 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)
224
+
225
+ pncli jira list-boards
226
+ --project <key> Project key
227
+
228
+ pncli jira list-sprints
229
+ --board <id> Board ID
230
+ --project <key> Project key — resolves to that project's board(s)
231
+ --state <states> Comma-separated states to filter (active,future,closed)
232
+
233
+ pncli jira set-sprint
234
+ --key <issue-key> Issue key
235
+ --sprint <id> Sprint ID (from list-sprints)
194
236
  ```
195
237
 
196
238
  ### Bitbucket
@@ -210,6 +252,9 @@ pncli bitbucket create-pr
210
252
  --target <branch> Target branch (defaults to config)
211
253
  --description <desc> PR description
212
254
  --reviewers <users> Comma-separated reviewer usernames
255
+ --project <key> Bitbucket project key (overrides parent --project; use
256
+ ~username for personal repos)
257
+ --repo <slug> Bitbucket repository slug (overrides parent --repo)
213
258
 
214
259
  pncli bitbucket update-pr
215
260
  --id <pr-id> Pull request ID
@@ -284,6 +329,98 @@ pncli bitbucket get-build-status
284
329
  --commit <sha> Commit SHA
285
330
  ```
286
331
 
332
+ ### Github
333
+
334
+ ```
335
+ pncli github list-prs
336
+ --state <state> PR state (choices: "open", "closed", "all", default: "open")
337
+ --head <branch> Filter by head branch (user:branch)
338
+ --base <branch> Filter by base branch
339
+
340
+ pncli github get-pr
341
+ --number <n> Pull request number
342
+
343
+ pncli github create-pr
344
+ --title <title> PR title
345
+ --head <branch> Source branch (or user:branch for forks)
346
+ --base <branch> Target branch (defaults to config or main)
347
+ --body <body> PR description
348
+ --draft Create as draft PR
349
+ --owner <owner> GitHub owner (overrides parent --owner)
350
+ --repo <repo> GitHub repository name (overrides parent --repo)
351
+
352
+ pncli github update-pr
353
+ --number <n> Pull request number
354
+ --title <title> New title
355
+ --body <body> New description
356
+ --base <branch> New base branch
357
+
358
+ pncli github merge-pr
359
+ --number <n> Pull request number
360
+ --method <method> Merge method (choices: "merge", "squash", "rebase",
361
+ default: "merge")
362
+ --commit-title <title> Commit title for merge/squash
363
+ --commit-message <msg> Commit message for merge/squash
364
+
365
+ pncli github close-pr
366
+ --number <n> Pull request number
367
+
368
+ pncli github list-comments
369
+ --number <n> Pull request number
370
+
371
+ pncli github add-comment
372
+ --number <n> Pull request number
373
+ --body <text> Comment text
374
+
375
+ pncli github list-review-comments
376
+ --number <n> Pull request number
377
+
378
+ pncli github add-inline-comment
379
+ --number <n> Pull request number
380
+ --commit <sha> Commit SHA the comment is on
381
+ --file <path> File path
382
+ --line <n> Line number
383
+ --body <text> Comment text
384
+ --side <side> Comment side (choices: "LEFT", "RIGHT", default: "RIGHT")
385
+
386
+ pncli github reply-comment
387
+ --number <n> Pull request number
388
+ --comment-id <id> Review comment ID to reply to
389
+ --body <text> Reply text
390
+
391
+ pncli github delete-comment
392
+ --comment-id <id> Comment ID
393
+
394
+ pncli github delete-review-comment
395
+ --comment-id <id> Review comment ID
396
+
397
+ pncli github diff
398
+ --number <n> Pull request number
399
+
400
+ pncli github list-files
401
+ --number <n> Pull request number
402
+
403
+ pncli github list-reviews
404
+ --number <n> Pull request number
405
+
406
+ pncli github approve
407
+ --number <n> Pull request number
408
+ --body <text> Review body text
409
+
410
+ pncli github request-changes
411
+ --number <n> Pull request number
412
+ --body <text> Review feedback text
413
+
414
+ pncli github list-reviewers
415
+ --number <n> Pull request number
416
+
417
+ pncli github get-status
418
+ --ref <ref> Git ref (branch, tag, or commit SHA)
419
+
420
+ pncli github list-checks
421
+ --ref <ref> Git ref (branch, tag, or commit SHA)
422
+ ```
423
+
287
424
  ### Confluence
288
425
 
289
426
  ```
@@ -298,7 +435,7 @@ pncli confluence get-page-by-title
298
435
 
299
436
  pncli confluence list-pages
300
437
  --space <key> Space key
301
- --limit <n> Max results per page (default: all)
438
+ --limit <n> Max total pages to return (default: all)
302
439
  --start <n> Offset for first result
303
440
 
304
441
  pncli confluence get-page-children
@@ -352,7 +489,7 @@ pncli confluence remove-label
352
489
 
353
490
  pncli confluence list-spaces
354
491
  --type <type> Space type: global or personal
355
- --limit <n> Max results (default: all)
492
+ --limit <n> Max total spaces to return (default: all)
356
493
 
357
494
  pncli confluence get-space
358
495
  --key <space-key> Space key
@@ -605,6 +742,27 @@ pncli ado work add-comment
605
742
  --id <n> Work item ID
606
743
  --body <text> Comment text
607
744
 
745
+ pncli ado work add-tag
746
+ --id <n> Work item ID
747
+ --tags <tags> Semicolon- or comma-separated tags to add
748
+
749
+ pncli ado work remove-tag
750
+ --id <n> Work item ID
751
+ --tags <tags> Semicolon- or comma-separated tags to remove
752
+
753
+ pncli ado work list-attachments
754
+ --id <n> Work item ID
755
+
756
+ pncli ado work add-attachment
757
+ --id <n> Work item ID
758
+ --file <path> Path to the file to upload
759
+ --comment <text> Optional comment for the attachment
760
+
761
+ pncli ado work download-attachment
762
+ --id <n> Work item ID
763
+ --attachment-id <guid> Attachment ID from work list-attachments output
764
+ --dir <path> Output directory (default: .pncli relative to cwd)
765
+
608
766
  pncli ado work types
609
767
  --discover Fetch from server (always true for this command)
610
768
  --save Save discovered types to ~/.pncli/config.json
@@ -723,6 +881,8 @@ pncli ado pipeline run
723
881
 
724
882
  pncli ado pipeline list-runs
725
883
  --definition <id> Filter by definition ID
884
+ --name <name> Filter by pipeline name (resolved to definition ID; use
885
+ pipeline list to see names)
726
886
  --branch <ref> Filter by branch name
727
887
  --status <filter> Filter by status (inProgress|completed|cancelling|...)
728
888
  --top <n> Maximum results (default: "50")
@@ -734,20 +894,24 @@ pncli ado pipeline cancel-run
734
894
  --id <n> Build ID
735
895
 
736
896
  pncli ado pipeline logs
737
- --id <n> Build ID
738
- --log-id <n> Specific log ID (omit to list all logs)
897
+ --build-id <n> Build (run) ID — from pipeline list-runs or get-run
898
+ --id <n> Build (run) ID — alias for --build-id (kept for backwards
899
+ compatibility)
900
+ --log-id <n> Specific log ID (omit to list all logs)
739
901
  ```
740
902
 
741
903
  ### Jenkins
742
904
 
743
905
  ```
744
906
  pncli jenkins pipeline list
907
+ --folder <name> Folder name to enumerate (supports nested folders:
908
+ parentFolder/childFolder)
745
909
 
746
910
  pncli jenkins pipeline get
747
- --name <job> Job name
911
+ --name <job> Job name (use folder/job for folder-scoped jobs)
748
912
 
749
913
  pncli jenkins pipeline run
750
- --name <job> Job name
914
+ --name <job> Job name (use folder/job for folder-scoped jobs)
751
915
  --parameter <k=v> Build parameter (repeatable) (default: [])
752
916
  --wait Wait for the build to complete before returning
753
917
  --timeout <s> Max wait time in seconds per phase (queue-wait and
@@ -756,15 +920,15 @@ pncli jenkins pipeline run
756
920
  --poll <s> Poll interval in seconds (default 10) (default: "10")
757
921
 
758
922
  pncli jenkins pipeline list-runs
759
- --name <job> Job name
923
+ --name <job> Job name (use folder/job for folder-scoped jobs)
760
924
  --top <n> Maximum number of builds to return (default 25) (default: "25")
761
925
 
762
926
  pncli jenkins pipeline get-run
763
- --name <job> Job name
927
+ --name <job> Job name (use folder/job for folder-scoped jobs)
764
928
  --number <n> Build number
765
929
 
766
930
  pncli jenkins pipeline logs
767
- --name <job> Job name
931
+ --name <job> Job name (use folder/job for folder-scoped jobs)
768
932
  --number <n> Build number
769
933
  ```
770
934
 
@@ -795,6 +959,8 @@ pncli artifactory search
795
959
  --properties Include artifact properties in results (default: false)
796
960
 
797
961
  pncli artifactory builds
962
+ --timeout <s> Request timeout in seconds (default 60; increase for large
963
+ Artifactory instances) (default: "60")
798
964
 
799
965
  pncli artifactory build-runs
800
966
 
@@ -945,13 +1111,80 @@ pncli skills list
945
1111
  --scope <scope> Installation scope: project | user (default: "project")
946
1112
  --target <dir> Override skills directory to scan
947
1113
 
1114
+ pncli skills uninstall
1115
+ --agent <agent> Target agent host: github-copilot | claude-code (default:
1116
+ "github-copilot")
1117
+ --scope <scope> Installation scope to uninstall from: project | user
1118
+ (default: "user")
1119
+ --claude Shorthand for --agent claude-code
1120
+ --target <dir> Override skills directory
1121
+
1122
+ pncli skills marketplace add
1123
+ --name <name> Human-readable name for this marketplace (default: derived
1124
+ from URL)
1125
+ --branch <branch> Branch to clone (default: remote HEAD)
1126
+ --token <token> HTTP access token for authenticated clone and pull (GitHub
1127
+ PAT or Bitbucket token)
1128
+ --agent <agent> Target agent host for plugin install: github-copilot |
1129
+ claude-code (default: github-copilot)
1130
+ --claude Shorthand for --agent claude-code
1131
+
948
1132
  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
1133
+ --name <name> Human-readable name for this marketplace (default: derived
1134
+ from URL)
1135
+ --branch <branch> Branch to clone (default: remote HEAD)
1136
+ --token <token> HTTP access token for authenticated clone and pull (GitHub
1137
+ PAT or Bitbucket token)
1138
+ --agent <agent> Target agent host for plugin install: github-copilot |
1139
+ claude-code (default: github-copilot)
1140
+ --claude Shorthand for --agent claude-code
1141
+
1142
+ pncli skills marketplace list
1143
+
1144
+ pncli skills marketplace plugins
1145
+
1146
+ pncli skills marketplace remove
952
1147
 
953
1148
  pncli skills marketplace sync
954
- --claude Install to ~/.claude/skills instead of ~/.agents/skills
1149
+ --marketplace <name> Marketplace name to sync, or "all" to sync every
1150
+ registered marketplace (skips interactive selection)
1151
+ --agent <agent> Target agent host: github-copilot | claude-code
1152
+ (default: github-copilot)
1153
+ --claude Shorthand for --agent claude-code
1154
+ --force Reinstall even if a marketplace has no new changes
1155
+ (applies to single-plugin and "all" installs alike)
1156
+ ```
1157
+
1158
+ ### Jwt
1159
+
1160
+ ```
1161
+ pncli jwt decode
1162
+ ```
1163
+
1164
+ ### Openshift
1165
+
1166
+ ```
1167
+ pncli openshift pods
1168
+ --namespace <ns> Kubernetes namespace
1169
+ --label-selector <selector> Label selector (e.g. app=my-app)
1170
+
1171
+ pncli openshift events
1172
+ --namespace <ns> Kubernetes namespace
1173
+ --field-selector <selector> Additional field selector (e.g.
1174
+ involvedObject.name=my-pod)
1175
+ --all Include Normal events in addition to Warning
1176
+ events (default: false)
1177
+
1178
+ pncli openshift logs
1179
+ --namespace <ns> Kubernetes namespace
1180
+ --pod <name> Pod name
1181
+ --container <name> Container name (defaults to first container)
1182
+ --lines <n> Number of most-recent lines to return (default: "100")
1183
+ --previous Return logs from the previous container instance (default:
1184
+ false)
1185
+
1186
+ pncli openshift pod-metrics
1187
+ --namespace <ns> Kubernetes namespace
955
1188
  ```
956
1189
 
957
1190
  <!-- 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,10 +91,12 @@ 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 },
95
- udeploy: { ...global?.udeploy, ...repo?.udeploy }
98
+ udeploy: { ...global?.udeploy, ...repo?.udeploy },
99
+ jenkins: { ...global?.jenkins, ...repo?.jenkins }
96
100
  };
97
101
  }
98
102
  function loadConfig(opts = {}) {
@@ -118,6 +122,10 @@ function loadConfig(opts = {}) {
118
122
  baseUrl: process.env[ENV_KEYS.BITBUCKET_BASE_URL] ?? globalConfig.bitbucket?.baseUrl,
119
123
  pat: process.env[ENV_KEYS.BITBUCKET_PAT] ?? globalConfig.bitbucket?.pat
120
124
  },
125
+ github: {
126
+ baseUrl: process.env[ENV_KEYS.GITHUB_BASE_URL] ?? globalConfig.github?.baseUrl,
127
+ token: process.env[ENV_KEYS.GITHUB_TOKEN] ?? globalConfig.github?.token
128
+ },
121
129
  confluence: {
122
130
  baseUrl: process.env[ENV_KEYS.CONFLUENCE_BASE_URL] ?? globalConfig.confluence?.baseUrl,
123
131
  apiToken: process.env[ENV_KEYS.CONFLUENCE_API_TOKEN] ?? globalConfig.confluence?.apiToken ?? process.env[ENV_KEYS.JIRA_API_TOKEN] ?? globalConfig.jira?.apiToken,
@@ -147,7 +155,7 @@ function loadConfig(opts = {}) {
147
155
  discoveredTypes: globalConfig.ado?.discoveredTypes ?? []
148
156
  },
149
157
  jenkins: {
150
- baseUrl: process.env[ENV_KEYS.JENKINS_BASE_URL] ?? globalConfig.jenkins?.baseUrl,
158
+ baseUrl: repoConfig.defaults?.jenkins?.baseUrl ?? process.env[ENV_KEYS.JENKINS_BASE_URL] ?? globalConfig.jenkins?.baseUrl,
151
159
  username: process.env[ENV_KEYS.JENKINS_USERNAME] ?? globalConfig.jenkins?.username,
152
160
  apiToken: process.env[ENV_KEYS.JENKINS_API_TOKEN] ?? globalConfig.jenkins?.apiToken
153
161
  },
@@ -244,6 +252,10 @@ function maskConfig(config) {
244
252
  ...config.bitbucket,
245
253
  pat: config.bitbucket.pat ? "***" : void 0
246
254
  },
255
+ github: {
256
+ ...config.github,
257
+ token: config.github.token ? "***" : void 0
258
+ },
247
259
  confluence: {
248
260
  ...config.confluence,
249
261
  apiToken: config.confluence.apiToken ? "***" : void 0
@@ -308,4 +320,4 @@ export {
308
320
  setRepoConfigValue,
309
321
  maskConfig
310
322
  };
311
- //# sourceMappingURL=chunk-CFUUOW7B.js.map
323
+ //# sourceMappingURL=chunk-FFVQ4PA7.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, JenkinsDefaults } 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; 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 udeploy: { ...global?.udeploy, ...repo?.udeploy },\n jenkins: { ...global?.jenkins, ...repo?.jenkins }\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: 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 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":[]}
@@ -356,6 +356,17 @@ var HttpClient = class {
356
356
  "Connection": "close"
357
357
  };
358
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
+ }
359
370
  async jira(path, opts = {}) {
360
371
  const baseUrl = this.config.jira.baseUrl;
361
372
  if (!baseUrl) throw new PncliError("Jira baseUrl not configured. Run: pncli config init");
@@ -457,6 +468,71 @@ Body: <multipart/form-data>
457
468
  }
458
469
  return request(url, { method: "POST", headers, body: formData }, opts.timeoutMs ?? 6e4);
459
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
+ }
460
536
  async bitbucket(path, opts = {}) {
461
537
  const baseUrl = this.config.bitbucket.baseUrl;
462
538
  if (!baseUrl) throw new PncliError("Bitbucket baseUrl not configured. Run: pncli config init");
@@ -1125,4 +1201,4 @@ export {
1125
1201
  HttpClient,
1126
1202
  createHttpClient
1127
1203
  };
1128
- //# sourceMappingURL=chunk-YHRFL7VX.js.map
1204
+ //# sourceMappingURL=chunk-XPPEXJBP.js.map