From 36dca17e0a178c53558b469ddc5322151b7f52c1 Mon Sep 17 00:00:00 2001 From: Sunny Kolattukudy Date: Tue, 4 Aug 2026 17:56:17 -0400 Subject: [PATCH 1/2] chore: standardize placeholder hostnames on imagile.dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo used five competing conventions for placeholder hostnames (example.com, company.com, mycompany, your-company, myteam). Three of those are real domains registered to third parties, so a user who copy-pasted a documented baseUrl would send auth headers to someone else's host. - Self-hosted placeholders now use .imagile.dev, which has no wildcard DNS: a copy-pasted config fails at DNS resolution before any credential leaves the machine. .dev is HSTS-preloaded as a second layer. - Vendor-hosted SaaS keeps the vendor domain with imagile as the tenant (imagile.service-now.com, imagile.sdelements.com). - Checkmarx IAM realm placeholder mycompany -> imagile. - src/lib/git-context.test.ts keeps other.example.com; those tests assert behavior against a foreign host, so the domain must stay distinct. - Email placeholders keep you@example.com (RFC 2606) — this rule covers service hostnames, not mailboxes. - Documents the convention in CLAUDE.md, including the standing constraint never to add wildcard DNS to imagile.dev. - Remaps the 150 CHANGELOG.md commit links onto current SHAs. Closes #294 Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 300 +++++++++---------- CLAUDE.md | 22 ++ infra/README.md | 2 +- pncli-scaffold-prompt.md | 6 +- skills/pncli/ado.md | 6 +- skills/pncli/artifactory.md | 6 +- skills/pncli/bitbucket.md | 6 +- skills/pncli/checkmarx.md | 6 +- skills/pncli/confluence.md | 6 +- skills/pncli/contrast.md | 2 +- skills/pncli/jenkins.md | 10 +- skills/pncli/jira.md | 6 +- skills/pncli/marketplace.md | 2 +- skills/pncli/openshift.md | 8 +- skills/pncli/sde.md | 6 +- skills/pncli/servicenow.md | 6 +- skills/pncli/sonarqube.md | 6 +- skills/pncli/sonatypeiq.md | 6 +- skills/pncli/udeploy.md | 6 +- src/lib/checkmarxFetch.test.ts | 6 +- src/lib/config.test.ts | 58 ++-- src/lib/errors.test.ts | 2 +- src/lib/git-context.test.ts | 72 ++--- src/lib/git-context.ts | 6 +- src/lib/http.test.ts | 46 +-- src/services/ado/client/build.test.ts | 14 +- src/services/ado/client/work.test.ts | 46 +-- src/services/ado/helpers.test.ts | 4 +- src/services/bitbucket/client.test.ts | 14 +- src/services/config/commands.ts | 26 +- src/services/deps/clients/artifactory.ts | 2 +- src/services/deps/clients/sonatype.test.ts | 12 +- src/services/deps/clients/sonatypeiq.test.ts | 8 +- src/services/github/client.test.ts | 14 +- src/services/jira/client.test.ts | 18 +- src/services/skills/commands.test.ts | 18 +- 36 files changed, 403 insertions(+), 381 deletions(-) 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/infra/README.md b/infra/README.md index e0fb135..ff3f03e 100644 --- a/infra/README.md +++ b/infra/README.md @@ -119,7 +119,7 @@ az functionapp config appsettings list \ curl -X POST "https://pncli-prod-feedback.azurewebsites.net/api/submit" \ -H "Content-Type: application/json" \ -H "Origin: https://kolatts.github.io" \ - -d '{"kind":"bug","title":"curl smoke test","body":"from curl","email":"you@example.com","hp":""}' + -d '{"kind":"bug","title":"curl smoke test","body":"from curl","email":"you@imagile.dev","hp":""}' # Should return 200 with empty body (honeypot) curl -X POST "https://pncli-prod-feedback.azurewebsites.net/api/submit" \ diff --git a/pncli-scaffold-prompt.md b/pncli-scaffold-prompt.md index 919352d..cd05531 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@imagile.dev", "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..0781cc4 100644 --- a/src/lib/config.test.ts +++ b/src/lib/config.test.ts @@ -9,16 +9,16 @@ 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' }, + user: { email: 'user@imagile.dev', userId: 'user1' }, + 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.user.email).toBe('user@example.com'); + expect(masked.jira.baseUrl).toBe('https://jira.imagile.dev'); + expect(masked.user.email).toBe('user@imagile.dev'); }); 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'); }); }); From 8554c56b2f3a8f61a4ea17d01d36268b15eedca1 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2026 22:01:27 +0000 Subject: [PATCH 2/2] fix: restore example.com for user email placeholders The hostname standardization correctly uses imagile.dev for service baseUrls, but the email exception rule (RFC 2606 example.com for mailbox placeholders) was not applied. Three spots were incorrectly changed: the user.email fixture in config.test.ts, the Jira email field in pncli-scaffold-prompt.md, and the curl smoke test email in infra/README.md. Co-authored-by: Sunny Kolattukudy --- infra/README.md | 2 +- pncli-scaffold-prompt.md | 2 +- src/lib/config.test.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/infra/README.md b/infra/README.md index ff3f03e..e0fb135 100644 --- a/infra/README.md +++ b/infra/README.md @@ -119,7 +119,7 @@ az functionapp config appsettings list \ curl -X POST "https://pncli-prod-feedback.azurewebsites.net/api/submit" \ -H "Content-Type: application/json" \ -H "Origin: https://kolatts.github.io" \ - -d '{"kind":"bug","title":"curl smoke test","body":"from curl","email":"you@imagile.dev","hp":""}' + -d '{"kind":"bug","title":"curl smoke test","body":"from curl","email":"you@example.com","hp":""}' # Should return 200 with empty body (honeypot) curl -X POST "https://pncli-prod-feedback.azurewebsites.net/api/submit" \ diff --git a/pncli-scaffold-prompt.md b/pncli-scaffold-prompt.md index cd05531..f7bbb26 100644 --- a/pncli-scaffold-prompt.md +++ b/pncli-scaffold-prompt.md @@ -234,7 +234,7 @@ Owned by the individual developer. Contains auth credentials and server URLs. NO { "jira": { "baseUrl": "https://your-domain.atlassian.net", - "email": "you@imagile.dev", + "email": "you@example.com", "apiToken": "your-jira-api-token" }, "bitbucket": { diff --git a/src/lib/config.test.ts b/src/lib/config.test.ts index 0781cc4..5907d19 100644 --- a/src/lib/config.test.ts +++ b/src/lib/config.test.ts @@ -9,7 +9,7 @@ vi.mock('child_process', () => ({ execSync: vi.fn() })); function baseConfig(overrides: Partial = {}): ResolvedConfig { return { - user: { email: 'user@imagile.dev', userId: 'user1' }, + user: { email: 'user@example.com', userId: 'user1' }, 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' }, @@ -98,7 +98,7 @@ describe('maskConfig', () => { it('preserves non-secret fields', () => { const masked = maskConfig(baseConfig()) as ResolvedConfig; expect(masked.jira.baseUrl).toBe('https://jira.imagile.dev'); - expect(masked.user.email).toBe('user@imagile.dev'); + expect(masked.user.email).toBe('user@example.com'); }); it('masks udeploy password when present', () => {