diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b74e6..a59a4aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,364 +5,364 @@ ### Features -* add Dynatrace integration ([#282](https://github.com/kolatts/pncli/issues/282)) ([db99b92](https://github.com/kolatts/pncli/commit/db99b92d434057db5f42fcbbfc2f53b07dc34975)) -* per-skill pncli-origin.json, purge-plugin, and purge-user commands ([#291](https://github.com/kolatts/pncli/issues/291)) ([d26e519](https://github.com/kolatts/pncli/commit/d26e5197be5b337601d718c36e452df34fbfa9bb)), closes [#288](https://github.com/kolatts/pncli/issues/288) -* rework Checkmarx from CxSAST on-premise to Checkmarx One cloud ([#276](https://github.com/kolatts/pncli/issues/276)) ([ff6e924](https://github.com/kolatts/pncli/commit/ff6e924451c35d020a3f9c39ec6856cc7310a0e4)) +* add Dynatrace integration ([#282](https://github.com/kolatts/pncli/issues/282)) ([2c31933](https://github.com/kolatts/pncli/commit/2c3193339f3efbf8e862124735611a18e6dd62a5)) +* per-skill pncli-origin.json, purge-plugin, and purge-user commands ([#291](https://github.com/kolatts/pncli/issues/291)) ([68d9227](https://github.com/kolatts/pncli/commit/68d9227e28418a87cb39159e88fa67bb77005ef8)), closes [#288](https://github.com/kolatts/pncli/issues/288) +* rework Checkmarx from CxSAST on-premise to Checkmarx One cloud ([#276](https://github.com/kolatts/pncli/issues/276)) ([813507d](https://github.com/kolatts/pncli/commit/813507d56bc29bd3dde46555c9f9dc3647b3bf67)) ### Bug Fixes -* create triage PRs as Imagile Bot ([#290](https://github.com/kolatts/pncli/issues/290)) ([dceb73d](https://github.com/kolatts/pncli/commit/dceb73dc22061978ab07f12baf9d3be72dc0167b)), closes [#289](https://github.com/kolatts/pncli/issues/289) -* drop leading /api/ from CheckmarxClient paths (fixes doubled /api/api/ after buildUrl fix) ([#287](https://github.com/kolatts/pncli/issues/287)) ([53ee98c](https://github.com/kolatts/pncli/commit/53ee98cecdd433bd8c150f94608d438363a1de58)) -* handle null projects/scans arrays in checkmarx list commands ([#278](https://github.com/kolatts/pncli/issues/278)) ([cb7a51f](https://github.com/kolatts/pncli/commit/cb7a51fc20dba963f1fddfebbc9fd9adbb839e4f)) -* pass file path as URL segment in bitbucket diff, not query param ([#272](https://github.com/kolatts/pncli/issues/272)) ([0e9bf62](https://github.com/kolatts/pncli/commit/0e9bf626ea3b3e01f83d58e37d31df57fff02743)), closes [#271](https://github.com/kolatts/pncli/issues/271) -* preserve base URL path segments in buildUrl() for Managed Dynatrace and similar hosts ([#284](https://github.com/kolatts/pncli/issues/284)) ([87fef4b](https://github.com/kolatts/pncli/commit/87fef4b09c3fe54903938dae2c505e79ea29fc9e)) -* restore closed-issue email notifications ([#280](https://github.com/kolatts/pncli/issues/280)) ([22c6263](https://github.com/kolatts/pncli/commit/22c626396816ceb8acd4a71549719cfe8979e1b7)), closes [#279](https://github.com/kolatts/pncli/issues/279) +* create triage PRs as Imagile Bot ([#290](https://github.com/kolatts/pncli/issues/290)) ([9f25a67](https://github.com/kolatts/pncli/commit/9f25a67faee8b19837e93b020f45aa93f3f45266)), closes [#289](https://github.com/kolatts/pncli/issues/289) +* drop leading /api/ from CheckmarxClient paths (fixes doubled /api/api/ after buildUrl fix) ([#287](https://github.com/kolatts/pncli/issues/287)) ([ffd0bd8](https://github.com/kolatts/pncli/commit/ffd0bd804348945ba251e9dcd5ffd6f06f22d453)) +* handle null projects/scans arrays in checkmarx list commands ([#278](https://github.com/kolatts/pncli/issues/278)) ([ff4e2c1](https://github.com/kolatts/pncli/commit/ff4e2c1e9e60bc2805dd64a7dd918b13ed765f37)) +* pass file path as URL segment in bitbucket diff, not query param ([#272](https://github.com/kolatts/pncli/issues/272)) ([459128c](https://github.com/kolatts/pncli/commit/459128c97870d9a48bd8f54aea8d3e4bc6152d01)), closes [#271](https://github.com/kolatts/pncli/issues/271) +* preserve base URL path segments in buildUrl() for Managed Dynatrace and similar hosts ([#284](https://github.com/kolatts/pncli/issues/284)) ([9bc9493](https://github.com/kolatts/pncli/commit/9bc9493411cef7756619dc43d889b0d4875c0882)) +* restore closed-issue email notifications ([#280](https://github.com/kolatts/pncli/issues/280)) ([da58b2a](https://github.com/kolatts/pncli/commit/da58b2ae3d07cd4b99c19c04664e7d8204204930)), closes [#279](https://github.com/kolatts/pncli/issues/279) ## [1.18.0](https://github.com/kolatts/pncli/compare/v1.17.0...v1.18.0) (2026-07-24) ### Features -* **confluence:** --body-file, --markdown, and XML error hints ([#257](https://github.com/kolatts/pncli/issues/257)) ([d3977d1](https://github.com/kolatts/pncli/commit/d3977d14a1535765b33c0b49cd635605d59577df)) -* **confluence:** add upload-attachment, delete-attachment, and get-page-history ([#263](https://github.com/kolatts/pncli/issues/263)) ([3d65aab](https://github.com/kolatts/pncli/commit/3d65aabde7935d663e2dce889131dc94843d18f1)), closes [#261](https://github.com/kolatts/pncli/issues/261) -* **github,bitbucket,ado:** add create-repo command to GitHub, Bitbucket, and ADO ([#268](https://github.com/kolatts/pncli/issues/268)) ([58eab4b](https://github.com/kolatts/pncli/commit/58eab4b3c4f6598ab200b171f4d893a6b776e8c5)), closes [#266](https://github.com/kolatts/pncli/issues/266) -* **github:** add create-issue command ([#265](https://github.com/kolatts/pncli/issues/265)) ([d848e4c](https://github.com/kolatts/pncli/commit/d848e4c1b2173178c21ee67ed7cbc1129eec68f5)) -* **jira,ado:** universal --input-file JSON convention with schema discovery ([#260](https://github.com/kolatts/pncli/issues/260)) ([b80fd6c](https://github.com/kolatts/pncli/commit/b80fd6cea6e26b0dca41dfbc8fc37edea090948e)) +* **confluence:** --body-file, --markdown, and XML error hints ([#257](https://github.com/kolatts/pncli/issues/257)) ([df8040f](https://github.com/kolatts/pncli/commit/df8040fb4abe808e4619fcf4d03d4a0688a6f691)) +* **confluence:** add upload-attachment, delete-attachment, and get-page-history ([#263](https://github.com/kolatts/pncli/issues/263)) ([529f4d5](https://github.com/kolatts/pncli/commit/529f4d5bf46d3725e1c0b107e62f239e332e9fa4)), closes [#261](https://github.com/kolatts/pncli/issues/261) +* **github,bitbucket,ado:** add create-repo command to GitHub, Bitbucket, and ADO ([#268](https://github.com/kolatts/pncli/issues/268)) ([950d9ae](https://github.com/kolatts/pncli/commit/950d9ae73105aac5c9c8b5a153388046f44bc3e7)), closes [#266](https://github.com/kolatts/pncli/issues/266) +* **github:** add create-issue command ([#265](https://github.com/kolatts/pncli/issues/265)) ([07b1a3d](https://github.com/kolatts/pncli/commit/07b1a3d3d2f122dde5331408be321aea5db7c22a)) +* **jira,ado:** universal --input-file JSON convention with schema discovery ([#260](https://github.com/kolatts/pncli/issues/260)) ([e74baeb](https://github.com/kolatts/pncli/commit/e74baebeae2832337feda4dd051a0b18e5d0ad2f)) ### Bug Fixes -* **config:** parse JSON array/object values in config set ([#270](https://github.com/kolatts/pncli/issues/270)) ([937ee12](https://github.com/kolatts/pncli/commit/937ee1236d172d1001f204fdfbc8228b935b79db)), closes [#269](https://github.com/kolatts/pncli/issues/269) +* **config:** parse JSON array/object values in config set ([#270](https://github.com/kolatts/pncli/issues/270)) ([2d0e91a](https://github.com/kolatts/pncli/commit/2d0e91ae26151e7d571077520c09f20944c28d64)), closes [#269](https://github.com/kolatts/pncli/issues/269) ## [1.17.0](https://github.com/kolatts/pncli/compare/v1.16.0...v1.17.0) (2026-07-20) ### Features -* **ado:** add work list-areas and list-iterations commands ([#248](https://github.com/kolatts/pncli/issues/248)) ([736052a](https://github.com/kolatts/pncli/commit/736052a5d7a8a10eab36639de11ee50e49698ec8)) -* **jenkins:** project-scoped baseUrl via defaults.jenkins.baseUrl ([#252](https://github.com/kolatts/pncli/issues/252)) ([522f9b8](https://github.com/kolatts/pncli/commit/522f9b8be1181c7c3166e5baf1c9a737e425c4f7)) -* **jira:** list boards/sprints and set sprint on an issue ([#250](https://github.com/kolatts/pncli/issues/250)) ([e62a1ef](https://github.com/kolatts/pncli/commit/e62a1efc65719149c39621a43d42c619b1bbfa6b)) -* **skills:** support multiple marketplaces with seamless sync and CRUD ([#247](https://github.com/kolatts/pncli/issues/247)) ([690de02](https://github.com/kolatts/pncli/commit/690de0278f0dfb7bc9969f00680f9d24854cea09)) +* **ado:** add work list-areas and list-iterations commands ([#248](https://github.com/kolatts/pncli/issues/248)) ([e5a7448](https://github.com/kolatts/pncli/commit/e5a7448f7ecbab9dbf8ee4bc8ed75033cadc7f85)) +* **jenkins:** project-scoped baseUrl via defaults.jenkins.baseUrl ([#252](https://github.com/kolatts/pncli/issues/252)) ([5e00577](https://github.com/kolatts/pncli/commit/5e00577014ebbdfe94877a47d322198e1b1a165f)) +* **jira:** list boards/sprints and set sprint on an issue ([#250](https://github.com/kolatts/pncli/issues/250)) ([2b17de8](https://github.com/kolatts/pncli/commit/2b17de89582e60391939be2cc2ac71805a8fc87f)) +* **skills:** support multiple marketplaces with seamless sync and CRUD ([#247](https://github.com/kolatts/pncli/issues/247)) ([2cab98c](https://github.com/kolatts/pncli/commit/2cab98c9180b357753842173933f74e9e5a4ca97)) ### Bug Fixes -* **jira:** skip non-scrum boards in listSprintsForProject ([#255](https://github.com/kolatts/pncli/issues/255)) ([5a799f5](https://github.com/kolatts/pncli/commit/5a799f5f1528baff2162c1973f80c8db6f4f701c)) -* **skills:** treat marketplace clone as successful when git exits non-zero but .git is valid ([#242](https://github.com/kolatts/pncli/issues/242)) ([417cda8](https://github.com/kolatts/pncli/commit/417cda84d04fe4147873ecc6bd6f6efdeedec2e1)), closes [#239](https://github.com/kolatts/pncli/issues/239) +* **jira:** skip non-scrum boards in listSprintsForProject ([#255](https://github.com/kolatts/pncli/issues/255)) ([c0e4858](https://github.com/kolatts/pncli/commit/c0e4858f909588a73824a4e59c977123efc011c8)) +* **skills:** treat marketplace clone as successful when git exits non-zero but .git is valid ([#242](https://github.com/kolatts/pncli/issues/242)) ([c9e3a06](https://github.com/kolatts/pncli/commit/c9e3a0632095e0e711c969efd9ea360e950bf5b9)), closes [#239](https://github.com/kolatts/pncli/issues/239) ## [1.16.0](https://github.com/kolatts/pncli/compare/v1.15.0...v1.16.0) (2026-06-27) ### Features -* add GitHub integration with PR, review, and comment operations ([#231](https://github.com/kolatts/pncli/issues/231)) ([8410e45](https://github.com/kolatts/pncli/commit/8410e45190819f68082442841c1cc506a044d69d)) -* **ci:** Discord notifications for issues and NPM releases ([#238](https://github.com/kolatts/pncli/issues/238)) ([c933caa](https://github.com/kolatts/pncli/commit/c933caa01fa0ba285fc328d7fda070db8df3f98e)) -* **site:** add Beyond Boring Discord link to footer and feedback page ([#236](https://github.com/kolatts/pncli/issues/236)) ([4a062f0](https://github.com/kolatts/pncli/commit/4a062f08252fc23f878f3f9d42831f7eb57b1786)) +* add GitHub integration with PR, review, and comment operations ([#231](https://github.com/kolatts/pncli/issues/231)) ([d52b627](https://github.com/kolatts/pncli/commit/d52b6275013cbe5adcd91ba019f1ac88d5a91d3c)) +* **ci:** Discord notifications for issues and NPM releases ([#238](https://github.com/kolatts/pncli/issues/238)) ([047d4ec](https://github.com/kolatts/pncli/commit/047d4ec3fa15db709dbf4541f514185921e44d71)) +* **site:** add Beyond Boring Discord link to footer and feedback page ([#236](https://github.com/kolatts/pncli/issues/236)) ([24a1a64](https://github.com/kolatts/pncli/commit/24a1a64b745f1a7ae35604a752e00510e4e061f3)) ### Bug Fixes -* **functions:** send close-reason email when GitHub issues are resolved ([#235](https://github.com/kolatts/pncli/issues/235)) ([d5ba032](https://github.com/kolatts/pncli/commit/d5ba03234aa35081c625ee6be5e7dd8d2778f4bb)), closes [#233](https://github.com/kolatts/pncli/issues/233) -* **skills:** marketplace setup now clones and copies all plugins ([#227](https://github.com/kolatts/pncli/issues/227)) ([a5221e2](https://github.com/kolatts/pncli/commit/a5221e2b307beb929a477f9b0714d74e69e4f9d9)) +* **functions:** send close-reason email when GitHub issues are resolved ([#235](https://github.com/kolatts/pncli/issues/235)) ([e0d1df0](https://github.com/kolatts/pncli/commit/e0d1df09c1221883ec490d029db19a35574cf3cc)), closes [#233](https://github.com/kolatts/pncli/issues/233) +* **skills:** marketplace setup now clones and copies all plugins ([#227](https://github.com/kolatts/pncli/issues/227)) ([83582f7](https://github.com/kolatts/pncli/commit/83582f70c5c5f2e95238817f5571b36bb9c2229b)) ## [1.15.0](https://github.com/kolatts/pncli/compare/v1.14.1...v1.15.0) (2026-06-21) ### Features -* **cli:** add --debug global option for API call traces ([#222](https://github.com/kolatts/pncli/issues/222)) ([9941d4c](https://github.com/kolatts/pncli/commit/9941d4c2a1e4dcd4280dd7734655ff1834a13c8e)), closes [#221](https://github.com/kolatts/pncli/issues/221) -* **skills:** add "All" option to interactive marketplace sync menu ([#225](https://github.com/kolatts/pncli/issues/225)) ([370c992](https://github.com/kolatts/pncli/commit/370c992ec1c4fbfce132cb5aed7f7f598b9bf955)) +* **cli:** add --debug global option for API call traces ([#222](https://github.com/kolatts/pncli/issues/222)) ([2a0375f](https://github.com/kolatts/pncli/commit/2a0375ff16bdcda32107e0ac78d328fd0f05867a)), closes [#221](https://github.com/kolatts/pncli/issues/221) +* **skills:** add "All" option to interactive marketplace sync menu ([#225](https://github.com/kolatts/pncli/issues/225)) ([63c0507](https://github.com/kolatts/pncli/commit/63c0507970ce86a59c22273abd50de62b99c1d3d)) ### Bug Fixes -* **git:** add UTC timezone to normalized git dates to prevent previous-year parse failures ([#215](https://github.com/kolatts/pncli/issues/215)) ([0023fae](https://github.com/kolatts/pncli/commit/0023fae57620f10cb0ce82f21a05c0b6663518c4)), closes [#214](https://github.com/kolatts/pncli/issues/214) -* **git:** increase execFileSync maxBuffer to 200 MB to prevent ENOBUFS on large repos ([#218](https://github.com/kolatts/pncli/issues/218)) ([f07292e](https://github.com/kolatts/pncli/commit/f07292e7b18d18a2ca01629c73ff05c74ea958e5)), closes [#217](https://github.com/kolatts/pncli/issues/217) -* **openshift:** send Accept: */* in openshiftText to avoid HTTP 406 ([#213](https://github.com/kolatts/pncli/issues/213)) ([ffa2a77](https://github.com/kolatts/pncli/commit/ffa2a77ba788be395f95ce4c3d423019601d503a)), closes [#212](https://github.com/kolatts/pncli/issues/212) -* **skills:** always prompt for plugin in sync, keep .agents default, add setup hint ([#223](https://github.com/kolatts/pncli/issues/223)) ([ed23034](https://github.com/kolatts/pncli/commit/ed230341d086797eab107bf4979df8e6eee5779a)) +* **git:** add UTC timezone to normalized git dates to prevent previous-year parse failures ([#215](https://github.com/kolatts/pncli/issues/215)) ([18dc252](https://github.com/kolatts/pncli/commit/18dc2521f7261953013ea5b211cae54a15ddb2bb)), closes [#214](https://github.com/kolatts/pncli/issues/214) +* **git:** increase execFileSync maxBuffer to 200 MB to prevent ENOBUFS on large repos ([#218](https://github.com/kolatts/pncli/issues/218)) ([49b75ee](https://github.com/kolatts/pncli/commit/49b75ee85fc7d826e8d974874b1a1f4e2dea99ca)), closes [#217](https://github.com/kolatts/pncli/issues/217) +* **openshift:** send Accept: */* in openshiftText to avoid HTTP 406 ([#213](https://github.com/kolatts/pncli/issues/213)) ([2e45442](https://github.com/kolatts/pncli/commit/2e4544268c193e93d8fa5dc91e4f1e23b36b5687)), closes [#212](https://github.com/kolatts/pncli/issues/212) +* **skills:** always prompt for plugin in sync, keep .agents default, add setup hint ([#223](https://github.com/kolatts/pncli/issues/223)) ([b7077a7](https://github.com/kolatts/pncli/commit/b7077a7a4615eb67513e4193a667676e4de1841e)) ## [1.14.1](https://github.com/kolatts/pncli/compare/v1.14.0...v1.14.1) (2026-06-14) ### Bug Fixes -* **ado:** always send application/octet-stream for work item attachments ([#210](https://github.com/kolatts/pncli/issues/210)) ([51d668c](https://github.com/kolatts/pncli/commit/51d668c581101da3fde4d691c813dcbdb4efb6c1)), closes [#209](https://github.com/kolatts/pncli/issues/209) +* **ado:** always send application/octet-stream for work item attachments ([#210](https://github.com/kolatts/pncli/issues/210)) ([d532e45](https://github.com/kolatts/pncli/commit/d532e457bdbffb931870f786e14a18be83c3d417)), closes [#209](https://github.com/kolatts/pncli/issues/209) ## [1.14.0](https://github.com/kolatts/pncli/compare/v1.13.0...v1.14.0) (2026-06-13) ### Features -* **ado:** add work item attachment upload ([#205](https://github.com/kolatts/pncli/issues/205)) ([701acf9](https://github.com/kolatts/pncli/commit/701acf9a5e99c53d3e7e5cfaca0eb9f880df32a6)) -* **jwt:** add jwt decode command ([#203](https://github.com/kolatts/pncli/issues/203)) ([8f0bc50](https://github.com/kolatts/pncli/commit/8f0bc50f81b048c3f120a632478845f84491c350)) -* **openshift:** OpenShift/Kubernetes service integration and health-checker skill ([#207](https://github.com/kolatts/pncli/issues/207)) ([64303f3](https://github.com/kolatts/pncli/commit/64303f32a6497fa9261bebfe996a36e96214640d)) +* **ado:** add work item attachment upload ([#205](https://github.com/kolatts/pncli/issues/205)) ([c1df406](https://github.com/kolatts/pncli/commit/c1df406d7ff65f4fb6e3d5e34af997253fc9f7ae)) +* **jwt:** add jwt decode command ([#203](https://github.com/kolatts/pncli/issues/203)) ([336637a](https://github.com/kolatts/pncli/commit/336637afaeb2c3f9c940f3f6fe471bab4a226be3)) +* **openshift:** OpenShift/Kubernetes service integration and health-checker skill ([#207](https://github.com/kolatts/pncli/issues/207)) ([a6addd2](https://github.com/kolatts/pncli/commit/a6addd263782ae14c1eed62edf81a473bde6daf1)) ## [1.13.0](https://github.com/kolatts/pncli/compare/v1.12.0...v1.13.0) (2026-05-30) ### Features -* **ado,jira:** add attachment list and download commands ([#199](https://github.com/kolatts/pncli/issues/199)) ([85c6055](https://github.com/kolatts/pncli/commit/85c605503e250b18ee0bd73a366bd99a409b6695)) -* **jira,ado:** add label and tag management commands ([#196](https://github.com/kolatts/pncli/issues/196)) ([6884ed5](https://github.com/kolatts/pncli/commit/6884ed514634d868b5d8603a2d93d6cf965456e3)) -* **jira:** add add-attachment command ([#192](https://github.com/kolatts/pncli/issues/192)) ([ca10258](https://github.com/kolatts/pncli/commit/ca10258b14d435af37f01be7c1be271d126846a7)) -* **skills:** print per-skill copy paths during marketplace sync ([#194](https://github.com/kolatts/pncli/issues/194)) ([256f94c](https://github.com/kolatts/pncli/commit/256f94c1e132a2b50ac0bddd99fb186eb9d0de24)), closes [#193](https://github.com/kolatts/pncli/issues/193) +* **ado,jira:** add attachment list and download commands ([#199](https://github.com/kolatts/pncli/issues/199)) ([03b810e](https://github.com/kolatts/pncli/commit/03b810efde4c212de4238b990e226a6604ef890e)) +* **jira,ado:** add label and tag management commands ([#196](https://github.com/kolatts/pncli/issues/196)) ([2634d60](https://github.com/kolatts/pncli/commit/2634d6039053b9ea0a072632be921f5b670d4c46)) +* **jira:** add add-attachment command ([#192](https://github.com/kolatts/pncli/issues/192)) ([82b664a](https://github.com/kolatts/pncli/commit/82b664a9784a6423c8177665efb02f525487c6c7)) +* **skills:** print per-skill copy paths during marketplace sync ([#194](https://github.com/kolatts/pncli/issues/194)) ([bd2fbc1](https://github.com/kolatts/pncli/commit/bd2fbc1ed1c1c18e14e04b41a16523151e10e6ef)), closes [#193](https://github.com/kolatts/pncli/issues/193) ### Bug Fixes -* **confluence:** make --limit cap total results in list-spaces and list-pages ([#190](https://github.com/kolatts/pncli/issues/190)) ([8524679](https://github.com/kolatts/pncli/commit/8524679cbbb524745ad4742fb17ed4a7e865a42b)), closes [#189](https://github.com/kolatts/pncli/issues/189) -* **git:** filter report commits by author date and route CSV through --output-file ([#188](https://github.com/kolatts/pncli/issues/188)) ([817ce47](https://github.com/kolatts/pncli/commit/817ce47112c03fdc2c464f32255628a3423ad5b9)), closes [#187](https://github.com/kolatts/pncli/issues/187) +* **confluence:** make --limit cap total results in list-spaces and list-pages ([#190](https://github.com/kolatts/pncli/issues/190)) ([76c7dde](https://github.com/kolatts/pncli/commit/76c7dded998b1cc477af0442276faae64d395f1d)), closes [#189](https://github.com/kolatts/pncli/issues/189) +* **git:** filter report commits by author date and route CSV through --output-file ([#188](https://github.com/kolatts/pncli/issues/188)) ([1616024](https://github.com/kolatts/pncli/commit/16160245aad5efed99d1014347f5194a7d655259)), closes [#187](https://github.com/kolatts/pncli/issues/187) ## [1.12.0](https://github.com/kolatts/pncli/compare/v1.11.1...v1.12.0) (2026-05-23) ### Features -* **jenkins:** add --folder flag to pipeline list for folder-scoped job enumeration ([#171](https://github.com/kolatts/pncli/issues/171)) ([0107ae6](https://github.com/kolatts/pncli/commit/0107ae698e858092dc955b92e655c318a917d5bc)) -* **jira:** support [@file](https://github.com/file) syntax and --fields-file for large custom field payloads ([#180](https://github.com/kolatts/pncli/issues/180)) ([a2512ca](https://github.com/kolatts/pncli/commit/a2512ca96d4644f3448c61cd445faf0ae5d33ced)), closes [#179](https://github.com/kolatts/pncli/issues/179) -* **skills:** add --force flag and all-plugins sync to marketplace sync ([#184](https://github.com/kolatts/pncli/issues/184)) ([2087f7a](https://github.com/kolatts/pncli/commit/2087f7aecce2cbc28f7d75c3c803ba2cd491f6cc)), closes [#183](https://github.com/kolatts/pncli/issues/183) -* **skills:** skip marketplace sync prompt when no git changes ([#165](https://github.com/kolatts/pncli/issues/165)) ([e895df6](https://github.com/kolatts/pncli/commit/e895df650494674af8b5188dc82eb54f44a0b516)) +* **jenkins:** add --folder flag to pipeline list for folder-scoped job enumeration ([#171](https://github.com/kolatts/pncli/issues/171)) ([8354c5a](https://github.com/kolatts/pncli/commit/8354c5a96304f4523e2cc00f7cce601806d5dbdb)) +* **jira:** support [@file](https://github.com/file) syntax and --fields-file for large custom field payloads ([#180](https://github.com/kolatts/pncli/issues/180)) ([a9d8df5](https://github.com/kolatts/pncli/commit/a9d8df5860cbc49e4382c8705eadb6103ff071cc)), closes [#179](https://github.com/kolatts/pncli/issues/179) +* **skills:** add --force flag and all-plugins sync to marketplace sync ([#184](https://github.com/kolatts/pncli/issues/184)) ([d81b2d8](https://github.com/kolatts/pncli/commit/d81b2d832534061a0da2e37a7967ba09e0859e17)), closes [#183](https://github.com/kolatts/pncli/issues/183) +* **skills:** skip marketplace sync prompt when no git changes ([#165](https://github.com/kolatts/pncli/issues/165)) ([c0793af](https://github.com/kolatts/pncli/commit/c0793afd378ae4d5c57b3dab9dacce464aa7eec2)) ### Bug Fixes -* **ado:** decode URL components in parseAdoRemote to prevent double-encoding ([#167](https://github.com/kolatts/pncli/issues/167)) ([0556b1c](https://github.com/kolatts/pncli/commit/0556b1c963e3529c4fce588021fd766d7928d764)), closes [#166](https://github.com/kolatts/pncli/issues/166) -* **ado:** honour caller Content-Type in ADO fetcher ([#158](https://github.com/kolatts/pncli/issues/158)) ([ee4a1d4](https://github.com/kolatts/pncli/commit/ee4a1d45a9b8d0b410703aedb0c965d26593dc67)), closes [#157](https://github.com/kolatts/pncli/issues/157) -* **ado:** pipeline list-runs --definition filter and add --name support ([#173](https://github.com/kolatts/pncli/issues/173)) ([eb45153](https://github.com/kolatts/pncli/commit/eb45153d4672b17b6c340f6cd69b19f31079723d)) -* **artifactory,ado:** builds timeout, list-runs top limit, pipeline logs --build-id alias ([#182](https://github.com/kolatts/pncli/issues/182)) ([acf8c97](https://github.com/kolatts/pncli/commit/acf8c978ceb30d777dd099cc80bf9dc493c307c5)) -* **artifactory:** parse build names from URIs and hint on empty builds list ([#172](https://github.com/kolatts/pncli/issues/172)) ([cca720a](https://github.com/kolatts/pncli/commit/cca720a9cdb3368f891720dd38291f3606d3d106)), closes [#170](https://github.com/kolatts/pncli/issues/170) -* **bitbucket:** add --project/--repo flags to create-pr subcommand ([#175](https://github.com/kolatts/pncli/issues/175)) ([8cbda27](https://github.com/kolatts/pncli/commit/8cbda277788580e64d25fb00e9463ac873b1faf4)), closes [#174](https://github.com/kolatts/pncli/issues/174) -* **git:** normalize date-only --since/--until to include time component ([#163](https://github.com/kolatts/pncli/issues/163)) ([cdf8b98](https://github.com/kolatts/pncli/commit/cdf8b98982ce80599967fe4b9218d24ba82d932e)), closes [#162](https://github.com/kolatts/pncli/issues/162) -* issue [#185](https://github.com/kolatts/pncli/issues/185) (automated) ([#186](https://github.com/kolatts/pncli/issues/186)) ([f953eb5](https://github.com/kolatts/pncli/commit/f953eb5e262cad1f13b4716d5cebebc013f377d9)) -* **jira:** fix parent field, raw field IDs, error messages, and allowedValues (BUG-13–16) ([#160](https://github.com/kolatts/pncli/issues/160)) ([92154b3](https://github.com/kolatts/pncli/commit/92154b39ff0e6779bfa2b6434b9b9b86b24acddb)) -* **jira:** support cascading-select fields in create-issue and fields discovery ([#177](https://github.com/kolatts/pncli/issues/177)) ([04f34d2](https://github.com/kolatts/pncli/commit/04f34d2744d054dde5fd28e9471b6c25e4ed8b4d)), closes [#176](https://github.com/kolatts/pncli/issues/176) -* **workflows:** allow all bots in claude review workflow ([#178](https://github.com/kolatts/pncli/issues/178)) ([9c961db](https://github.com/kolatts/pncli/commit/9c961dbd7080494f24c2b0163a939c378d0b9376)) +* **ado:** decode URL components in parseAdoRemote to prevent double-encoding ([#167](https://github.com/kolatts/pncli/issues/167)) ([29c6d3e](https://github.com/kolatts/pncli/commit/29c6d3e03feee6daa6329d83962844ab159ac652)), closes [#166](https://github.com/kolatts/pncli/issues/166) +* **ado:** honour caller Content-Type in ADO fetcher ([#158](https://github.com/kolatts/pncli/issues/158)) ([b10613e](https://github.com/kolatts/pncli/commit/b10613eed6971bce5b4164ddf47d1a0b9a790d9e)), closes [#157](https://github.com/kolatts/pncli/issues/157) +* **ado:** pipeline list-runs --definition filter and add --name support ([#173](https://github.com/kolatts/pncli/issues/173)) ([720a60b](https://github.com/kolatts/pncli/commit/720a60b1fc32cad104a13242e087e938e3be2236)) +* **artifactory,ado:** builds timeout, list-runs top limit, pipeline logs --build-id alias ([#182](https://github.com/kolatts/pncli/issues/182)) ([d71837b](https://github.com/kolatts/pncli/commit/d71837bbabd1cceb4e75f97bd177714081792f39)) +* **artifactory:** parse build names from URIs and hint on empty builds list ([#172](https://github.com/kolatts/pncli/issues/172)) ([f497708](https://github.com/kolatts/pncli/commit/f497708a94bdb0de84b74e9e773b68e3760b8154)), closes [#170](https://github.com/kolatts/pncli/issues/170) +* **bitbucket:** add --project/--repo flags to create-pr subcommand ([#175](https://github.com/kolatts/pncli/issues/175)) ([d03ab4d](https://github.com/kolatts/pncli/commit/d03ab4d80a99fd246c09c5d12f51f0643f0c3e90)), closes [#174](https://github.com/kolatts/pncli/issues/174) +* **git:** normalize date-only --since/--until to include time component ([#163](https://github.com/kolatts/pncli/issues/163)) ([b6b7099](https://github.com/kolatts/pncli/commit/b6b70999816720986220164c6d05bd7712af5a1d)), closes [#162](https://github.com/kolatts/pncli/issues/162) +* issue [#185](https://github.com/kolatts/pncli/issues/185) (automated) ([#186](https://github.com/kolatts/pncli/issues/186)) ([bb227c2](https://github.com/kolatts/pncli/commit/bb227c2a7fdefd7480979f161f909b3e799ce044)) +* **jira:** fix parent field, raw field IDs, error messages, and allowedValues (BUG-13–16) ([#160](https://github.com/kolatts/pncli/issues/160)) ([2798761](https://github.com/kolatts/pncli/commit/2798761b6bad7fa81ab39d45250b055658dc7b07)) +* **jira:** support cascading-select fields in create-issue and fields discovery ([#177](https://github.com/kolatts/pncli/issues/177)) ([e33dbe6](https://github.com/kolatts/pncli/commit/e33dbe67844699dc35bf058e395456fa13795a12)), closes [#176](https://github.com/kolatts/pncli/issues/176) +* **workflows:** allow all bots in claude review workflow ([#178](https://github.com/kolatts/pncli/issues/178)) ([2bdde88](https://github.com/kolatts/pncli/commit/2bdde88d6054482a3d7b19a4df5602223f57cfcc)) ## [1.11.1](https://github.com/kolatts/pncli/compare/v1.11.0...v1.11.1) (2026-05-16) ### Bug Fixes -* **deps:** replace @inquirer/prompts with individual packages ([#155](https://github.com/kolatts/pncli/issues/155)) ([c21ea66](https://github.com/kolatts/pncli/commit/c21ea66ec3694049c24b1b1af7fdd1229683a01d)), closes [#154](https://github.com/kolatts/pncli/issues/154) +* **deps:** replace @inquirer/prompts with individual packages ([#155](https://github.com/kolatts/pncli/issues/155)) ([fe35cf6](https://github.com/kolatts/pncli/commit/fe35cf66d3a753f28d5e057d73015db4cf3ed26c)), closes [#154](https://github.com/kolatts/pncli/issues/154) ## [1.11.0](https://github.com/kolatts/pncli/compare/v1.10.1...v1.11.0) (2026-05-15) ### Features -* **git:** add report command with date filtering and CSV export ([#148](https://github.com/kolatts/pncli/issues/148)) ([b1f40e1](https://github.com/kolatts/pncli/commit/b1f40e17a2f4e373716c45734fccb747335304f8)) -* **skills:** add --token option to marketplace setup for Bitbucket HTTP access tokens ([#151](https://github.com/kolatts/pncli/issues/151)) ([666e514](https://github.com/kolatts/pncli/commit/666e51472d4f66c9673733740e7bc62f263148bd)) -* **skills:** add marketplace setup and sync commands ([#144](https://github.com/kolatts/pncli/issues/144)) ([29951a2](https://github.com/kolatts/pncli/commit/29951a21a6346aa59983ce1e4778da1c7b3347d2)) -* **skills:** revamp to single distributable pncli skill + example-skills split ([#146](https://github.com/kolatts/pncli/issues/146)) ([122b137](https://github.com/kolatts/pncli/commit/122b1373c5347b0ac5a63ffcb8971bccfe259410)) +* **git:** add report command with date filtering and CSV export ([#148](https://github.com/kolatts/pncli/issues/148)) ([073ab42](https://github.com/kolatts/pncli/commit/073ab42af60cc657c1cb5b85f996bdb4e21dc3c3)) +* **skills:** add --token option to marketplace setup for Bitbucket HTTP access tokens ([#151](https://github.com/kolatts/pncli/issues/151)) ([1d6d8f7](https://github.com/kolatts/pncli/commit/1d6d8f7218895d583dda17d220e1fe0c71e0ebbe)) +* **skills:** add marketplace setup and sync commands ([#144](https://github.com/kolatts/pncli/issues/144)) ([8b7126e](https://github.com/kolatts/pncli/commit/8b7126e67ec941e22f6084d0259f2f14514cc759)) +* **skills:** revamp to single distributable pncli skill + example-skills split ([#146](https://github.com/kolatts/pncli/issues/146)) ([40285d6](https://github.com/kolatts/pncli/commit/40285d60ac69ccc1d06e2b42edb024c65f9f3a4f)) ### Bug Fixes -* **ci:** strengthen claude-triage PR gate ([#153](https://github.com/kolatts/pncli/issues/153)) ([2c04388](https://github.com/kolatts/pncli/commit/2c04388c36e47fadd5159079ff50017b3697fa39)) +* **ci:** strengthen claude-triage PR gate ([#153](https://github.com/kolatts/pncli/issues/153)) ([f89c561](https://github.com/kolatts/pncli/commit/f89c561b28375c440b9cd8c34ea7a9b3ec412e65)) ## [1.10.1](https://github.com/kolatts/pncli/compare/v1.10.0...v1.10.1) (2026-05-14) ### Bug Fixes -* improve supply chain security for socket.dev ([#141](https://github.com/kolatts/pncli/issues/141)) ([426818d](https://github.com/kolatts/pncli/commit/426818dbd55f528924c98da9fbeb4dc70aa30808)) +* improve supply chain security for socket.dev ([#141](https://github.com/kolatts/pncli/issues/141)) ([d9e13a5](https://github.com/kolatts/pncli/commit/d9e13a5d1d792530644baff1f6e2534099006098)) ## [1.10.0](https://github.com/kolatts/pncli/compare/v1.9.0...v1.10.0) (2026-05-14) ### Features -* enable mcp__github__pull_request_review_write for Claude review approvals ([#138](https://github.com/kolatts/pncli/issues/138)) ([3f07dc2](https://github.com/kolatts/pncli/commit/3f07dc25288e9530bdc473ba3902170d0b5ad579)) -* **sonatypeiq:** add Sonatype IQ Server integration with PAT auth ([#130](https://github.com/kolatts/pncli/issues/130)) ([76d0c73](https://github.com/kolatts/pncli/commit/76d0c738de1d3b8f15bd509d0af47f4d078fc30e)) +* enable mcp__github__pull_request_review_write for Claude review approvals ([#138](https://github.com/kolatts/pncli/issues/138)) ([30ac8d9](https://github.com/kolatts/pncli/commit/30ac8d9c0ec34c81df61cff7219f0e106f25a192)) +* **sonatypeiq:** add Sonatype IQ Server integration with PAT auth ([#130](https://github.com/kolatts/pncli/issues/130)) ([ce20edd](https://github.com/kolatts/pncli/commit/ce20edd4709325f2dfa8ed5fc606f86adb64bf41)) ### Bug Fixes -* **deps:** resolve Sonatype IQ public ID to internal UUID before evaluation ([#135](https://github.com/kolatts/pncli/issues/135)) ([41674bc](https://github.com/kolatts/pncli/commit/41674bc91e787b7f1a80c436c27f8be7e285383c)), closes [#133](https://github.com/kolatts/pncli/issues/133) -* improve supply chain security for socket.dev ([#140](https://github.com/kolatts/pncli/issues/140)) ([f0b6e3f](https://github.com/kolatts/pncli/commit/f0b6e3f308402202928cb4de34b0bdf754658809)) -* **skills:** bundle skills with npm package and copy from dist on install ([#137](https://github.com/kolatts/pncli/issues/137)) ([4cf8c0c](https://github.com/kolatts/pncli/commit/4cf8c0cc9e4b4ca370d90b57f2c1b88f8eac2eb0)) +* **deps:** resolve Sonatype IQ public ID to internal UUID before evaluation ([#135](https://github.com/kolatts/pncli/issues/135)) ([ec05dc6](https://github.com/kolatts/pncli/commit/ec05dc6ef4d9d3962d855c307ce8de3a5b00c539)), closes [#133](https://github.com/kolatts/pncli/issues/133) +* improve supply chain security for socket.dev ([#140](https://github.com/kolatts/pncli/issues/140)) ([122288b](https://github.com/kolatts/pncli/commit/122288bbccd67899cc6e44fde259400de61242aa)) +* **skills:** bundle skills with npm package and copy from dist on install ([#137](https://github.com/kolatts/pncli/issues/137)) ([f459e7a](https://github.com/kolatts/pncli/commit/f459e7ac77e88d7917e2cd4523e4860beea562b7)) ## [1.9.0](https://github.com/kolatts/pncli/compare/v1.8.0...v1.9.0) (2026-05-11) ### Features -* **deps:** add Sonatype OSS Index as vulnerability source for deps frisk ([#62](https://github.com/kolatts/pncli/issues/62)) ([4b8651e](https://github.com/kolatts/pncli/commit/4b8651e9cc907d6e653afa6758f05af3e618f216)) -* **jira,ado:** add --parent flag to create-issue and work create ([#125](https://github.com/kolatts/pncli/issues/125)) ([c4bdb60](https://github.com/kolatts/pncli/commit/c4bdb60b8152f9b52f7d7f8fa107ecf4dc33b17e)), closes [#31](https://github.com/kolatts/pncli/issues/31) -* **servicenow,contrast:** add ServiceNow change management and Contrast IAST integrations ([#128](https://github.com/kolatts/pncli/issues/128)) ([47a706f](https://github.com/kolatts/pncli/commit/47a706f40a49e869cbdef901de00f058ffec5847)) -* **site:** add auto-generated commands reference page ([#126](https://github.com/kolatts/pncli/issues/126)) ([f01e67a](https://github.com/kolatts/pncli/commit/f01e67a7fce91dacf63cc6902d491b11d8c6ee81)), closes [#99](https://github.com/kolatts/pncli/issues/99) -* **site:** add integration testing-maturity badges and reframe homepage ([#124](https://github.com/kolatts/pncli/issues/124)) ([74185cf](https://github.com/kolatts/pncli/commit/74185cfdf8d566ab3cab00e16f9bab9899362dcf)) +* **deps:** add Sonatype OSS Index as vulnerability source for deps frisk ([#62](https://github.com/kolatts/pncli/issues/62)) ([5825098](https://github.com/kolatts/pncli/commit/58250987ba603f3ef8cc4801b9d5ee0d11172240)) +* **jira,ado:** add --parent flag to create-issue and work create ([#125](https://github.com/kolatts/pncli/issues/125)) ([9539ad4](https://github.com/kolatts/pncli/commit/9539ad40cd067fdcfbab810bc7cc53f36e92cec9)), closes [#31](https://github.com/kolatts/pncli/issues/31) +* **servicenow,contrast:** add ServiceNow change management and Contrast IAST integrations ([#128](https://github.com/kolatts/pncli/issues/128)) ([18371e9](https://github.com/kolatts/pncli/commit/18371e9b939f5ba111242b83b5efc4a9cbeaaa30)) +* **site:** add auto-generated commands reference page ([#126](https://github.com/kolatts/pncli/issues/126)) ([3502e97](https://github.com/kolatts/pncli/commit/3502e976be84279682c3a3ac600cf99a16e3fc0d)), closes [#99](https://github.com/kolatts/pncli/issues/99) +* **site:** add integration testing-maturity badges and reframe homepage ([#124](https://github.com/kolatts/pncli/issues/124)) ([74fd5f1](https://github.com/kolatts/pncli/commit/74fd5f16c56fc7e6a0010bf5ed26ed9c6835c311)) ## [1.8.0](https://github.com/kolatts/pncli/compare/v1.7.0...v1.8.0) (2026-04-24) ### Features -* add --path filter to ado repo diff ([dbbee5b](https://github.com/kolatts/pncli/commit/dbbee5b980514436512c76e2a7a48f11ccc2902b)) -* add --path filter to ado repo diff command ([10a7a0c](https://github.com/kolatts/pncli/commit/10a7a0c1e514aafe67a59caa39a5e62eb25f56d6)), closes [#70](https://github.com/kolatts/pncli/issues/70) -* **artifactory:** add Artifactory API support ([#83](https://github.com/kolatts/pncli/issues/83)) ([077a861](https://github.com/kolatts/pncli/commit/077a8614e7e1606746e2beb5458e36a3f611160b)) -* **checkmarx:** add CxSAST 9.x integration with OAuth2 token exchange ([#118](https://github.com/kolatts/pncli/issues/118)) ([65e6f29](https://github.com/kolatts/pncli/commit/65e6f29f0535294b32fd703eaa93142ea572f16a)) -* **cli:** add --output-file global option for large command output ([#101](https://github.com/kolatts/pncli/issues/101)) ([092cbf8](https://github.com/kolatts/pncli/commit/092cbf835be7c422f13d99ad5905580eebb7bde7)) -* **docs:** Dark mode ([#74](https://github.com/kolatts/pncli/issues/74)) ([066d53b](https://github.com/kolatts/pncli/commit/066d53bcf67640a064e4eb5c12d6409f5b0c5822)) -* **jenkins:** add Jenkins Data Center pipeline integration ([#85](https://github.com/kolatts/pncli/issues/85)) ([dd0c90a](https://github.com/kolatts/pncli/commit/dd0c90aefdcc395d745dfc739540839eed7bf752)) -* **site:** reorganize NOTICE file and add hidden easter egg page ([#82](https://github.com/kolatts/pncli/issues/82)) ([86f4f77](https://github.com/kolatts/pncli/commit/86f4f77b92ca063b1a6586bf22283c21c3f6d394)) -* **site:** replace dark mode logo invert with dedicated dark variant ([#95](https://github.com/kolatts/pncli/issues/95)) ([9f05229](https://github.com/kolatts/pncli/commit/9f05229fd6d97fce0b46a0d06b043c81908067bd)) -* **skills:** add ship skill, vitest tests, and pre-commit gate cleanup ([#76](https://github.com/kolatts/pncli/issues/76)) ([23c0c3d](https://github.com/kolatts/pncli/commit/23c0c3db8267f6d136220014ae01cba27ac99f69)) -* **skills:** redux — isolate consumer skills, align to agentskills spec, add --agent/--scope to install ([#107](https://github.com/kolatts/pncli/issues/107)) ([edc57d0](https://github.com/kolatts/pncli/commit/edc57d09550d29e16c3e511f587d290431b45ae6)) -* **udeploy:** IBM UrbanCode Deploy integration with PAT auth ([#86](https://github.com/kolatts/pncli/issues/86)) ([160f2b3](https://github.com/kolatts/pncli/commit/160f2b31818d74a8d031650950e7d46ea3863cc4)) -* **udeploy:** re-add username/password auth and fix PAT token encoding ([#105](https://github.com/kolatts/pncli/issues/105)) ([b77bc1d](https://github.com/kolatts/pncli/commit/b77bc1d9c9ef3b1814982555558c7fc7ad63f382)) -* **udeploy:** support username/password basic auth in addition to auth tokens ([#98](https://github.com/kolatts/pncli/issues/98)) ([2570680](https://github.com/kolatts/pncli/commit/2570680f57067346e78205125715030c4e9e0408)), closes [#97](https://github.com/kolatts/pncli/issues/97) +* add --path filter to ado repo diff ([cdb29c3](https://github.com/kolatts/pncli/commit/cdb29c332e58f65ae962923fab24c153e51a605e)) +* add --path filter to ado repo diff command ([c1d529a](https://github.com/kolatts/pncli/commit/c1d529ae1e5314a32e4d6969400e72941fde5fc5)), closes [#70](https://github.com/kolatts/pncli/issues/70) +* **artifactory:** add Artifactory API support ([#83](https://github.com/kolatts/pncli/issues/83)) ([3797b75](https://github.com/kolatts/pncli/commit/3797b7537734f80ddd5d8a6a55a9c3b054ccd920)) +* **checkmarx:** add CxSAST 9.x integration with OAuth2 token exchange ([#118](https://github.com/kolatts/pncli/issues/118)) ([ecd5489](https://github.com/kolatts/pncli/commit/ecd5489a864bc57b2fe5d31a928d50e2c294d414)) +* **cli:** add --output-file global option for large command output ([#101](https://github.com/kolatts/pncli/issues/101)) ([f18c6bb](https://github.com/kolatts/pncli/commit/f18c6bbf0a89bde392d89d7c51ea729bf6afda05)) +* **docs:** Dark mode ([#74](https://github.com/kolatts/pncli/issues/74)) ([cd90955](https://github.com/kolatts/pncli/commit/cd909559d4c6402cb646e26647c0b3cda5f31b9d)) +* **jenkins:** add Jenkins Data Center pipeline integration ([#85](https://github.com/kolatts/pncli/issues/85)) ([3c7ad5c](https://github.com/kolatts/pncli/commit/3c7ad5c9de7289e273724d5d2e45245af0cbad93)) +* **site:** reorganize NOTICE file and add hidden easter egg page ([#82](https://github.com/kolatts/pncli/issues/82)) ([abdfed2](https://github.com/kolatts/pncli/commit/abdfed22a04aea9c3a16102386c0682eefc12645)) +* **site:** replace dark mode logo invert with dedicated dark variant ([#95](https://github.com/kolatts/pncli/issues/95)) ([112419c](https://github.com/kolatts/pncli/commit/112419ca3410021c9555fcb64835ad60601c1a61)) +* **skills:** add ship skill, vitest tests, and pre-commit gate cleanup ([#76](https://github.com/kolatts/pncli/issues/76)) ([f41d674](https://github.com/kolatts/pncli/commit/f41d6740bf995a5607ff4b0dfe07ad2ba9ae1b48)) +* **skills:** redux — isolate consumer skills, align to agentskills spec, add --agent/--scope to install ([#107](https://github.com/kolatts/pncli/issues/107)) ([c658520](https://github.com/kolatts/pncli/commit/c658520753b032ba3567fdedc166f47c68359115)) +* **udeploy:** IBM UrbanCode Deploy integration with PAT auth ([#86](https://github.com/kolatts/pncli/issues/86)) ([fcef1e0](https://github.com/kolatts/pncli/commit/fcef1e07b1bf7322a7f85ae21ef579dd71028a4b)) +* **udeploy:** re-add username/password auth and fix PAT token encoding ([#105](https://github.com/kolatts/pncli/issues/105)) ([922b09f](https://github.com/kolatts/pncli/commit/922b09f538a517a5c2a6530abe0392a20277641e)) +* **udeploy:** support username/password basic auth in addition to auth tokens ([#98](https://github.com/kolatts/pncli/issues/98)) ([94b45f5](https://github.com/kolatts/pncli/commit/94b45f53d9f4f395f9a20c2c92ff9c4622eb1192)), closes [#97](https://github.com/kolatts/pncli/issues/97) ### Bug Fixes -* add .mailmap to normalize contributor email identity ([3e581b5](https://github.com/kolatts/pncli/commit/3e581b5adca4ec97a6267ba90f8ff243e9c0d91e)) -* **ado:** use 7.1-preview.1 for connectionData endpoint ([f0e94ae](https://github.com/kolatts/pncli/commit/f0e94ae45b7b0f48a4e0ca06aad7240cbdd2c0c1)) -* **ado:** use 7.1-preview.1 for connectionData endpoint ([b21983d](https://github.com/kolatts/pncli/commit/b21983db7527224a5c6829719f2c3ac4a89ae5f4)), closes [#69](https://github.com/kolatts/pncli/issues/69) -* **artifactory:** drop leading slash from API prefix to preserve base URL path ([#94](https://github.com/kolatts/pncli/issues/94)) ([26ab1ef](https://github.com/kolatts/pncli/commit/26ab1ef846fb8724a3ed8117248309012d795d64)), closes [#90](https://github.com/kolatts/pncli/issues/90) -* **bitbucket:** pass bb subcommand to getClient so --project/--repo are resolved ([#92](https://github.com/kolatts/pncli/issues/92)) ([4e2e0d9](https://github.com/kolatts/pncli/commit/4e2e0d9a3ff4a4c379e6ec7268bad6ee5d60f35a)), closes [#89](https://github.com/kolatts/pncli/issues/89) -* **jenkins:** handle multi-level folder paths in pipeline commands ([#96](https://github.com/kolatts/pncli/issues/96)) ([961766e](https://github.com/kolatts/pncli/commit/961766ea72237ea865b0afda0964718628f7bd87)), closes [#91](https://github.com/kolatts/pncli/issues/91) -* **site:** reset Turnstile widget on failed submission ([#88](https://github.com/kolatts/pncli/issues/88)) ([bde51cb](https://github.com/kolatts/pncli/commit/bde51cb2484f265f0d15c97525668183462804f9)) -* **udeploy:** remove username/password auth, PAT-only ([#103](https://github.com/kolatts/pncli/issues/103)) ([24f0248](https://github.com/kolatts/pncli/commit/24f0248a7f147a7002beaa6c9df38e9880c60395)) -* **udeploy:** rename --version options to avoid root-level Commander.js collision ([#112](https://github.com/kolatts/pncli/issues/112)) ([96084c9](https://github.com/kolatts/pncli/commit/96084c97ddc1bda68c7f1c3b24811d17ca24f1d5)) -* **udeploy:** support username+pat as Basic auth credential pair ([#110](https://github.com/kolatts/pncli/issues/110)) ([3143caa](https://github.com/kolatts/pncli/commit/3143caae45636b2ecdba02baf9c93bdc157a3bc1)), closes [#109](https://github.com/kolatts/pncli/issues/109) +* add .mailmap to normalize contributor email identity ([e4d8cce](https://github.com/kolatts/pncli/commit/e4d8cceeb015dea3a949f6d6e9ec2ff0a70364a4)) +* **ado:** use 7.1-preview.1 for connectionData endpoint ([3ee99c1](https://github.com/kolatts/pncli/commit/3ee99c1339fcaf24e0a30072b4c9f2b154b45305)) +* **ado:** use 7.1-preview.1 for connectionData endpoint ([4122850](https://github.com/kolatts/pncli/commit/4122850b5b4b9e08d09c2e4a3be43ba5f478a061)), closes [#69](https://github.com/kolatts/pncli/issues/69) +* **artifactory:** drop leading slash from API prefix to preserve base URL path ([#94](https://github.com/kolatts/pncli/issues/94)) ([6d64f7f](https://github.com/kolatts/pncli/commit/6d64f7f521c5e93c7c468007c788ec79ff5a5752)), closes [#90](https://github.com/kolatts/pncli/issues/90) +* **bitbucket:** pass bb subcommand to getClient so --project/--repo are resolved ([#92](https://github.com/kolatts/pncli/issues/92)) ([3005dcd](https://github.com/kolatts/pncli/commit/3005dcd79e82ff6c09cc26f42e25ca20d7781d50)), closes [#89](https://github.com/kolatts/pncli/issues/89) +* **jenkins:** handle multi-level folder paths in pipeline commands ([#96](https://github.com/kolatts/pncli/issues/96)) ([1c47b44](https://github.com/kolatts/pncli/commit/1c47b44fb15e2f832d028fc82d9f8e06a5c8afa6)), closes [#91](https://github.com/kolatts/pncli/issues/91) +* **site:** reset Turnstile widget on failed submission ([#88](https://github.com/kolatts/pncli/issues/88)) ([ecc81a4](https://github.com/kolatts/pncli/commit/ecc81a40c90909d1de0103ed7b761fa9a2634368)) +* **udeploy:** remove username/password auth, PAT-only ([#103](https://github.com/kolatts/pncli/issues/103)) ([9341e70](https://github.com/kolatts/pncli/commit/9341e7052efba2613757876601899048b22d55e1)) +* **udeploy:** rename --version options to avoid root-level Commander.js collision ([#112](https://github.com/kolatts/pncli/issues/112)) ([048bb20](https://github.com/kolatts/pncli/commit/048bb20eb7c6608492c7f5fb0c06bf0349e10c1b)) +* **udeploy:** support username+pat as Basic auth credential pair ([#110](https://github.com/kolatts/pncli/issues/110)) ([1e041af](https://github.com/kolatts/pncli/commit/1e041af241d45b3a88847ef522e3eeb375489f46)), closes [#109](https://github.com/kolatts/pncli/issues/109) ## [1.7.0](https://github.com/kolatts/pncli/compare/v1.6.1...v1.7.0) (2026-04-13) ### Features -* migrate function app secrets to Key Vault references ([f8f0d7b](https://github.com/kolatts/pncli/commit/f8f0d7b59b48f44851c319f1af1a858d3b8349c8)) +* migrate function app secrets to Key Vault references ([b578991](https://github.com/kolatts/pncli/commit/b578991be4d4041058eab223f5988c51892e0f57)) ### Bug Fixes -* raise IP rate limit to 10 and reload page after submission ([01de005](https://github.com/kolatts/pncli/commit/01de0052167a636c374c85dfeaec219279c75257)) +* raise IP rate limit to 10 and reload page after submission ([a6b3a3e](https://github.com/kolatts/pncli/commit/a6b3a3e55d16e88354c7a915e502c1da7f851aa2)) ## [1.6.1](https://github.com/kolatts/pncli/compare/v1.6.0...v1.6.1) (2026-04-12) ### Bug Fixes -* add repository field to package.json for npm provenance verification ([8fa894d](https://github.com/kolatts/pncli/commit/8fa894d1b77e4805092c9bb0a55663354dc786d0)) +* add repository field to package.json for npm provenance verification ([d5e11c9](https://github.com/kolatts/pncli/commit/d5e11c9f9563a405a75275412467dfbb1923aa6c)) ## [1.6.0](https://github.com/kolatts/pncli/compare/v1.5.0...v1.6.0) (2026-04-12) ### Features -* add --output flag to config check command ([#41](https://github.com/kolatts/pncli/issues/41)) ([8483edd](https://github.com/kolatts/pncli/commit/8483edd597ad70d21d1f1db012026d86d10434fc)), closes [#40](https://github.com/kolatts/pncli/issues/40) -* add --repo flag to pncli config set for non-interactive repo config ([b3fa4c7](https://github.com/kolatts/pncli/commit/b3fa4c74eafd24ce259f375a9248ebed2c0a8007)) -* add 5 multi-tool workflow skills for vulnerability scanning and ticket creation ([58d7b78](https://github.com/kolatts/pncli/commit/58d7b781adf4429d911bf3bae7172befe02cf180)) -* add CLAUDE.md with project conventions and site screenshot requirement ([2747172](https://github.com/kolatts/pncli/commit/2747172742474a51a8cb4fe5e5e6a6216f9b9fe4)) -* add denied label and close issue when triage rejects scope ([ecf31b1](https://github.com/kolatts/pncli/commit/ecf31b16de08a7f36bdd952b1e4837c6ae3c9289)) -* add service pills, category grouping, skills install CLI, and provider prompting ([53293de](https://github.com/kolatts/pncli/commit/53293def8acf7502a740bc07effca88d123be873)) -* Claude issue triage and review response workflows ([#34](https://github.com/kolatts/pncli/issues/34)) ([0204ce0](https://github.com/kolatts/pncli/commit/0204ce0e18402d0240ec1073d5cc8c8f8e87a003)) -* surgical skills install, copilot-instructions download, and local-setup skill ([6daeb71](https://github.com/kolatts/pncli/commit/6daeb713cc53e55622a43a8968bbe07bc9b90740)) -* trigger triage on from-website label in addition to claude-triage ([fb65214](https://github.com/kolatts/pncli/commit/fb652146270b9b87da2882759a9eb3fd9040eb05)) -* Turnstile CAPTCHA, persistent rate limiting, and Azure Queue for feedback ([#45](https://github.com/kolatts/pncli/issues/45)) ([e067fd5](https://github.com/kolatts/pncli/commit/e067fd503ec63c4f3ea7033b906c803bb118d1ae)) -* vulnerability scanning skills, service pills, skills install CLI, and local-setup ([77b0744](https://github.com/kolatts/pncli/commit/77b074470f4d0b4100d6ac3ed77614feb77432c4)) +* add --output flag to config check command ([#41](https://github.com/kolatts/pncli/issues/41)) ([39ab198](https://github.com/kolatts/pncli/commit/39ab198098ec739060f4dd96cc3e0c24d4e1532e)), closes [#40](https://github.com/kolatts/pncli/issues/40) +* add --repo flag to pncli config set for non-interactive repo config ([ce48d59](https://github.com/kolatts/pncli/commit/ce48d593e8559ae6537a2ee709a5b90c11bba371)) +* add 5 multi-tool workflow skills for vulnerability scanning and ticket creation ([a835d03](https://github.com/kolatts/pncli/commit/a835d037f3b51e0cceec624edc3b5e5cb8f8b94f)) +* add CLAUDE.md with project conventions and site screenshot requirement ([16a6c52](https://github.com/kolatts/pncli/commit/16a6c52bffdd56c70c5f42b39ead7d57b4995696)) +* add denied label and close issue when triage rejects scope ([cc3cba8](https://github.com/kolatts/pncli/commit/cc3cba8ebf8b33e8cec030dcd64d0816f16c1a25)) +* add service pills, category grouping, skills install CLI, and provider prompting ([2c29714](https://github.com/kolatts/pncli/commit/2c2971409127560764f40acfa1938c68d143a716)) +* Claude issue triage and review response workflows ([#34](https://github.com/kolatts/pncli/issues/34)) ([e429306](https://github.com/kolatts/pncli/commit/e429306fc9c785c4566a7b9cc94640d92bdb2aef)) +* surgical skills install, copilot-instructions download, and local-setup skill ([0fd52a7](https://github.com/kolatts/pncli/commit/0fd52a732ee7a53fdca5436b38ea6ec60b6fef57)) +* trigger triage on from-website label in addition to claude-triage ([e5ffeb4](https://github.com/kolatts/pncli/commit/e5ffeb4910dc973b9cf3027a8da0704b15fb852e)) +* Turnstile CAPTCHA, persistent rate limiting, and Azure Queue for feedback ([#45](https://github.com/kolatts/pncli/issues/45)) ([09a1c2e](https://github.com/kolatts/pncli/commit/09a1c2ec442bba05d20f1a1496dfd8a768c21500)) +* vulnerability scanning skills, service pills, skills install CLI, and local-setup ([dd0343d](https://github.com/kolatts/pncli/commit/dd0343d80625309f2717f20bd6d0d2fd27c38b38)) ### Bug Fixes -* add job summary, label creation, and label cleanup improvements ([#38](https://github.com/kolatts/pncli/issues/38)) ([1d61e7a](https://github.com/kolatts/pncli/commit/1d61e7a8e93a02f72f99711ced65bbf07429ed06)) -* address PR review — path traversal guard, gallery fallback, ADO linking ([d994091](https://github.com/kolatts/pncli/commit/d9940917aeaab3058d0174559d6e5fadb812782b)) -* allow claude bot PRs through review, skip other bots ([b4d4ac7](https://github.com/kolatts/pncli/commit/b4d4ac736f32b966de8c9096cfae96f77911dd86)) -* allow claude bot to trigger review action via allowed_bots ([05ce1e3](https://github.com/kolatts/pncli/commit/05ce1e3a8c7d13df9065f3b6fdf4aba461ec5b3e)) -* append .git suffix to claude-marketplace URL ([#28](https://github.com/kolatts/pncli/issues/28)) ([992fd31](https://github.com/kolatts/pncli/commit/992fd31cd3207bbd836b89f7692268b5fd1bfaa5)) -* mandate gh pr create in triage and improve comment link format ([f143aeb](https://github.com/kolatts/pncli/commit/f143aebe1bce32f6ddf36da9dbb8089b11e5abc4)) -* scope triage concurrency group to label name to prevent cancellation ([ffba8a8](https://github.com/kolatts/pncli/commit/ffba8a871a4c33f95cb153d2e8cf8330305078d6)) -* validate project fit from CLAUDE.md before any code changes in triage ([ec48034](https://github.com/kolatts/pncli/commit/ec4803456006710e9d1601ca02a532e62a94bbf1)) +* add job summary, label creation, and label cleanup improvements ([#38](https://github.com/kolatts/pncli/issues/38)) ([f052818](https://github.com/kolatts/pncli/commit/f0528188f0cc90afe53dc72080342370c14496ca)) +* address PR review — path traversal guard, gallery fallback, ADO linking ([dce526e](https://github.com/kolatts/pncli/commit/dce526e4caf13af391921ef150cede7821590877)) +* allow claude bot PRs through review, skip other bots ([de57067](https://github.com/kolatts/pncli/commit/de570670940e2db4283619581377473c5255df5e)) +* allow claude bot to trigger review action via allowed_bots ([3c47ba3](https://github.com/kolatts/pncli/commit/3c47ba35d5f5f7efc18519897a6c2e2a6d8e5963)) +* append .git suffix to claude-marketplace URL ([#28](https://github.com/kolatts/pncli/issues/28)) ([554c707](https://github.com/kolatts/pncli/commit/554c707c88e0c70ea0886f54739d2ae552b0fadf)) +* mandate gh pr create in triage and improve comment link format ([d5227b8](https://github.com/kolatts/pncli/commit/d5227b88950ccf1a049d500e174887dc8d83569e)) +* scope triage concurrency group to label name to prevent cancellation ([2da1286](https://github.com/kolatts/pncli/commit/2da128649c788599c3747157ee848d617be82c41)) +* validate project fit from CLAUDE.md before any code changes in triage ([8ab1163](https://github.com/kolatts/pncli/commit/8ab1163c5ddc57cc8dd3c4d7f1ae1dac44818a84)) ## [1.5.0](https://github.com/kolatts/pncli/compare/v1.4.0...v1.5.0) (2026-04-11) ### Features -* add permissions configuration for Bash commands in settings ([d8ddd7f](https://github.com/kolatts/pncli/commit/d8ddd7f29e9c6658c6ccd02e1cf26eb0e9b4a3cb)) -* add pncli config check command ([#24](https://github.com/kolatts/pncli/issues/24)) ([ab18549](https://github.com/kolatts/pncli/commit/ab1854903e790021edfb78d6880bd2157b726ba5)) -* bootstrap Astro site and GitHub Pages deploy workflow (Phase 1) ([#19](https://github.com/kolatts/pncli/issues/19)) ([85ee755](https://github.com/kolatts/pncli/commit/85ee75512f740fe469a5999c663de672db6c2993)) -* Claude Code skills, ADO diff/build-status, and site Skills section ([#25](https://github.com/kolatts/pncli/issues/25)) ([a284f93](https://github.com/kolatts/pncli/commit/a284f932579fce505548a4478208f55c28342c37)) -* pncli GitHub Pages site (Phases 1–5) ([#20](https://github.com/kolatts/pncli/issues/20)) ([bac6e89](https://github.com/kolatts/pncli/commit/bac6e89642db0f27bdd47753f421514dd875af8a)) +* add permissions configuration for Bash commands in settings ([0fcf3c1](https://github.com/kolatts/pncli/commit/0fcf3c1a6a8496c1f496cc8275643146202602fb)) +* add pncli config check command ([#24](https://github.com/kolatts/pncli/issues/24)) ([0c0f251](https://github.com/kolatts/pncli/commit/0c0f25130a0971404c7461b5dc5d548f713a121a)) +* bootstrap Astro site and GitHub Pages deploy workflow (Phase 1) ([#19](https://github.com/kolatts/pncli/issues/19)) ([459bee1](https://github.com/kolatts/pncli/commit/459bee14f89493b6f8b4b8b6eff09c76c1fe737d)) +* Claude Code skills, ADO diff/build-status, and site Skills section ([#25](https://github.com/kolatts/pncli/issues/25)) ([ba31afd](https://github.com/kolatts/pncli/commit/ba31afda0bfbc591b5f7860f4a70cb39b400ab02)) +* pncli GitHub Pages site (Phases 1–5) ([#20](https://github.com/kolatts/pncli/issues/20)) ([72c19bf](https://github.com/kolatts/pncli/commit/72c19bf257df5d867a5d669dedc8eacffa64470b)) ### Bug Fixes -* downgrade to .NET 9 — .NET 10 runtime unstable on Linux Consumption ([7f65292](https://github.com/kolatts/pncli/commit/7f652921641a05d2c13af92d2c602e197bbae766)) -* drop AspNetCore integration — function uses standard isolated HTTP types ([0fdcae3](https://github.com/kolatts/pncli/commit/0fdcae3740d7f383846d07e28774e7f2f540f7a1)) -* redirect provision.sh progress output to stderr ([c8a5407](https://github.com/kolatts/pncli/commit/c8a5407703f38571160682c4532abf47b46bf6b7)) -* remove ApplicationInsights package — PerfCounterCollector aborts on Linux ([313cd89](https://github.com/kolatts/pncli/commit/313cd890d98aaee7851f0ff4e630a022a30b0bc5)) -* **site:** move paperwork monster to hero section, fix DC copy and Artifactory status ([#23](https://github.com/kolatts/pncli/issues/23)) ([f3219be](https://github.com/kolatts/pncli/commit/f3219be556f81c8b35feab4a39c211a3087ffbb7)) -* update Azure Functions packages for .NET 10 compatibility ([4bef710](https://github.com/kolatts/pncli/commit/4bef7106f96bc2f5656513d1e9020ec6ec5c72a9)) +* downgrade to .NET 9 — .NET 10 runtime unstable on Linux Consumption ([bf1b9bb](https://github.com/kolatts/pncli/commit/bf1b9bb202743048057557759f960c526917c671)) +* drop AspNetCore integration — function uses standard isolated HTTP types ([e6e9658](https://github.com/kolatts/pncli/commit/e6e9658281bf1842741c4d9e38e0cf3f1f5c92fc)) +* redirect provision.sh progress output to stderr ([ee13f8b](https://github.com/kolatts/pncli/commit/ee13f8b2ccfd1e704229b4810159178f5b599b6e)) +* remove ApplicationInsights package — PerfCounterCollector aborts on Linux ([0ef1d06](https://github.com/kolatts/pncli/commit/0ef1d06664a616e58f091b8fc9b18738eed9cc93)) +* **site:** move paperwork monster to hero section, fix DC copy and Artifactory status ([#23](https://github.com/kolatts/pncli/issues/23)) ([01125eb](https://github.com/kolatts/pncli/commit/01125ebfaec0dfa52addea6f50e53de5b7a13163)) +* update Azure Functions packages for .NET 10 compatibility ([7cd1ab6](https://github.com/kolatts/pncli/commit/7cd1ab6633999c80b1d997f9a3b71be02436dd18)) ## [1.4.0](https://github.com/kolatts/pncli/compare/v1.3.0...v1.4.0) (2026-04-11) ### Features -* Azure DevOps Server integration (work items, repos, PRs, pipelines) ([#15](https://github.com/kolatts/pncli/issues/15)) ([a4fc281](https://github.com/kolatts/pncli/commit/a4fc28113361d06c18e633f5b418226989febe96)) -* consolidate SDElements auth into single connection string ([663d9b2](https://github.com/kolatts/pncli/commit/663d9b22add61cf4c14d1d0f882d2f6ae003de07)) +* Azure DevOps Server integration (work items, repos, PRs, pipelines) ([#15](https://github.com/kolatts/pncli/issues/15)) ([20deffd](https://github.com/kolatts/pncli/commit/20deffdf7fbe8d4b8d23a7a77c7a528360630389)) +* consolidate SDElements auth into single connection string ([f8d0b29](https://github.com/kolatts/pncli/commit/f8d0b298983528339a6ba4114d6112be1421125f)) ### Bug Fixes -* normalize SDElements host to full base URL in connection string parser ([38c38f4](https://github.com/kolatts/pncli/commit/38c38f4544884e6d1b5110aaa3c26294bd583e31)) -* suppress git stderr in getRepoRoot to avoid fatal error outside repos ([94bca2f](https://github.com/kolatts/pncli/commit/94bca2faf2b33e75672ee3111801f508bfb8320e)) +* normalize SDElements host to full base URL in connection string parser ([e1af936](https://github.com/kolatts/pncli/commit/e1af93662c6d9d2617cbdf13ff1d1c4e322783a2)) +* suppress git stderr in getRepoRoot to avoid fatal error outside repos ([20d6ee0](https://github.com/kolatts/pncli/commit/20d6ee0804b3c268123375136cd5095bd55b25b8)) ## [1.3.0](https://github.com/kolatts/pncli/compare/v1.2.0...v1.3.0) (2026-04-06) ### Features -* Confluence integration + fail() exit fix + TLS bypass ([#10](https://github.com/kolatts/pncli/issues/10)) ([95a2084](https://github.com/kolatts/pncli/commit/95a20840c07661dcf1ef875cddd48e76aab3344f)) -* SDElements integration — projects, tasks, threats, users ([#13](https://github.com/kolatts/pncli/issues/13)) ([7608ebe](https://github.com/kolatts/pncli/commit/7608ebe91afc6f16817e83d6df1401df70c1b934)) -* SonarQube Server integration with PAT auth ([#12](https://github.com/kolatts/pncli/issues/12)) ([1428bea](https://github.com/kolatts/pncli/commit/1428bea266d9c68f5b2d0270ca86c4caec48a809)) +* Confluence integration + fail() exit fix + TLS bypass ([#10](https://github.com/kolatts/pncli/issues/10)) ([078aea4](https://github.com/kolatts/pncli/commit/078aea4937eff7b72fa8ca89689329e356d23a58)) +* SDElements integration — projects, tasks, threats, users ([#13](https://github.com/kolatts/pncli/issues/13)) ([0ea2119](https://github.com/kolatts/pncli/commit/0ea2119259220e9262f36a89e822f5aa980ca4d4)) +* SonarQube Server integration with PAT auth ([#12](https://github.com/kolatts/pncli/issues/12)) ([a265c76](https://github.com/kolatts/pncli/commit/a265c76ee7877e70820905c12e25bab672eac8cb)) ## [1.2.0](https://github.com/kolatts/pncli/compare/v1.1.0...v1.2.0) (2026-04-05) ### Features -* dep watchdog — pncli deps command group ([#7](https://github.com/kolatts/pncli/issues/7)) ([d5aeb5f](https://github.com/kolatts/pncli/commit/d5aeb5f133193d1ba3fa9e01c8d0b80a4bbe9531)) +* dep watchdog — pncli deps command group ([#7](https://github.com/kolatts/pncli/issues/7)) ([f76934c](https://github.com/kolatts/pncli/commit/f76934c6e23b8e0f7739c9dc1bb68d1aa2a1b8f0)) ### Bug Fixes -* Jira error deserialization, Connection header, and exit codes ([#8](https://github.com/kolatts/pncli/issues/8)) ([00e78ad](https://github.com/kolatts/pncli/commit/00e78ad22390ac598bf6ee59d3b5907cce4f84ce)) +* Jira error deserialization, Connection header, and exit codes ([#8](https://github.com/kolatts/pncli/issues/8)) ([798bb43](https://github.com/kolatts/pncli/commit/798bb433e21269011d21bfdba0d8017f3ec76a90)) ## [1.1.0](https://github.com/kolatts/pncli/compare/v1.0.1...v1.1.0) (2026-04-05) ### Features -* add PNCLI_EMAIL and PNCLI_USERID as global user identity ([81f0091](https://github.com/kolatts/pncli/commit/81f00913a3ca4295631ad5e3701dac6a1553e70a)) -* add user identity prompts to config init wizard ([e200a5a](https://github.com/kolatts/pncli/commit/e200a5a7defd54ba4a39a49518dd6342533c23dc)) -* enterprise testing — user identity, Jira v2, husky, v1.1.0 ([8fb3b2e](https://github.com/kolatts/pncli/commit/8fb3b2e086fe1cd4e6ca31e1b8592dfecefdfbd7)) -* Jira custom fields + auto-generated copilot docs ([#6](https://github.com/kolatts/pncli/issues/6)) ([a88c01b](https://github.com/kolatts/pncli/commit/a88c01bd681679e738407690d284ac640893fe0d)) -* switch Jira to API v2 with Bearer token auth ([6372db9](https://github.com/kolatts/pncli/commit/6372db9bba3c4213f466cdf021caed4dc11e510f)) +* add PNCLI_EMAIL and PNCLI_USERID as global user identity ([fa611bf](https://github.com/kolatts/pncli/commit/fa611bf0ecadb24c7493faecacab77cb23cea7f1)) +* add user identity prompts to config init wizard ([b0f5be5](https://github.com/kolatts/pncli/commit/b0f5be587b344da503c57719114a1aefba9cf561)) +* enterprise testing — user identity, Jira v2, husky, v1.1.0 ([08853f2](https://github.com/kolatts/pncli/commit/08853f23a48cea90de3506cb2da1cfc0144d60a2)) +* Jira custom fields + auto-generated copilot docs ([#6](https://github.com/kolatts/pncli/issues/6)) ([390511f](https://github.com/kolatts/pncli/commit/390511fb4e971b14a2d00847aa1bbed09c15f348)) +* switch Jira to API v2 with Bearer token auth ([e6e0b09](https://github.com/kolatts/pncli/commit/e6e0b09fe6b22a932e7b0058bca179058c07183b)) ## [1.0.1](https://github.com/kolatts/pncli/compare/v1.0.0...v1.0.1) (2026-04-04) ### Bug Fixes -* rename package to @kolatts/pncli and add --access=public for npm publish ([6082ae6](https://github.com/kolatts/pncli/commit/6082ae6cd8b5f10413a517cf3c0ced68de21e8dc)) +* rename package to @kolatts/pncli and add --access=public for npm publish ([f85a6b5](https://github.com/kolatts/pncli/commit/f85a6b510f7eb938c1a4b54c8813ecb1e3a3826c)) ## 1.0.0 (2026-04-04) ### Features -* add HTTP client and Bitbucket Server integration 🔌 ([921acfa](https://github.com/kolatts/pncli/commit/921acfaaea580a94a957d9cc3aaa687ee86cb790)) -* add Jira Data Cloud integration 🎫 ([7334fd2](https://github.com/kolatts/pncli/commit/7334fd2623c46b0f57bb369fd1456e489b6b777b)) -* scaffold Phase 1 — skeleton, config system, git commands 🏗️ ([3d72b21](https://github.com/kolatts/pncli/commit/3d72b21c1231321f7188aeff16bfd8e23f607bdd)) +* add HTTP client and Bitbucket Server integration 🔌 ([e1ecace](https://github.com/kolatts/pncli/commit/e1ecace58b9452c69f8e492248cd6f39061bb88a)) +* add Jira Data Cloud integration 🎫 ([0c9b30d](https://github.com/kolatts/pncli/commit/0c9b30d82438c4e0b82963c05d6e133cc8e416e7)) +* scaffold Phase 1 — skeleton, config system, git commands 🏗️ ([25a7aeb](https://github.com/kolatts/pncli/commit/25a7aeb933d068eb44cc1a15baa31ee5534638c6)) ### Bug Fixes -* remove invalid package-name input from release-please-action@v4 ([ec144d9](https://github.com/kolatts/pncli/commit/ec144d9972508a03773acd3817b3f4c7c3141072)) +* remove invalid package-name input from release-please-action@v4 ([85215e4](https://github.com/kolatts/pncli/commit/85215e4cf22972f766d33e23b9a699e534685eff)) ## Changelog diff --git a/CLAUDE.md b/CLAUDE.md index 267476f..74c5934 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -76,6 +76,28 @@ pncli integrations must be self-contained. Users cannot be required to have any Unit tests must exercise internal logic — auth header construction, URL building, response parsing, config resolution, token-cache expiry — by stubbing `fetch` (see `src/lib/http.test.ts` for the pattern). Tests must never depend on a live external service being reachable; a developer running `npm test` offline or on a locked-down CI runner must get the same pass/fail result as one with full network access. Connectivity against real services is what `pncli config test` is for, not the unit test suite. +Test fixtures must use placeholder hostnames per **Placeholder Hostnames** below. A repro captured against a live host gets sanitized before it becomes a test. + +## Placeholder Hostnames + +Never commit a real hostname, environment ID, tenant ID, or account identifier — not in source, tests, docs, skills, issues, or PR descriptions. This includes internal hosts from whatever environment you reproduced a bug in. + +**Self-hosted / on-premise services** use `.imagile.dev`: + +`jira.imagile.dev`, `bitbucket.imagile.dev`, `confluence.imagile.dev`, `sonar.imagile.dev`, `jenkins.imagile.dev`, `artifactory.imagile.dev`, `dynatrace.imagile.dev`, `ucd.imagile.dev`, `sde.imagile.dev`, `tfs.imagile.dev`, `ado.imagile.dev`, `iq.imagile.dev`, `ghe.imagile.dev` + +**Vendor-hosted SaaS** keeps the vendor domain, with `imagile` as the tenant: `imagile.service-now.com`, `imagile.sdelements.com`, `abc12345.live.dynatrace.com`, `eu.ast.checkmarx.net`. + +**Opaque IDs** (tenant, realm, environment, org): `imagile` where a name reads naturally, `abc12345` for short IDs, `abc12345-0000-0000-0000-000000000000` for UUID-shaped values. + +Do not use `example.com`, `company.com`, `mycompany.com`, `your-company.com`, or `examplecompany.net`. The last four are real domains registered to third parties — a user who copy-pastes one into `baseUrl` sends their credentials to someone else's host. + +**Exception — email addresses.** Email placeholders keep `you@example.com`. `example.com` is RFC 2606 reserved and is the conventional placeholder for an address field; `you@imagile.dev` would wrongly imply the user's mailbox lives on the maintainer's domain. This rule covers service hostnames, not email. + +**Exception:** tests asserting behavior against a *foreign* host (rejecting a mismatched git remote, cross-origin checks) must use a visibly different domain. `src/lib/git-context.test.ts` keeps `other.example.com` for exactly this reason — using `imagile.dev` on both sides would defeat the test. + +**Constraint — never add wildcard DNS to `imagile.dev`.** These placeholders are safe because `*.imagile.dev` does not resolve, so a copy-pasted config fails at DNS before pncli sends any auth header. A wildcard A/CNAME record would silently turn every published example into a credential-collection endpoint. If a wildcard ever becomes necessary, migrate these docs to a reserved RFC 2606 domain first. + ## Commit Conventions Use Conventional Commits: `fix:` (patch), `feat:` (minor), `feat!:` (breaking/major). diff --git a/pncli-scaffold-prompt.md b/pncli-scaffold-prompt.md index 919352d..f7bbb26 100644 --- a/pncli-scaffold-prompt.md +++ b/pncli-scaffold-prompt.md @@ -234,11 +234,11 @@ Owned by the individual developer. Contains auth credentials and server URLs. NO { "jira": { "baseUrl": "https://your-domain.atlassian.net", - "email": "you@company.com", + "email": "you@example.com", "apiToken": "your-jira-api-token" }, "bitbucket": { - "baseUrl": "https://bitbucket.your-company.com", + "baseUrl": "https://bitbucket.imagile.dev", "pat": "your-bitbucket-pat" }, "defaults": { @@ -343,7 +343,7 @@ Error shape: - Detect repo root via `git rev-parse --show-toplevel` - Parse Bitbucket project/repo from first remote matching the configured `bitbucket.baseUrl` -- Parse both SSH (`git@bitbucket.company.com:7999/PROJ/repo.git`) and HTTPS (`https://bitbucket.company.com/scm/PROJ/repo.git`) remote formats +- Parse both SSH (`git@bitbucket.imagile.dev:7999/PROJ/repo.git`) and HTTPS (`https://bitbucket.imagile.dev/scm/PROJ/repo.git`) remote formats - Get current branch via `git rev-parse --abbrev-ref HEAD` - All git operations use `child_process.execSync` with `{ encoding: 'utf8', cwd: repoRoot }` - Handle "not a git repo" gracefully — return null, don't throw diff --git a/skills/pncli/ado.md b/skills/pncli/ado.md index 1130b6e..f446bf4 100644 --- a/skills/pncli/ado.md +++ b/skills/pncli/ado.md @@ -6,13 +6,13 @@ Enables: `pncli ado workitem`, `pncli ado repo`, `pncli ado repo create`, `pncli | Key | Env var | Description | |-----|---------|-------------| -| `ado.baseUrl` | `PNCLI_ADO_BASE_URL` | ADO Server root, e.g. `https://tfs.company.com` | +| `ado.baseUrl` | `PNCLI_ADO_BASE_URL` | ADO Server root, e.g. `https://tfs.imagile.dev` | | `ado.pat` | `PNCLI_ADO_PAT` | Personal access token | ## Config file (persistent) ``` -pncli config set ado.baseUrl https://tfs.company.com +pncli config set ado.baseUrl https://tfs.imagile.dev pncli config set ado.pat pncli config set defaults.ado.collection DefaultCollection pncli config set defaults.ado.project MyProject @@ -21,7 +21,7 @@ pncli config set defaults.ado.project MyProject ## Env vars (ephemeral / CI) ``` -export PNCLI_ADO_BASE_URL=https://tfs.company.com +export PNCLI_ADO_BASE_URL=https://tfs.imagile.dev export PNCLI_ADO_PAT= ``` diff --git a/skills/pncli/artifactory.md b/skills/pncli/artifactory.md index 3f99ed5..78fb10b 100644 --- a/skills/pncli/artifactory.md +++ b/skills/pncli/artifactory.md @@ -6,7 +6,7 @@ Enables: `pncli artifactory repo`, `pncli artifactory package` — list reposito | Key | Env var | Description | |-----|---------|-------------| -| `artifactory.baseUrl` | `PNCLI_ARTIFACTORY_BASE_URL` | Artifactory root, e.g. `https://artifactory.company.com` | +| `artifactory.baseUrl` | `PNCLI_ARTIFACTORY_BASE_URL` | Artifactory root, e.g. `https://artifactory.imagile.dev` | | `artifactory.token` | `PNCLI_ARTIFACTORY_TOKEN` | Identity token or API key | ## Optional — virtual repo names @@ -20,7 +20,7 @@ Enables: `pncli artifactory repo`, `pncli artifactory package` — list reposito ## Config file (persistent) ``` -pncli config set artifactory.baseUrl https://artifactory.company.com +pncli config set artifactory.baseUrl https://artifactory.imagile.dev pncli config set artifactory.token pncli config set artifactory.npmRepo npm-virtual pncli config set artifactory.nugetRepo nuget-virtual @@ -30,6 +30,6 @@ pncli config set artifactory.mavenRepo maven-virtual ## Env vars (ephemeral / CI) ``` -export PNCLI_ARTIFACTORY_BASE_URL=https://artifactory.company.com +export PNCLI_ARTIFACTORY_BASE_URL=https://artifactory.imagile.dev export PNCLI_ARTIFACTORY_TOKEN= ``` diff --git a/skills/pncli/bitbucket.md b/skills/pncli/bitbucket.md index 25f3485..efc996c 100644 --- a/skills/pncli/bitbucket.md +++ b/skills/pncli/bitbucket.md @@ -6,20 +6,20 @@ Enables: `pncli bitbucket create-repo`, `pncli bitbucket list-prs`, `pncli bitbu | Key | Env var | Description | |-----|---------|-------------| -| `bitbucket.baseUrl` | `PNCLI_BITBUCKET_BASE_URL` | Bitbucket Server root, e.g. `https://bitbucket.company.com` | +| `bitbucket.baseUrl` | `PNCLI_BITBUCKET_BASE_URL` | Bitbucket Server root, e.g. `https://bitbucket.imagile.dev` | | `bitbucket.pat` | `PNCLI_BITBUCKET_PAT` | Personal access token | ## Config file (persistent) ``` -pncli config set bitbucket.baseUrl https://bitbucket.company.com +pncli config set bitbucket.baseUrl https://bitbucket.imagile.dev pncli config set bitbucket.pat ``` ## Env vars (ephemeral / CI) ``` -export PNCLI_BITBUCKET_BASE_URL=https://bitbucket.company.com +export PNCLI_BITBUCKET_BASE_URL=https://bitbucket.imagile.dev export PNCLI_BITBUCKET_PAT= ``` diff --git a/skills/pncli/checkmarx.md b/skills/pncli/checkmarx.md index 2bd4ac7..ef2c73a 100644 --- a/skills/pncli/checkmarx.md +++ b/skills/pncli/checkmarx.md @@ -7,7 +7,7 @@ Enables: `pncli checkmarx project list/get`, `pncli checkmarx scan list/get/stat | Key | Env var | Description | |-----|---------|-------------| | `checkmarx.baseUrl` | `PNCLI_CHECKMARX_BASE_URL` | Checkmarx One API base, e.g. `https://ast.checkmarx.net/api` | -| `checkmarx.tenantName` | `PNCLI_CHECKMARX_TENANT_NAME` | IAM realm / tenant name, e.g. `mycompany` | +| `checkmarx.tenantName` | `PNCLI_CHECKMARX_TENANT_NAME` | IAM realm / tenant name, e.g. `imagile` | | `checkmarx.apiKey` | `PNCLI_CHECKMARX_API_KEY` | API key created in Checkmarx One IAM (recommended) | | `checkmarx.clientId` | `PNCLI_CHECKMARX_CLIENT_ID` | OAuth2 client ID (alternative to API key) | | `checkmarx.clientSecret` | `PNCLI_CHECKMARX_CLIENT_SECRET` | OAuth2 client secret (alternative to API key) | @@ -19,7 +19,7 @@ short-lived bearer token automatically. No external tools are required. ``` pncli config set checkmarx.baseUrl https://ast.checkmarx.net/api -pncli config set checkmarx.tenantName mycompany +pncli config set checkmarx.tenantName imagile pncli config set checkmarx.apiKey ``` @@ -27,7 +27,7 @@ pncli config set checkmarx.apiKey ``` export PNCLI_CHECKMARX_BASE_URL=https://ast.checkmarx.net/api -export PNCLI_CHECKMARX_TENANT_NAME=mycompany +export PNCLI_CHECKMARX_TENANT_NAME=imagile export PNCLI_CHECKMARX_API_KEY= ``` diff --git a/skills/pncli/confluence.md b/skills/pncli/confluence.md index b9b9338..192f7f7 100644 --- a/skills/pncli/confluence.md +++ b/skills/pncli/confluence.md @@ -6,20 +6,20 @@ Enables: `pncli confluence get-page`, `create-page`, `update-page`, `delete-page | Key | Env var | Description | |-----|---------|-------------| -| `confluence.baseUrl` | `PNCLI_CONFLUENCE_BASE_URL` | Confluence server root, e.g. `https://confluence.company.com` | +| `confluence.baseUrl` | `PNCLI_CONFLUENCE_BASE_URL` | Confluence server root, e.g. `https://confluence.imagile.dev` | | `confluence.apiToken` | `PNCLI_CONFLUENCE_API_TOKEN` | Personal access token | ## Config file (persistent) ``` -pncli config set confluence.baseUrl https://confluence.company.com +pncli config set confluence.baseUrl https://confluence.imagile.dev pncli config set confluence.apiToken ``` ## Env vars (ephemeral / CI) ``` -export PNCLI_CONFLUENCE_BASE_URL=https://confluence.company.com +export PNCLI_CONFLUENCE_BASE_URL=https://confluence.imagile.dev export PNCLI_CONFLUENCE_API_TOKEN= ``` diff --git a/skills/pncli/contrast.md b/skills/pncli/contrast.md index 2ac2356..72c2b60 100644 --- a/skills/pncli/contrast.md +++ b/skills/pncli/contrast.md @@ -16,7 +16,7 @@ All four credential keys are found in your Contrast account under **User Setting **Base URL examples:** - Cloud SaaS: `https://app.contrastsecurity.com` -- On-premise: `https://contrast.company.com` +- On-premise: `https://contrast.imagile.dev` ## Config file (persistent) diff --git a/skills/pncli/jenkins.md b/skills/pncli/jenkins.md index 13ae946..891c92e 100644 --- a/skills/pncli/jenkins.md +++ b/skills/pncli/jenkins.md @@ -6,7 +6,7 @@ Enables: `pncli jenkins build`, `pncli jenkins job` — list builds, get build s | Key | Env var | Description | |-----|---------|-------------| -| `jenkins.baseUrl` | `PNCLI_JENKINS_BASE_URL` | Jenkins root, e.g. `https://jenkins.company.com` | +| `jenkins.baseUrl` | `PNCLI_JENKINS_BASE_URL` | Jenkins root, e.g. `https://jenkins.imagile.dev` | | `jenkins.username` | `PNCLI_JENKINS_USERNAME` | Jenkins username | | `jenkins.apiToken` | `PNCLI_JENKINS_API_TOKEN` | API token (generated in Jenkins → User → Configure → API Token) | @@ -15,7 +15,7 @@ pncli authenticates using HTTP Basic (username + API token). ## Config file (persistent) ``` -pncli config set jenkins.baseUrl https://jenkins.company.com +pncli config set jenkins.baseUrl https://jenkins.imagile.dev pncli config set jenkins.username pncli config set jenkins.apiToken ``` @@ -23,7 +23,7 @@ pncli config set jenkins.apiToken ## Env vars (ephemeral / CI) ``` -export PNCLI_JENKINS_BASE_URL=https://jenkins.company.com +export PNCLI_JENKINS_BASE_URL=https://jenkins.imagile.dev export PNCLI_JENKINS_USERNAME= export PNCLI_JENKINS_API_TOKEN= ``` @@ -36,7 +36,7 @@ Teams with different Jenkins controllers per repo can set `defaults.jenkins.base { "defaults": { "jenkins": { - "baseUrl": "https://jenkins.myteam.company.com" + "baseUrl": "https://jenkins.myteam.imagile.dev" } } } @@ -45,7 +45,7 @@ Teams with different Jenkins controllers per repo can set `defaults.jenkins.base Or via the CLI: ``` -pncli config set --repo defaults.jenkins.baseUrl https://jenkins.myteam.company.com +pncli config set --repo defaults.jenkins.baseUrl https://jenkins.myteam.imagile.dev ``` Resolution order (highest to lowest): project `.pncli.json` → global config → `PNCLI_JENKINS_BASE_URL` env var. diff --git a/skills/pncli/jira.md b/skills/pncli/jira.md index e6bc320..aa3c091 100644 --- a/skills/pncli/jira.md +++ b/skills/pncli/jira.md @@ -6,20 +6,20 @@ Enables: `pncli jira get-issue`, `create-issue`, `update-issue`, `search`, `list | Key | Env var | Description | |-----|---------|-------------| -| `jira.baseUrl` | `PNCLI_JIRA_BASE_URL` | Jira server root, e.g. `https://jira.company.com` | +| `jira.baseUrl` | `PNCLI_JIRA_BASE_URL` | Jira server root, e.g. `https://jira.imagile.dev` | | `jira.apiToken` | `PNCLI_JIRA_API_TOKEN` | Personal access token | ## Config file (persistent) ``` -pncli config set jira.baseUrl https://jira.company.com +pncli config set jira.baseUrl https://jira.imagile.dev pncli config set jira.apiToken ``` ## Env vars (ephemeral / CI) ``` -export PNCLI_JIRA_BASE_URL=https://jira.company.com +export PNCLI_JIRA_BASE_URL=https://jira.imagile.dev export PNCLI_JIRA_API_TOKEN= ``` diff --git a/skills/pncli/marketplace.md b/skills/pncli/marketplace.md index a38cf54..6738690 100644 --- a/skills/pncli/marketplace.md +++ b/skills/pncli/marketplace.md @@ -12,7 +12,7 @@ Use `--branch main` if the default branch is `main` instead of `master`. Use `-- **Example:** ``` -pncli skills marketplace add https://bitbucket.company.com/scm/ai/skills.git --name internal-ai +pncli skills marketplace add https://bitbucket.imagile.dev/scm/ai/skills.git --name internal-ai ``` You can register as many marketplaces as you like — just run `add` again with a different URL. `marketplace setup` is kept as an alias of `add` for backward compatibility. diff --git a/skills/pncli/openshift.md b/skills/pncli/openshift.md index 3c92073..b83305b 100644 --- a/skills/pncli/openshift.md +++ b/skills/pncli/openshift.md @@ -7,7 +7,7 @@ No `kubectl` or `oc` CLI is required. | Key | Env var | Description | |-----|---------|-------------| -| `openshift.baseUrl` | `PNCLI_OPENSHIFT_BASE_URL` | API server URL, e.g. `https://api.cluster.example.com:6443` | +| `openshift.baseUrl` | `PNCLI_OPENSHIFT_BASE_URL` | API server URL, e.g. `https://api.cluster.imagile.dev:6443` | | `openshift.token` | `PNCLI_OPENSHIFT_TOKEN` | Service account bearer token | ## Getting your service account token @@ -20,7 +20,7 @@ cat /var/run/secrets/kubernetes.io/serviceaccount/token **Via OpenShift REST API** (using an existing token): ```bash curl -H "Authorization: Bearer $EXISTING_TOKEN" \ - https://api.cluster.example.com:6443/api/v1/namespaces/my-ns/serviceaccounts/default/token \ + https://api.cluster.imagile.dev:6443/api/v1/namespaces/my-ns/serviceaccounts/default/token \ -X POST -H 'Content-Type: application/json' \ -d '{"apiVersion":"authentication.k8s.io/v1","kind":"TokenRequest","spec":{"expirationSeconds":3600}}' ``` @@ -28,14 +28,14 @@ curl -H "Authorization: Bearer $EXISTING_TOKEN" \ ## Set via env vars (ephemeral) ```bash -export PNCLI_OPENSHIFT_BASE_URL=https://api.cluster.example.com:6443 +export PNCLI_OPENSHIFT_BASE_URL=https://api.cluster.imagile.dev:6443 export PNCLI_OPENSHIFT_TOKEN=eyJhbGciOiJSUzI1NiI... ``` ## Set via config file (persistent) ```bash -pncli config set openshift.baseUrl https://api.cluster.example.com:6443 +pncli config set openshift.baseUrl https://api.cluster.imagile.dev:6443 pncli config set openshift.token eyJhbGciOiJSUzI1NiI... ``` diff --git a/skills/pncli/sde.md b/skills/pncli/sde.md index 50db5ed..b84c8c4 100644 --- a/skills/pncli/sde.md +++ b/skills/pncli/sde.md @@ -8,18 +8,18 @@ Enables: `pncli sde task` — list threat model tasks and their compliance statu |-----|---------|-------------| | `sde.connection` | `PNCLI_SDE_CONNECTION` | Connection string in the format `token@hostname` | -The connection string combines your API token and the SDElements hostname into a single value, e.g. `mytoken@sde.company.com`. +The connection string combines your API token and the SDElements hostname into a single value, e.g. `mytoken@sde.imagile.dev`. ## Config file (persistent) ``` -pncli config set sde.connection mytoken@sde.company.com +pncli config set sde.connection mytoken@sde.imagile.dev ``` ## Env vars (ephemeral / CI) ``` -export PNCLI_SDE_CONNECTION=mytoken@sde.company.com +export PNCLI_SDE_CONNECTION=mytoken@sde.imagile.dev ``` ## Repo defaults diff --git a/skills/pncli/servicenow.md b/skills/pncli/servicenow.md index c83fbcc..66c32e4 100644 --- a/skills/pncli/servicenow.md +++ b/skills/pncli/servicenow.md @@ -6,7 +6,7 @@ Enables: `pncli servicenow change`, `pncli servicenow incident` — list and get | Key | Env var | Description | |-----|---------|-------------| -| `servicenow.baseUrl` | `PNCLI_SERVICENOW_BASE_URL` | Instance root, e.g. `https://mycompany.service-now.com` | +| `servicenow.baseUrl` | `PNCLI_SERVICENOW_BASE_URL` | Instance root, e.g. `https://imagile.service-now.com` | | `servicenow.username` | `PNCLI_SERVICENOW_USERNAME` | ServiceNow username | ### Auth — password or API token (one required) @@ -19,7 +19,7 @@ Enables: `pncli servicenow change`, `pncli servicenow incident` — list and get ## Config file (persistent) ``` -pncli config set servicenow.baseUrl https://mycompany.service-now.com +pncli config set servicenow.baseUrl https://imagile.service-now.com pncli config set servicenow.username pncli config set servicenow.password ``` @@ -27,7 +27,7 @@ pncli config set servicenow.password ## Env vars (ephemeral / CI) ``` -export PNCLI_SERVICENOW_BASE_URL=https://mycompany.service-now.com +export PNCLI_SERVICENOW_BASE_URL=https://imagile.service-now.com export PNCLI_SERVICENOW_USERNAME= export PNCLI_SERVICENOW_PASSWORD= ``` diff --git a/skills/pncli/sonarqube.md b/skills/pncli/sonarqube.md index a146f78..cab2a35 100644 --- a/skills/pncli/sonarqube.md +++ b/skills/pncli/sonarqube.md @@ -6,20 +6,20 @@ Enables: `pncli sonar issue`, `pncli sonar project` — list code quality and se | Key | Env var | Description | |-----|---------|-------------| -| `sonar.baseUrl` | `PNCLI_SONAR_BASE_URL` | SonarQube server root, e.g. `https://sonar.company.com` | +| `sonar.baseUrl` | `PNCLI_SONAR_BASE_URL` | SonarQube server root, e.g. `https://sonar.imagile.dev` | | `sonar.token` | `PNCLI_SONAR_TOKEN` | User token (generated in SonarQube → My Account → Security) | ## Config file (persistent) ``` -pncli config set sonar.baseUrl https://sonar.company.com +pncli config set sonar.baseUrl https://sonar.imagile.dev pncli config set sonar.token ``` ## Env vars (ephemeral / CI) ``` -export PNCLI_SONAR_BASE_URL=https://sonar.company.com +export PNCLI_SONAR_BASE_URL=https://sonar.imagile.dev export PNCLI_SONAR_TOKEN= ``` diff --git a/skills/pncli/sonatypeiq.md b/skills/pncli/sonatypeiq.md index 3b5d4d9..3bba47d 100644 --- a/skills/pncli/sonatypeiq.md +++ b/skills/pncli/sonatypeiq.md @@ -6,7 +6,7 @@ Enables: `pncli sonatypeiq applications`, `pncli deps frisk --source sonatypeiq` | Key | Env var | Description | |-----|---------|-------------| -| `sonatypeiq.baseUrl` | `PNCLI_SONATYPEIQ_BASE_URL` | IQ Server root, e.g. `https://iq.company.com` | +| `sonatypeiq.baseUrl` | `PNCLI_SONATYPEIQ_BASE_URL` | IQ Server root, e.g. `https://iq.imagile.dev` | | `sonatypeiq.userCode` | `PNCLI_SONATYPEIQ_USER_CODE` | User Token code (from User Menu → User Token) | | `sonatypeiq.passcode` | `PNCLI_SONATYPEIQ_PASSCODE` | User Token passcode (from User Menu → User Token) | @@ -15,7 +15,7 @@ The `userCode` and `passcode` are User Token credentials, not your login passwor ## Config file (persistent) ``` -pncli config set sonatypeiq.baseUrl https://iq.company.com +pncli config set sonatypeiq.baseUrl https://iq.imagile.dev pncli config set sonatypeiq.userCode pncli config set sonatypeiq.passcode ``` @@ -23,7 +23,7 @@ pncli config set sonatypeiq.passcode ## Env vars (ephemeral / CI) ``` -export PNCLI_SONATYPEIQ_BASE_URL=https://iq.company.com +export PNCLI_SONATYPEIQ_BASE_URL=https://iq.imagile.dev export PNCLI_SONATYPEIQ_USER_CODE= export PNCLI_SONATYPEIQ_PASSCODE= ``` diff --git a/skills/pncli/udeploy.md b/skills/pncli/udeploy.md index d2103a5..938cbb7 100644 --- a/skills/pncli/udeploy.md +++ b/skills/pncli/udeploy.md @@ -8,7 +8,7 @@ Enables: `pncli udeploy component`, `pncli udeploy version`, `pncli udeploy proc | Key | Env var | Description | |-----|---------|-------------| -| `udeploy.baseUrl` | `PNCLI_UDEPLOY_BASE_URL` | UCD server root, e.g. `https://ucd.company.com` | +| `udeploy.baseUrl` | `PNCLI_UDEPLOY_BASE_URL` | UCD server root, e.g. `https://ucd.imagile.dev` | ### Auth option A — PAT @@ -26,7 +26,7 @@ Enables: `pncli udeploy component`, `pncli udeploy version`, `pncli udeploy proc ## Config file (persistent) ``` -pncli config set udeploy.baseUrl https://ucd.company.com +pncli config set udeploy.baseUrl https://ucd.imagile.dev pncli config set udeploy.pat # or pncli config set udeploy.username @@ -36,7 +36,7 @@ pncli config set udeploy.password ## Env vars (ephemeral / CI) ``` -export PNCLI_UDEPLOY_BASE_URL=https://ucd.company.com +export PNCLI_UDEPLOY_BASE_URL=https://ucd.imagile.dev export PNCLI_UDEPLOY_PAT= ``` diff --git a/src/lib/checkmarxFetch.test.ts b/src/lib/checkmarxFetch.test.ts index 38352db..f0d3ec0 100644 --- a/src/lib/checkmarxFetch.test.ts +++ b/src/lib/checkmarxFetch.test.ts @@ -17,7 +17,7 @@ function makeConfig(overrides: Partial = {}): Resol udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: 'https://ast.checkmarx.net', - tenantName: 'mycompany', + tenantName: 'imagile', apiKey: undefined, clientId: 'my-client-id', clientSecret: 'my-client-secret', @@ -111,7 +111,7 @@ describe('buildCheckmarxFetcher', () => { await fetcher('https://eu.ast.checkmarx.net/api/projects'); expect(mockFetch.mock.calls[0][0]).toBe( - 'https://eu.iam.checkmarx.net/auth/realms/mycompany/protocol/openid-connect/token' + 'https://eu.iam.checkmarx.net/auth/realms/imagile/protocol/openid-connect/token' ); }); @@ -127,7 +127,7 @@ describe('buildCheckmarxFetcher', () => { // First call is token exchange const tokenCall = mockFetch.mock.calls[0]; - expect(tokenCall[0]).toBe('https://iam.checkmarx.net/auth/realms/mycompany/protocol/openid-connect/token'); + expect(tokenCall[0]).toBe('https://iam.checkmarx.net/auth/realms/imagile/protocol/openid-connect/token'); expect(tokenCall[1]?.method).toBe('POST'); const body = tokenCall[1]?.body as string; expect(body).toContain('grant_type=client_credentials'); diff --git a/src/lib/config.test.ts b/src/lib/config.test.ts index ad9fca7..5907d19 100644 --- a/src/lib/config.test.ts +++ b/src/lib/config.test.ts @@ -10,15 +10,15 @@ vi.mock('child_process', () => ({ execSync: vi.fn() })); function baseConfig(overrides: Partial = {}): ResolvedConfig { return { user: { email: 'user@example.com', userId: 'user1' }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'secret-jira', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'secret-bb' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'secret-jira', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'secret-bb' }, github: { baseUrl: 'https://api.github.com', token: 'secret-gh' }, - confluence: { baseUrl: 'https://confluence.example.com', apiToken: 'secret-confluence', apiTokenExplicit: true }, - artifactory: { baseUrl: 'https://art.example.com', token: 'secret-art', npmRepo: 'npm', nugetRepo: 'nuget', mavenRepo: 'maven' }, - sonar: { baseUrl: 'https://sonar.example.com', token: 'secret-sonar' }, - sde: { baseUrl: 'https://sde.example.com', token: 'secret-sde' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'secret-ado', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'secret-jenkins' }, + confluence: { baseUrl: 'https://confluence.imagile.dev', apiToken: 'secret-confluence', apiTokenExplicit: true }, + artifactory: { baseUrl: 'https://art.imagile.dev', token: 'secret-art', npmRepo: 'npm', nugetRepo: 'nuget', mavenRepo: 'maven' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'secret-sonar' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'secret-sde' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'secret-ado', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'secret-jenkins' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, @@ -97,12 +97,12 @@ describe('maskConfig', () => { it('preserves non-secret fields', () => { const masked = maskConfig(baseConfig()) as ResolvedConfig; - expect(masked.jira.baseUrl).toBe('https://jira.example.com'); + expect(masked.jira.baseUrl).toBe('https://jira.imagile.dev'); expect(masked.user.email).toBe('user@example.com'); }); it('masks udeploy password when present', () => { - const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.example.com', pat: undefined, username: 'alice', password: 'secret' } }); + const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.imagile.dev', pat: undefined, username: 'alice', password: 'secret' } }); const masked = maskConfig(config) as ResolvedConfig; expect((masked.udeploy as { password?: string }).password).toBe('***'); }); @@ -114,7 +114,7 @@ describe('maskConfig', () => { }); it('masks checkmarx clientSecret when present', () => { - const config = baseConfig({ checkmarx: { baseUrl: 'https://ast.checkmarx.net', tenantName: 'mycompany', apiKey: 'key', clientId: 'id', clientSecret: 'secret' } }); + const config = baseConfig({ checkmarx: { baseUrl: 'https://ast.checkmarx.net', tenantName: 'imagile', apiKey: 'key', clientId: 'id', clientSecret: 'secret' } }); const masked = maskConfig(config) as ResolvedConfig; expect((masked.checkmarx as { apiKey?: string }).apiKey).toBe('***'); expect((masked.checkmarx as { clientSecret?: string }).clientSecret).toBe('***'); @@ -127,7 +127,7 @@ describe('maskConfig', () => { }); it('masks servicenow password and apiToken when present', () => { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: 'user', password: 'secret', apiToken: 'tok' } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: 'user', password: 'secret', apiToken: 'tok' } }); const masked = maskConfig(config) as ResolvedConfig; expect((masked.servicenow as { password?: string }).password).toBe('***'); expect((masked.servicenow as { apiToken?: string }).apiToken).toBe('***'); @@ -180,51 +180,51 @@ describe('loadConfig — jenkins.baseUrl resolution order', () => { }); it('project defaults.jenkins.baseUrl overrides global jenkins.baseUrl', () => { - fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.example.com' } })); - fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({ defaults: { jenkins: { baseUrl: 'https://project.jenkins.example.com' } } })); + fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.imagile.dev' } })); + fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({ defaults: { jenkins: { baseUrl: 'https://project.jenkins.imagile.dev' } } })); const config = loadConfig({ configPath: globalConfigPath }); - expect(config.jenkins.baseUrl).toBe('https://project.jenkins.example.com'); + expect(config.jenkins.baseUrl).toBe('https://project.jenkins.imagile.dev'); }); it('global jenkins.baseUrl is used when no project override is set', () => { - fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.example.com' } })); + fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.imagile.dev' } })); fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({})); const config = loadConfig({ configPath: globalConfigPath }); - expect(config.jenkins.baseUrl).toBe('https://global.jenkins.example.com'); + expect(config.jenkins.baseUrl).toBe('https://global.jenkins.imagile.dev'); }); it('env var takes precedence over global jenkins.baseUrl', () => { - process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.example.com'; - fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.example.com' } })); + process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.imagile.dev'; + fs.writeFileSync(globalConfigPath, JSON.stringify({ jenkins: { baseUrl: 'https://global.jenkins.imagile.dev' } })); fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({})); const config = loadConfig({ configPath: globalConfigPath }); - expect(config.jenkins.baseUrl).toBe('https://env.jenkins.example.com'); + expect(config.jenkins.baseUrl).toBe('https://env.jenkins.imagile.dev'); }); it('env var is used as fallback when neither project nor global config sets baseUrl', () => { - process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.example.com'; + process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.imagile.dev'; fs.writeFileSync(globalConfigPath, JSON.stringify({})); fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({})); const config = loadConfig({ configPath: globalConfigPath }); - expect(config.jenkins.baseUrl).toBe('https://env.jenkins.example.com'); + expect(config.jenkins.baseUrl).toBe('https://env.jenkins.imagile.dev'); }); it('project defaults.jenkins.baseUrl takes precedence over env var', () => { - process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.example.com'; + process.env['PNCLI_JENKINS_BASE_URL'] = 'https://env.jenkins.imagile.dev'; fs.writeFileSync(globalConfigPath, JSON.stringify({})); - fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({ defaults: { jenkins: { baseUrl: 'https://project.jenkins.example.com' } } })); + fs.writeFileSync(path.join(tmpDir, '.pncli.json'), JSON.stringify({ defaults: { jenkins: { baseUrl: 'https://project.jenkins.imagile.dev' } } })); const config = loadConfig({ configPath: globalConfigPath }); - expect(config.jenkins.baseUrl).toBe('https://project.jenkins.example.com'); + expect(config.jenkins.baseUrl).toBe('https://project.jenkins.imagile.dev'); }); }); @@ -256,9 +256,9 @@ describe('setConfigValue — JSON parsing', () => { }); it('stores a plain string as a string', () => { - setConfigValue('jira.baseUrl', 'https://jira.example.com', globalConfigPath); + setConfigValue('jira.baseUrl', 'https://jira.imagile.dev', globalConfigPath); const stored = JSON.parse(fs.readFileSync(globalConfigPath, 'utf8')); - expect(stored.jira.baseUrl).toBe('https://jira.example.com'); + expect(stored.jira.baseUrl).toBe('https://jira.imagile.dev'); }); it('stores invalid JSON as a raw string', () => { diff --git a/src/lib/errors.test.ts b/src/lib/errors.test.ts index 31c5f91..902cc74 100644 --- a/src/lib/errors.test.ts +++ b/src/lib/errors.test.ts @@ -28,6 +28,6 @@ describe('PncliError', () => { }); it('accepts url', () => { - expect(new PncliError('x', 500, 'https://api.example.com').url).toBe('https://api.example.com'); + expect(new PncliError('x', 500, 'https://api.imagile.dev').url).toBe('https://api.imagile.dev'); }); }); diff --git a/src/lib/git-context.test.ts b/src/lib/git-context.test.ts index 07359d5..afe001e 100644 --- a/src/lib/git-context.test.ts +++ b/src/lib/git-context.test.ts @@ -3,37 +3,37 @@ import { parseRemote, parseAdoRemote, parseGitHubRemote } from './git-context.js describe('parseRemote', () => { it('returns null when bitbucketBaseUrl is undefined', () => { - expect(parseRemote('git@bitbucket.example.com:7999/PROJ/repo.git', undefined)).toBeNull(); + expect(parseRemote('git@bitbucket.imagile.dev:7999/PROJ/repo.git', undefined)).toBeNull(); }); it('parses SSH format', () => { const result = parseRemote( - 'git@bitbucket.example.com:7999/PROJ/repo.git', - 'https://bitbucket.example.com' + 'git@bitbucket.imagile.dev:7999/PROJ/repo.git', + 'https://bitbucket.imagile.dev' ); expect(result).toEqual({ project: 'PROJ', repo: 'repo' }); }); it('parses SSH format without .git suffix', () => { const result = parseRemote( - 'git@bitbucket.example.com:7999/PROJ/repo', - 'https://bitbucket.example.com' + 'git@bitbucket.imagile.dev:7999/PROJ/repo', + 'https://bitbucket.imagile.dev' ); expect(result).toEqual({ project: 'PROJ', repo: 'repo' }); }); it('parses HTTPS format', () => { const result = parseRemote( - 'https://bitbucket.example.com/scm/PROJ/repo.git', - 'https://bitbucket.example.com' + 'https://bitbucket.imagile.dev/scm/PROJ/repo.git', + 'https://bitbucket.imagile.dev' ); expect(result).toEqual({ project: 'PROJ', repo: 'repo' }); }); it('parses HTTPS format without .git suffix', () => { const result = parseRemote( - 'https://bitbucket.example.com/scm/PROJ/repo', - 'https://bitbucket.example.com' + 'https://bitbucket.imagile.dev/scm/PROJ/repo', + 'https://bitbucket.imagile.dev' ); expect(result).toEqual({ project: 'PROJ', repo: 'repo' }); }); @@ -41,15 +41,15 @@ describe('parseRemote', () => { it('returns null when host does not match base URL', () => { const result = parseRemote( 'git@other.example.com:7999/PROJ/repo.git', - 'https://bitbucket.example.com' + 'https://bitbucket.imagile.dev' ); expect(result).toBeNull(); }); it('handles base URL with trailing slash', () => { const result = parseRemote( - 'https://bitbucket.example.com/scm/PROJ/repo.git', - 'https://bitbucket.example.com/' + 'https://bitbucket.imagile.dev/scm/PROJ/repo.git', + 'https://bitbucket.imagile.dev/' ); expect(result).toEqual({ project: 'PROJ', repo: 'repo' }); }); @@ -57,45 +57,45 @@ describe('parseRemote', () => { describe('parseAdoRemote', () => { it('returns null when adoBaseUrl is undefined', () => { - expect(parseAdoRemote('https://tfs.example.com/col/proj/_git/repo', undefined)).toBeNull(); + expect(parseAdoRemote('https://tfs.imagile.dev/col/proj/_git/repo', undefined)).toBeNull(); }); it('parses HTTPS format', () => { const result = parseAdoRemote( - 'https://tfs.example.com/col/proj/_git/repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/col/proj/_git/repo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'proj', repo: 'repo' }); }); it('parses HTTPS format with .git suffix', () => { const result = parseAdoRemote( - 'https://tfs.example.com/col/proj/_git/repo.git', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/col/proj/_git/repo.git', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'proj', repo: 'repo' }); }); it('parses HTTPS format with path prefix', () => { const result = parseAdoRemote( - 'https://tfs.example.com/tfs/col/proj/_git/repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/tfs/col/proj/_git/repo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'proj', repo: 'repo' }); }); it('parses SSH protocol format', () => { const result = parseAdoRemote( - 'ssh://git@tfs.example.com:22/col/proj/_ssh/repo', - 'https://tfs.example.com' + 'ssh://git@tfs.imagile.dev:22/col/proj/_ssh/repo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'proj', repo: 'repo' }); }); it('parses base URL with port', () => { const result = parseAdoRemote( - 'https://tfs.example.com:8080/col/proj/_git/repo', - 'https://tfs.example.com:8080' + 'https://tfs.imagile.dev:8080/col/proj/_git/repo', + 'https://tfs.imagile.dev:8080' ); expect(result).toEqual({ collection: 'col', project: 'proj', repo: 'repo' }); }); @@ -103,47 +103,47 @@ describe('parseAdoRemote', () => { it('returns null when host does not match', () => { const result = parseAdoRemote( 'https://other.example.com/col/proj/_git/repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev' ); expect(result).toBeNull(); }); it('returns null when no _git or _ssh segment', () => { const result = parseAdoRemote( - 'https://tfs.example.com/col/proj/repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/col/proj/repo', + 'https://tfs.imagile.dev' ); expect(result).toBeNull(); }); it('returns null when not enough path segments before marker', () => { const result = parseAdoRemote( - 'https://tfs.example.com/proj/_git/repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/proj/_git/repo', + 'https://tfs.imagile.dev' ); expect(result).toBeNull(); }); it('decodes percent-encoded project name from HTTPS URL', () => { const result = parseAdoRemote( - 'https://tfs.example.com/col/My%20Project/_git/myrepo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/col/My%20Project/_git/myrepo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'My Project', repo: 'myrepo' }); }); it('decodes percent-encoded collection and repo names', () => { const result = parseAdoRemote( - 'https://tfs.example.com/My%20Org/My%20Project/_git/My%20Repo', - 'https://tfs.example.com' + 'https://tfs.imagile.dev/My%20Org/My%20Project/_git/My%20Repo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'My Org', project: 'My Project', repo: 'My Repo' }); }); it('decodes percent-encoded project name from SSH URL', () => { const result = parseAdoRemote( - 'ssh://git@tfs.example.com:22/col/My%20Project/_ssh/myrepo', - 'https://tfs.example.com' + 'ssh://git@tfs.imagile.dev:22/col/My%20Project/_ssh/myrepo', + 'https://tfs.imagile.dev' ); expect(result).toEqual({ collection: 'col', project: 'My Project', repo: 'myrepo' }); }); @@ -171,9 +171,9 @@ describe('parseGitHubRemote', () => { }); it('matches a GitHub Enterprise host when baseUrl is provided', () => { - expect(parseGitHubRemote('ssh://git@ghe.example.com/org/repo.git', 'https://ghe.example.com')) + expect(parseGitHubRemote('ssh://git@ghe.imagile.dev/org/repo.git', 'https://ghe.imagile.dev')) .toEqual({ owner: 'org', repo: 'repo' }); - expect(parseGitHubRemote('git@ghe.example.com:org/repo.git', 'https://ghe.example.com')) + expect(parseGitHubRemote('git@ghe.imagile.dev:org/repo.git', 'https://ghe.imagile.dev')) .toEqual({ owner: 'org', repo: 'repo' }); }); diff --git a/src/lib/git-context.ts b/src/lib/git-context.ts index 1de5ccc..57f6e5f 100644 --- a/src/lib/git-context.ts +++ b/src/lib/git-context.ts @@ -41,7 +41,7 @@ export function parseRemote( // Normalize base URL for comparison const base = bitbucketBaseUrl.replace(/\/$/, '').replace(/^https?:\/\//, ''); - // SSH format: git@bitbucket.company.com:7999/PROJ/repo.git + // SSH format: git@bitbucket.imagile.dev:7999/PROJ/repo.git const sshMatch = remoteUrl.match(/^git@([^:]+)(?::\d+)?[:/]([^/]+)\/([^/]+?)(?:\.git)?$/); if (sshMatch) { const [, host, project, repo] = sshMatch; @@ -50,7 +50,7 @@ export function parseRemote( } } - // HTTPS format: https://bitbucket.company.com/scm/PROJ/repo.git + // HTTPS format: https://bitbucket.imagile.dev/scm/PROJ/repo.git const httpsMatch = remoteUrl.match(/^https?:\/\/([^/]+)\/scm\/([^/]+)\/([^/]+?)(?:\.git)?$/); if (httpsMatch) { const [, host, project, repo] = httpsMatch; @@ -82,7 +82,7 @@ export function parseAdoRemote( if (!adoBaseUrl) return null; // Normalize base URL: extract just the hostname (without port) for comparison, - // so that https://tfs.company.com:8080 and git@tfs.company.com:... both match. + // so that https://tfs.imagile.dev:8080 and git@tfs.imagile.dev:... both match. let baseHostname: string; try { const normalizedBase = /^https?:\/\//.test(adoBaseUrl) ? adoBaseUrl : `https://${adoBaseUrl}`; diff --git a/src/lib/http.test.ts b/src/lib/http.test.ts index f0cb984..f1d0db4 100644 --- a/src/lib/http.test.ts +++ b/src/lib/http.test.ts @@ -6,15 +6,15 @@ import type { ResolvedConfig } from '../types/config.js'; function baseConfig(overrides: Partial = {}): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: 'https://api.github.com', token: 'tok' }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, @@ -64,7 +64,7 @@ describe('HttpClient — missing credentials', () => { it('throws on missing jira apiToken', async () => { const config = baseConfig(); - config.jira = { baseUrl: 'https://jira.example.com', apiToken: undefined, customFields: [] }; + config.jira = { baseUrl: 'https://jira.imagile.dev', apiToken: undefined, customFields: [] }; const client = new HttpClient(config); await expect(client.jira('/rest/api/2/issue/TEST-1')).rejects.toMatchObject({ name: 'PncliError' }); }); @@ -78,7 +78,7 @@ describe('HttpClient — missing credentials', () => { it('throws on missing bitbucket pat', async () => { const config = baseConfig(); - config.bitbucket = { baseUrl: 'https://bb.example.com', pat: undefined }; + config.bitbucket = { baseUrl: 'https://bb.imagile.dev', pat: undefined }; const client = new HttpClient(config); await expect(client.bitbucket('/rest/api/1.0/projects')).rejects.toMatchObject({ name: 'PncliError' }); }); @@ -106,7 +106,7 @@ describe('HttpClient — missing credentials', () => { it('throws on missing udeploy credentials', async () => { const config = baseConfig(); - config.udeploy = { baseUrl: 'https://ucd.example.com', pat: undefined, username: undefined, password: undefined }; + config.udeploy = { baseUrl: 'https://ucd.imagile.dev', pat: undefined, username: undefined, password: undefined }; const client = new HttpClient(config); await expect(client.udeploy('/cli/application')).rejects.toMatchObject({ name: 'PncliError' }); }); @@ -120,7 +120,7 @@ describe('HttpClient — udeploy auth encoding', () => { return new Response('[]', { status: 200 }); }); try { - const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.example.com', pat: 'my-pat', username: undefined, password: undefined } }); + const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.imagile.dev', pat: 'my-pat', username: undefined, password: undefined } }); const client = new HttpClient(config); await client.udeploy('/cli/application'); } finally { @@ -138,7 +138,7 @@ describe('HttpClient — udeploy auth encoding', () => { return new Response('[]', { status: 200 }); }); try { - const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.example.com', pat: undefined, username: 'alice', password: 'secret' } }); + const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.imagile.dev', pat: undefined, username: 'alice', password: 'secret' } }); const client = new HttpClient(config); await client.udeploy('/cli/application'); } finally { @@ -156,7 +156,7 @@ describe('HttpClient — udeploy auth encoding', () => { return new Response('[]', { status: 200 }); }); try { - const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.example.com', pat: 'my-pat', username: 'alice', password: 'secret' } }); + const config = baseConfig({ udeploy: { baseUrl: 'https://ucd.imagile.dev', pat: 'my-pat', username: 'alice', password: 'secret' } }); const client = new HttpClient(config); await client.udeploy('/cli/application'); } finally { @@ -439,7 +439,7 @@ describe('HttpClient — ServiceNow', () => { }); it('throws on missing credentials', async () => { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: undefined, password: undefined, apiToken: undefined } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: undefined, password: undefined, apiToken: undefined } }); const client = new HttpClient(config); await expect(client.servicenow('/api/now/table/change_request')).rejects.toMatchObject({ name: 'PncliError' }); }); @@ -451,7 +451,7 @@ describe('HttpClient — ServiceNow', () => { return new Response('{"result":[]}', { status: 200 }); }); try { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: 'alice', password: 'secret', apiToken: undefined } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: 'alice', password: 'secret', apiToken: undefined } }); const client = new HttpClient(config); await client.servicenow('/api/now/table/change_request'); } finally { @@ -469,7 +469,7 @@ describe('HttpClient — ServiceNow', () => { return new Response('{"result":[]}', { status: 200 }); }); try { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: 'alice', password: undefined, apiToken: 'my-token' } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: 'alice', password: undefined, apiToken: 'my-token' } }); const client = new HttpClient(config); await client.servicenow('/api/now/table/change_request'); } finally { @@ -487,7 +487,7 @@ describe('HttpClient — ServiceNow', () => { return new Response('{"result":[]}', { status: 200 }); }); try { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: 'alice', password: 'pw', apiToken: 'tok' } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: 'alice', password: 'pw', apiToken: 'tok' } }); const client = new HttpClient(config); await client.servicenow('/api/now/table/change_request'); } finally { @@ -499,7 +499,7 @@ describe('HttpClient — ServiceNow', () => { }); it('throws PncliError with status 0 on dry-run', async () => { - const config = baseConfig({ servicenow: { baseUrl: 'https://sn.example.com', username: 'u', password: 'p', apiToken: undefined } }); + const config = baseConfig({ servicenow: { baseUrl: 'https://sn.imagile.dev', username: 'u', password: 'p', apiToken: undefined } }); const client = new HttpClient(config, true); await expect(client.servicenow('/api/now/table/change_request')).rejects.toMatchObject({ status: 0, message: 'dry-run' }); }); @@ -514,7 +514,7 @@ describe('HttpClient — jiraUpload', () => { it('throws on missing jira apiToken', async () => { const config = baseConfig(); - config.jira = { baseUrl: 'https://jira.example.com', apiToken: undefined, customFields: [] }; + config.jira = { baseUrl: 'https://jira.imagile.dev', apiToken: undefined, customFields: [] }; const client = new HttpClient(config); const form = new FormData(); await expect(client.jiraUpload('/rest/api/2/issue/TEST-1/attachments', form)).rejects.toMatchObject({ name: 'PncliError' }); @@ -557,7 +557,7 @@ describe('HttpClient — confluenceUpload', () => { it('throws on missing confluence apiToken', async () => { const config = baseConfig(); - config.confluence = { baseUrl: 'https://conf.example.com', apiToken: undefined, apiTokenExplicit: false }; + config.confluence = { baseUrl: 'https://conf.imagile.dev', apiToken: undefined, apiTokenExplicit: false }; const client = new HttpClient(config); const form = new FormData(); await expect(client.confluenceUpload('/rest/api/content/10001/child/attachment', form)).rejects.toMatchObject({ name: 'PncliError' }); @@ -605,7 +605,7 @@ describe('HttpClient — Contrast', () => { return new Response('{}', { status: 200 }); }); try { - const config = baseConfig({ contrast: { baseUrl: 'https://app.contrastsecurity.com', orgUuid: 'org-123', apiKey: 'my-api-key', serviceKey: 'my-svc-key', username: 'user@example.com' } }); + const config = baseConfig({ contrast: { baseUrl: 'https://app.contrastsecurity.com', orgUuid: 'org-123', apiKey: 'my-api-key', serviceKey: 'my-svc-key', username: 'user@imagile.dev' } }); const client = new HttpClient(config); await client.contrast('/Contrast/api/ng/org-123/applications'); } finally { @@ -614,7 +614,7 @@ describe('HttpClient — Contrast', () => { const authorization = capturedHeaders[0]?.['authorization'] ?? ''; const apiKey = capturedHeaders[0]?.['api-key'] ?? ''; const decoded = Buffer.from(authorization, 'base64').toString(); - expect(decoded).toBe('user@example.com:my-svc-key'); + expect(decoded).toBe('user@imagile.dev:my-svc-key'); expect(apiKey).toBe('my-api-key'); }); @@ -633,7 +633,7 @@ describe('HttpClient — openshiftText Accept header', () => { return new Response('log line 1\nlog line 2\n', { status: 200 }); }); try { - const config = baseConfig({ openshift: { baseUrl: 'https://api.cluster.example.com:6443', token: 'oc-tok' } }); + const config = baseConfig({ openshift: { baseUrl: 'https://api.cluster.imagile.dev:6443', token: 'oc-tok' } }); const client = new HttpClient(config); await client.openshiftText('/api/v1/namespaces/default/pods/my-pod/log', { lines: 10 }); } finally { diff --git a/src/services/ado/client/build.test.ts b/src/services/ado/client/build.test.ts index eaf162c..d5d00b6 100644 --- a/src/services/ado/client/build.test.ts +++ b/src/services/ado/client/build.test.ts @@ -6,15 +6,15 @@ import type { ResolvedConfig } from '../../../types/config.js'; function makeConfig(): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: undefined, token: undefined }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'my-pat', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'my-pat', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, diff --git a/src/services/ado/client/work.test.ts b/src/services/ado/client/work.test.ts index 6a4d2a2..3005fbe 100644 --- a/src/services/ado/client/work.test.ts +++ b/src/services/ado/client/work.test.ts @@ -9,15 +9,15 @@ import type { ResolvedConfig } from '../../../types/config.js'; function makeConfig(): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: undefined, token: undefined }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'my-pat', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'my-pat', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, @@ -34,7 +34,7 @@ function makeWorkItem(tags: string) { id: 42, fields: { 'System.Tags': tags }, _links: {}, - url: 'https://ado.example.com/myorg/_apis/wit/workitems/42' + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/42' }; } @@ -213,7 +213,7 @@ describe('AdoWorkClient — listAttachments', () => { relations: [ { rel: 'AttachedFile', - url: 'https://ado.example.com/myorg/_apis/wit/attachments/abc-123', + url: 'https://ado.imagile.dev/myorg/_apis/wit/attachments/abc-123', attributes: { name: 'screenshot.png', comment: 'Bug screenshot', @@ -224,11 +224,11 @@ describe('AdoWorkClient — listAttachments', () => { }, { rel: 'System.LinkTypes.Related', - url: 'https://ado.example.com/myorg/_apis/wit/workitems/99', + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/99', attributes: {} } ], - url: 'https://ado.example.com/myorg/_apis/wit/workitems/42' + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/42' }; vi.stubGlobal('fetch', async () => @@ -242,7 +242,7 @@ describe('AdoWorkClient — listAttachments', () => { expect(attachments).toHaveLength(1); expect(attachments[0].id).toBe('abc-123'); expect(attachments[0].name).toBe('screenshot.png'); - expect(attachments[0].url).toBe('https://ado.example.com/myorg/_apis/wit/attachments/abc-123'); + expect(attachments[0].url).toBe('https://ado.imagile.dev/myorg/_apis/wit/attachments/abc-123'); expect(attachments[0].comment).toBe('Bug screenshot'); expect(attachments[0].resourceSize).toBe(4096); }); @@ -254,11 +254,11 @@ describe('AdoWorkClient — listAttachments', () => { relations: [ { rel: 'System.LinkTypes.Related', - url: 'https://ado.example.com/myorg/_apis/wit/workitems/99', + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/99', attributes: {} } ], - url: 'https://ado.example.com/myorg/_apis/wit/workitems/42' + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/42' }; vi.stubGlobal('fetch', async () => @@ -276,7 +276,7 @@ describe('AdoWorkClient — listAttachments', () => { const workItemNoRelations = { id: 42, fields: {}, - url: 'https://ado.example.com/myorg/_apis/wit/workitems/42' + url: 'https://ado.imagile.dev/myorg/_apis/wit/workitems/42' }; vi.stubGlobal('fetch', async () => @@ -302,7 +302,7 @@ describe('AdoWorkClient — listAreas', () => { structureType: 'area', hasChildren: true, path: '\\MyProject\\Area', - url: 'https://ado.example.com/myorg/MyProject/_apis/wit/classificationnodes/areas', + url: 'https://ado.imagile.dev/myorg/MyProject/_apis/wit/classificationnodes/areas', children: [ { id: 2, @@ -311,7 +311,7 @@ describe('AdoWorkClient — listAreas', () => { structureType: 'area', hasChildren: false, path: '\\MyProject\\Area\\TeamA', - url: 'https://ado.example.com/myorg/MyProject/_apis/wit/classificationnodes/areas/TeamA' + url: 'https://ado.imagile.dev/myorg/MyProject/_apis/wit/classificationnodes/areas/TeamA' } ] }; @@ -361,7 +361,7 @@ describe('AdoWorkClient — listIterations', () => { structureType: 'iteration', hasChildren: true, path: '\\MyProject\\Iteration', - url: 'https://ado.example.com/myorg/MyProject/_apis/wit/classificationnodes/iterations', + url: 'https://ado.imagile.dev/myorg/MyProject/_apis/wit/classificationnodes/iterations', children: [ { id: 11, @@ -370,7 +370,7 @@ describe('AdoWorkClient — listIterations', () => { structureType: 'iteration', hasChildren: false, path: '\\MyProject\\Iteration\\Sprint 1', - url: 'https://ado.example.com/myorg/MyProject/_apis/wit/classificationnodes/iterations/Sprint%201', + url: 'https://ado.imagile.dev/myorg/MyProject/_apis/wit/classificationnodes/iterations/Sprint%201', attributes: { startDate: '2024-01-01T00:00:00Z', finishDate: '2024-01-14T00:00:00Z' @@ -426,7 +426,7 @@ describe('AdoWorkClient — downloadAttachment', () => { const http = new HttpClient(makeConfig()); const client = new AdoWorkClient(http); - const buffer = await client.downloadAttachment('https://ado.example.com/myorg/_apis/wit/attachments/abc-123'); + const buffer = await client.downloadAttachment('https://ado.imagile.dev/myorg/_apis/wit/attachments/abc-123'); expect(buffer).toBeInstanceOf(Buffer); expect(buffer.length).toBe(8); @@ -444,7 +444,7 @@ describe('AdoWorkClient — uploadAttachment', () => { const capturedRequests: Array<{ url: string; method: string; body: unknown; contentType?: string }> = []; const attachmentResponse = { id: 'att-guid-123', - url: 'https://ado.example.com/myorg/_apis/wit/attachments/att-guid-123', + url: 'https://ado.imagile.dev/myorg/_apis/wit/attachments/att-guid-123', name: 'pncli-test-report.txt' }; @@ -469,7 +469,7 @@ describe('AdoWorkClient — uploadAttachment', () => { fs.unlinkSync(tmpFile); expect(result.id).toBe('att-guid-123'); - expect(result.url).toBe('https://ado.example.com/myorg/_apis/wit/attachments/att-guid-123'); + expect(result.url).toBe('https://ado.imagile.dev/myorg/_apis/wit/attachments/att-guid-123'); // First request: upload to attachments endpoint expect(capturedRequests[0].url).toContain('_apis/wit/attachments'); @@ -497,7 +497,7 @@ describe('AdoWorkClient — uploadAttachment', () => { if (String(url).includes('attachments?fileName')) { return new Response(JSON.stringify({ id: 'att-guid-456', - url: 'https://ado.example.com/myorg/_apis/wit/attachments/att-guid-456', + url: 'https://ado.imagile.dev/myorg/_apis/wit/attachments/att-guid-456', name: 'pncli-test-notes.txt' }), { status: 200 }); } diff --git a/src/services/ado/helpers.test.ts b/src/services/ado/helpers.test.ts index 19fa735..4933a0c 100644 --- a/src/services/ado/helpers.test.ts +++ b/src/services/ado/helpers.test.ts @@ -84,9 +84,9 @@ describe('buildFieldPatch', () => { describe('splitWorkFieldsDictionary', () => { it('routes built-in work item fields regardless of casing', () => { const { builtin, custom } = splitWorkFieldsDictionary({ - Title: 'Login broken', Description: 'details', Priority: 2, AssignedTo: 'bob@example.com' + Title: 'Login broken', Description: 'details', Priority: 2, AssignedTo: 'bob@imagile.dev' }); - expect(builtin).toEqual({ title: 'Login broken', description: 'details', priority: 2, assignee: 'bob@example.com' }); + expect(builtin).toEqual({ title: 'Login broken', description: 'details', priority: 2, assignee: 'bob@imagile.dev' }); expect(custom).toEqual({}); }); diff --git a/src/services/bitbucket/client.test.ts b/src/services/bitbucket/client.test.ts index 1309c9c..588e723 100644 --- a/src/services/bitbucket/client.test.ts +++ b/src/services/bitbucket/client.test.ts @@ -6,15 +6,15 @@ import type { ResolvedConfig } from '../../types/config.js'; function makeConfig(): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: 'https://api.github.com', token: 'ghtok' }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, diff --git a/src/services/config/commands.ts b/src/services/config/commands.ts index 7d67568..5e69912 100644 --- a/src/services/config/commands.ts +++ b/src/services/config/commands.ts @@ -657,7 +657,7 @@ async function initGlobalConfig(start: number): Promise { process.stderr.write('\n── Jira ──────────────────────────────────────────\n'); const jiraBaseUrl = await input({ - message: 'Jira base URL (e.g. jira.your-company.com):', + message: 'Jira base URL (e.g. jira.imagile.dev):', default: '' }); @@ -667,7 +667,7 @@ async function initGlobalConfig(start: number): Promise { process.stderr.write('\n── Bitbucket ─────────────────────────────────────\n'); const bitbucketBaseUrl = await input({ - message: 'Bitbucket Server base URL (e.g. bitbucket.your-company.com):', + message: 'Bitbucket Server base URL (e.g. bitbucket.imagile.dev):', default: '' }); @@ -716,7 +716,7 @@ async function initGlobalConfig(start: number): Promise { process.stderr.write('\n── Confluence ────────────────────────────────────\n'); const confluenceBaseUrl = await input({ - message: 'Confluence base URL (e.g. confluence.your-company.com):', + message: 'Confluence base URL (e.g. confluence.imagile.dev):', default: '' }); @@ -738,7 +738,7 @@ async function initGlobalConfig(start: number): Promise { if (useArtifactory) { artifactoryBaseUrl = await input({ - message: 'Artifactory base URL (e.g. artifactory.company.com):', + message: 'Artifactory base URL (e.g. artifactory.imagile.dev):', default: '' }); @@ -775,7 +775,7 @@ async function initGlobalConfig(start: number): Promise { if (useSonar) { sonarBaseUrl = await input({ - message: 'SonarQube Server base URL (e.g. sonar.your-company.com):', + message: 'SonarQube Server base URL (e.g. sonar.imagile.dev):', default: '' }); @@ -811,7 +811,7 @@ async function initGlobalConfig(start: number): Promise { } } else { sdeBaseUrl = await input({ - message: 'SDElements hostname\n Cloud-hosted: your-org.sdelements.com\n On-premise: sde.your-company.com\n Host: ', + message: 'SDElements hostname\n Cloud-hosted: imagile.sdelements.com\n On-premise: sde.imagile.dev\n Host: ', default: '' }); @@ -837,7 +837,7 @@ async function initGlobalConfig(start: number): Promise { if (useAdo) { adoBaseUrl = await input({ - message: 'Azure DevOps Server base URL (e.g. tfs.company.com or devops.company.com/tfs):', + message: 'Azure DevOps Server base URL (e.g. tfs.imagile.dev or devops.imagile.dev/tfs):', default: '' }); @@ -918,7 +918,7 @@ async function initGlobalConfig(start: number): Promise { if (useJenkins) { jenkinsBaseUrl = await input({ - message: 'Jenkins base URL (e.g. jenkins.your-company.com):', + message: 'Jenkins base URL (e.g. jenkins.imagile.dev):', default: '' }); @@ -947,7 +947,7 @@ async function initGlobalConfig(start: number): Promise { if (useUdeploy) { udeployBaseUrl = await input({ - message: 'UDeploy base URL (e.g. ucd.company.com:8443):', + message: 'UDeploy base URL (e.g. ucd.imagile.dev:8443):', default: '' }); @@ -1019,7 +1019,7 @@ async function initGlobalConfig(start: number): Promise { }); checkmarxTenantName = await input({ - message: 'Checkmarx One tenant name (IAM realm, e.g. mycompany):', + message: 'Checkmarx One tenant name (IAM realm, e.g. imagile):', default: '' }); @@ -1075,7 +1075,7 @@ async function initGlobalConfig(start: number): Promise { if (useServiceNow) { servicenowBaseUrl = await input({ - message: 'ServiceNow instance URL (e.g. mycompany.service-now.com):', + message: 'ServiceNow instance URL (e.g. imagile.service-now.com):', default: '' }); @@ -1138,7 +1138,7 @@ async function initGlobalConfig(start: number): Promise { process.stderr.write(' User Token credentials are found in your IQ Server profile under User Token.\n'); sonatypeIqBaseUrl = await input({ - message: 'Sonatype IQ Server base URL (e.g. iq.your-company.com):', + message: 'Sonatype IQ Server base URL (e.g. iq.imagile.dev):', default: '' }); @@ -1248,7 +1248,7 @@ async function initGlobalConfig(start: number): Promise { process.stderr.write(' Service account token: cat /var/run/secrets/kubernetes.io/serviceaccount/token\n'); openShiftBaseUrl = await input({ - message: 'OpenShift API server URL (e.g. https://api.cluster.example.com:6443):', + message: 'OpenShift API server URL (e.g. https://api.cluster.imagile.dev:6443):', default: '' }); diff --git a/src/services/deps/clients/artifactory.ts b/src/services/deps/clients/artifactory.ts index bac5887..1275f73 100644 --- a/src/services/deps/clients/artifactory.ts +++ b/src/services/deps/clients/artifactory.ts @@ -74,7 +74,7 @@ export function requireArtifactory(config: ArtifactoryConfig, command: string): if (!config.baseUrl && !config.token) { throw new PncliError( `${command} requires Artifactory. Add the following to ~/.pncli/config.json:\n` + - ` "artifactory": { "baseUrl": "https://artifactory.company.com", "token": "your-token" }\n` + + ` "artifactory": { "baseUrl": "https://artifactory.imagile.dev", "token": "your-token" }\n` + `Or set PNCLI_ARTIFACTORY_BASE_URL and PNCLI_ARTIFACTORY_TOKEN environment variables.`, 503 ); diff --git a/src/services/deps/clients/sonatype.test.ts b/src/services/deps/clients/sonatype.test.ts index dc67dc6..500f42d 100644 --- a/src/services/deps/clients/sonatype.test.ts +++ b/src/services/deps/clients/sonatype.test.ts @@ -90,7 +90,7 @@ describe('CVE alias extraction', () => { coordinates: 'pkg:npm/foo@1.0.0', vulnerabilities: [{ id: 'sonatype-1', displayName: 'CVE-2021-1234', title: '', description: '', - cvssScore: 7.5, reference: 'https://example.com' + cvssScore: 7.5, reference: 'https://imagile.dev' }] }]) ); @@ -104,7 +104,7 @@ describe('CVE alias extraction', () => { coordinates: 'pkg:npm/foo@1.0.0', vulnerabilities: [{ id: 'sonatype-1', displayName: 'Not a CVE ref', title: 'CVE-2021-5678 - RCE vuln', - description: '', cvssScore: 8.0, reference: 'https://example.com' + description: '', cvssScore: 8.0, reference: 'https://imagile.dev' }] }]) ); @@ -118,7 +118,7 @@ describe('CVE alias extraction', () => { coordinates: 'pkg:npm/foo@1.0.0', vulnerabilities: [{ id: 'sonatype-1', displayName: 'CVE-2021-0001', title: 'CVE-2021-0002 issue', - description: 'see CVE-2021-0003', cvssScore: 7.0, reference: 'https://example.com' + description: 'see CVE-2021-0003', cvssScore: 7.0, reference: 'https://imagile.dev' }] }]) ); @@ -135,7 +135,7 @@ describe('CVE alias extraction', () => { coordinates: 'pkg:npm/foo@1.0.0', vulnerabilities: [{ id: 'sonatype-1', displayName: 'CVE-2021-0001', title: 'CVE-2021-0001 repeated', - description: '', cvssScore: 7.0, reference: 'https://example.com' + description: '', cvssScore: 7.0, reference: 'https://imagile.dev' }] }]) ); @@ -169,7 +169,7 @@ describe('report alignment', () => { coordinates: 'pkg:npm/bar@2.0.0', vulnerabilities: [{ id: 'sonatype-1', displayName: 'CVE-2021-9999', title: '', description: '', - cvssScore: 9.5, reference: 'https://example.com' + cvssScore: 9.5, reference: 'https://imagile.dev' }] }, { coordinates: 'pkg:npm/foo@1.0.0', vulnerabilities: [] } @@ -188,7 +188,7 @@ describe('report alignment', () => { coordinates: 'pkg:npm/unknown@9.9.9', vulnerabilities: [{ id: 'sonatype-1', displayName: 'CVE-2021-0000', title: '', description: '', - cvssScore: 8.0, reference: 'https://example.com' + cvssScore: 8.0, reference: 'https://imagile.dev' }] } ]) diff --git a/src/services/deps/clients/sonatypeiq.test.ts b/src/services/deps/clients/sonatypeiq.test.ts index 6289d01..25a4326 100644 --- a/src/services/deps/clients/sonatypeiq.test.ts +++ b/src/services/deps/clients/sonatypeiq.test.ts @@ -10,7 +10,7 @@ function pkg(name: string, version = '1.0.0', ecosystem: Package['ecosystem'] = function makeConfig(overrides?: Partial): ResolvedConfig { return { sonatypeiq: { - baseUrl: 'https://iq.example.com', + baseUrl: 'https://iq.imagile.dev', userCode: 'mycode', passcode: 'mypass', ...overrides @@ -337,21 +337,21 @@ describe('HTTP error handling', () => { describe('checkSonatypeIqConnectivity', () => { it('reports reachable and authenticated on 200', async () => { vi.stubGlobal('fetch', async () => new Response('{"applications":[]}', { status: 200 })); - const result = await checkSonatypeIqConnectivity('https://iq.example.com', 'user', 'pass'); + const result = await checkSonatypeIqConnectivity('https://iq.imagile.dev', 'user', 'pass'); expect(result.reachable).toBe(true); expect(result.authenticated).toBe(true); }); it('reports reachable but not authenticated on 401', async () => { vi.stubGlobal('fetch', async () => new Response('', { status: 401 })); - const result = await checkSonatypeIqConnectivity('https://iq.example.com', 'user', 'badpass'); + const result = await checkSonatypeIqConnectivity('https://iq.imagile.dev', 'user', 'badpass'); expect(result.reachable).toBe(true); expect(result.authenticated).toBe(false); }); it('reports unreachable on network error', async () => { vi.stubGlobal('fetch', async () => { throw new Error('ECONNREFUSED'); }); - const result = await checkSonatypeIqConnectivity('https://iq.example.com', 'user', 'pass'); + const result = await checkSonatypeIqConnectivity('https://iq.imagile.dev', 'user', 'pass'); expect(result.reachable).toBe(false); expect(result.error).toMatch('ECONNREFUSED'); }); diff --git a/src/services/github/client.test.ts b/src/services/github/client.test.ts index 40b311c..90e8025 100644 --- a/src/services/github/client.test.ts +++ b/src/services/github/client.test.ts @@ -6,15 +6,15 @@ import type { ResolvedConfig } from '../../types/config.js'; function makeConfig(): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: 'https://api.github.com', token: 'ghtok' }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, diff --git a/src/services/jira/client.test.ts b/src/services/jira/client.test.ts index 262f154..4a7ddc4 100644 --- a/src/services/jira/client.test.ts +++ b/src/services/jira/client.test.ts @@ -6,15 +6,15 @@ import type { ResolvedConfig } from '../../types/config.js'; function makeConfig(): ResolvedConfig { return { user: { email: undefined, userId: undefined }, - jira: { baseUrl: 'https://jira.example.com', apiToken: 'tok', customFields: [] }, - bitbucket: { baseUrl: 'https://bb.example.com', pat: 'tok' }, + jira: { baseUrl: 'https://jira.imagile.dev', apiToken: 'tok', customFields: [] }, + bitbucket: { baseUrl: 'https://bb.imagile.dev', pat: 'tok' }, github: { baseUrl: undefined, token: undefined }, - confluence: { baseUrl: 'https://conf.example.com', apiToken: 'tok', apiTokenExplicit: true }, + confluence: { baseUrl: 'https://conf.imagile.dev', apiToken: 'tok', apiTokenExplicit: true }, artifactory: {}, - sonar: { baseUrl: 'https://sonar.example.com', token: 'tok' }, - sde: { baseUrl: 'https://sde.example.com', token: 'tok' }, - ado: { baseUrl: 'https://ado.example.com', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, - jenkins: { baseUrl: 'https://jenkins.example.com', username: 'user', apiToken: 'tok' }, + sonar: { baseUrl: 'https://sonar.imagile.dev', token: 'tok' }, + sde: { baseUrl: 'https://sde.imagile.dev', token: 'tok' }, + ado: { baseUrl: 'https://ado.imagile.dev', pat: 'tok', fieldAliases: {}, discoveredFields: [], discoveredTypes: [] }, + jenkins: { baseUrl: 'https://jenkins.imagile.dev', username: 'user', apiToken: 'tok' }, udeploy: { baseUrl: undefined, pat: undefined, username: undefined, password: undefined }, checkmarx: { baseUrl: undefined, tenantName: undefined, apiKey: undefined, clientId: undefined, clientSecret: undefined }, servicenow: { baseUrl: undefined, username: undefined, password: undefined, apiToken: undefined }, @@ -112,7 +112,7 @@ describe('JiraClient — listAttachments', () => { created: '2024-01-01T00:00:00.000Z', size: 4096, mimeType: 'image/png', - content: 'https://jira.example.com/secure/attachment/10001/screenshot.png' + content: 'https://jira.imagile.dev/secure/attachment/10001/screenshot.png' } ]; @@ -336,7 +336,7 @@ describe('JiraClient — downloadAttachment', () => { const http = new HttpClient(makeConfig()); const client = new JiraClient(http); - const buffer = await client.downloadAttachment('https://jira.example.com/secure/attachment/10001/file.jpg'); + const buffer = await client.downloadAttachment('https://jira.imagile.dev/secure/attachment/10001/file.jpg'); expect(buffer).toBeInstanceOf(Buffer); expect(buffer.length).toBe(4); diff --git a/src/services/skills/commands.test.ts b/src/services/skills/commands.test.ts index 8cbcb6c..76d60b7 100644 --- a/src/services/skills/commands.test.ts +++ b/src/services/skills/commands.test.ts @@ -15,8 +15,8 @@ afterEach(() => { describe('injectTokenIntoUrl', () => { it('injects token into a Bitbucket URL using x-token-auth scheme', () => { - const result = injectTokenIntoUrl('https://bitbucket.example.com/scm/proj/repo.git', 'mytoken123'); - expect(result).toBe('https://x-token-auth:mytoken123@bitbucket.example.com/scm/proj/repo.git'); + const result = injectTokenIntoUrl('https://bitbucket.imagile.dev/scm/proj/repo.git', 'mytoken123'); + expect(result).toBe('https://x-token-auth:mytoken123@bitbucket.imagile.dev/scm/proj/repo.git'); }); it('injects token into a GitHub URL using x-access-token scheme', () => { @@ -25,21 +25,21 @@ describe('injectTokenIntoUrl', () => { }); it('URL-encodes special characters in the token', () => { - const result = injectTokenIntoUrl('https://bitbucket.example.com/scm/proj/repo.git', 'tok@en/sp ec'); + const result = injectTokenIntoUrl('https://bitbucket.imagile.dev/scm/proj/repo.git', 'tok@en/sp ec'); expect(result).toContain('x-token-auth:'); - expect(result).toContain('@bitbucket.example.com'); + expect(result).toContain('@bitbucket.imagile.dev'); // token with special chars should be encoded; URL.password returns percent-encoded form const parsed = new URL(result); expect(decodeURIComponent(parsed.password)).toBe('tok@en/sp ec'); }); it('preserves the path and query string', () => { - const result = injectTokenIntoUrl('https://bitbucket.example.com/scm/PROJ/my-repo.git', 'tok'); + const result = injectTokenIntoUrl('https://bitbucket.imagile.dev/scm/PROJ/my-repo.git', 'tok'); expect(result).toContain('/scm/PROJ/my-repo.git'); }); it('throws on a non-http URL', () => { - expect(() => injectTokenIntoUrl('git@bitbucket.example.com:proj/repo.git', 'tok')).toThrow(); + expect(() => injectTokenIntoUrl('git@bitbucket.imagile.dev:proj/repo.git', 'tok')).toThrow(); }); }); @@ -51,7 +51,7 @@ describe('repoNameFromUrl', () => { }); it('extracts repo name from a Bitbucket URL', () => { - expect(repoNameFromUrl('https://bitbucket.example.com/scm/proj/repo.git')).toBe('repo'); + expect(repoNameFromUrl('https://bitbucket.imagile.dev/scm/proj/repo.git')).toBe('repo'); }); it('handles URLs without .git suffix', () => { @@ -273,7 +273,7 @@ describe('getAllMarketplaces', () => { it('disambiguates a legacy marketplace whose derived name collides with an existing entry', () => { const config: GlobalConfig = { - marketplace: { repoUrl: 'https://bitbucket.example.com/scm/other/skills.git', localPath: '/home/user/.agents/marketplaces/skills' }, + marketplace: { repoUrl: 'https://bitbucket.imagile.dev/scm/other/skills.git', localPath: '/home/user/.agents/marketplaces/skills' }, marketplaces: [ { name: 'skills', repoUrl: 'https://github.com/org/skills.git', localPath: '/home/user/.agents/marketplaces/skills-gh' }, ], @@ -282,7 +282,7 @@ describe('getAllMarketplaces', () => { expect(result).toHaveLength(2); expect(result[0].name).toBe('skills'); expect(result[1].name).toBe('skills-2'); - expect(result[1].repoUrl).toBe('https://bitbucket.example.com/scm/other/skills.git'); + expect(result[1].repoUrl).toBe('https://bitbucket.imagile.dev/scm/other/skills.git'); }); });