@kolatts/pncli 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ envOverriddenSecretPaths,
3
4
  getGlobalConfigPath,
4
5
  loadConfig,
5
6
  loadJsonFile,
@@ -9,9 +10,10 @@ import {
9
10
  setRepoConfigValue,
10
11
  writeGlobalConfig,
11
12
  writeRepoConfig
12
- } from "./chunk-QHJ2HM5J.js";
13
+ } from "./chunk-L6OY2546.js";
13
14
  import "./chunk-HRNOAQDN.js";
14
15
  export {
16
+ envOverriddenSecretPaths,
15
17
  getGlobalConfigPath,
16
18
  loadConfig,
17
19
  loadJsonFile,
@@ -22,4 +24,4 @@ export {
22
24
  writeGlobalConfig,
23
25
  writeRepoConfig
24
26
  };
25
- //# sourceMappingURL=config-Y6IE6GY7.js.map
27
+ //# sourceMappingURL=config-OH2O5E3P.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolatts/pncli",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "The Paperwork Nightmare CLI — structured JSON access to Jira, Bitbucket, GitHub, Confluence, Azure DevOps, SonarQube, Jenkins, and more, built for AI coding agents. Connectivity without MCP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -108,6 +108,7 @@ Each service has its own file in this skill with the config keys and example val
108
108
  | Figma | `figma.md` | Design files, comments, version history |
109
109
  | Alation | `alation.md` | Data catalog metadata (data sources, schemas, tables, columns), search, Document Hubs |
110
110
  | Skills Marketplace | `marketplace.md` | Org plugins and shipped AGENTS.md / CLAUDE.md from git marketplaces |
111
+ | Skills guide | `skills-guide.md` | How skills management fits together: sources, agent hosts, scopes, sync, private-repo auth, OS keychain |
111
112
 
112
113
  ## Installing skills
113
114
 
@@ -115,7 +116,7 @@ The skills bundled with pncli install into a repo with `pncli skills install` (d
115
116
 
116
117
  Installed skills are a copy — after upgrading pncli, re-run `pncli skills install` to refresh them. `skills list` and `skills status` warn when the installed copy came from a different pncli version.
117
118
 
118
- Org-internal plugins come from a git-hosted marketplace: `pncli skills marketplace add <git-clone-url> --all-agents` registers one and installs every plugin into all three agent hosts, and `pncli skills marketplace sync --marketplace all --all-agents` keeps them current. A marketplace can also ship an `instructions/AGENTS.md` and `instructions/CLAUDE.md`; `add` and `sync` merge those into each agent's user-level instructions file (`~/.codex/AGENTS.md`, `~/.copilot/copilot-instructions.md`, `~/.claude/CLAUDE.md`) as a marked block that leaves your own content untouched — `pncli skills marketplace instructions list|install|remove` manages them. `pncli skills status`, `pncli skills locations`, and `pncli doctor` show what is installed and where. The full workflow is in the `marketplace.md` file that ships inside the installed skill, and `pncli skills marketplace --help` summarises it.
119
+ Org-internal plugins come from a git-hosted marketplace: `pncli skills marketplace add <git-clone-url> --all-agents` registers one and installs every plugin into all three agent hosts, and `pncli skills marketplace sync --marketplace all --all-agents` keeps them current. A marketplace can also ship an `instructions/AGENTS.md` and `instructions/CLAUDE.md`; `add` and `sync` merge those into each agent's user-level instructions file (`~/.codex/AGENTS.md`, `~/.copilot/copilot-instructions.md`, `~/.claude/CLAUDE.md`) as a marked block that leaves your own content untouched — `pncli skills marketplace instructions list|install|remove` manages them. `pncli skills status`, `pncli skills locations`, and `pncli doctor` show what is installed and where. The full workflow is in the `marketplace.md` file that ships inside the installed skill, and `pncli skills marketplace --help` summarises it. For the concepts behind all of this — where skills come from, how they stay current, and how private marketplaces authenticate — run `pncli skills guide` (or read `skills-guide.md`).
119
120
 
120
121
  ## Setup walkthrough
121
122
 
@@ -159,10 +160,14 @@ Review results. If any service shows `ok: false`, help troubleshoot the URL or c
159
160
  pncli config show
160
161
  ```
161
162
 
163
+ **Keeping tokens out of plaintext** — `pncli config keychain migrate` moves every secret in `~/.pncli/config.json` into the OS keychain (macOS Keychain, Windows Credential Manager, Secret Service) and leaves `keychain:` references in their place; `--to config` moves them back. `PNCLI_*` environment variables still take precedence.
164
+
162
165
  **Troubleshooting** — when any command fails unexpectedly, run:
163
166
 
164
167
  ```
165
168
  pncli doctor
166
169
  ```
167
170
 
168
- It reports config-file health, credential validity per service, and skill install state (including stale skills) in one JSON envelope, with a `problems` array listing suggested fixes. Add `--offline` to skip the network checks.
171
+ It reports config-file health, credential validity per service, keychain references that do not resolve, git authentication for marketplace hosts (GitHub token scope, expiry, and SSO authorization), and skill install state (including stale skills) in one JSON envelope, with a `problems` array listing suggested fixes. Add `--offline` to skip the network checks.
172
+
173
+ When a clone fails with "repository not found" or an auth error, `pncli git credentials inspect` shows which credential git actually uses for each remote (after `insteadOf` rewriting, or from Git Credential Manager / the `gh` CLI / the OS keychain), and whether it can read the repo; `--scan <dir>` checks every clone under a folder, and `pncli git credentials stored` lists what the credential stores hold. See `github.md`.
@@ -51,3 +51,7 @@ pncli ado work schema --example-only > wi.json
51
51
  pncli ado work create --type Bug --input-file wi.json
52
52
  pncli ado work update --id 123 --input-file wi.json --field Priority=1 # flag wins, and it's reported
53
53
  ```
54
+
55
+ ## Skills marketplaces on this host
56
+
57
+ A skills marketplace repository on this host (see `marketplace.md`) with no `--token` of its own uses `ado.pat` (`PNCLI_ADO_PAT`) for clone and pull, and for `pncli skills git-auth`. The PAT needs the Code (Read) scope.
@@ -38,3 +38,7 @@ pncli bitbucket --project MYPROJ create-repo --name my-new-repo
38
38
  # With a description and explicit project flag
39
39
  pncli bitbucket create-repo --project MYPROJ --name my-new-repo --description "My project"
40
40
  ```
41
+
42
+ ## Skills marketplaces on this host
43
+
44
+ A skills marketplace repository on this host (see `marketplace.md`) with no `--token` of its own uses `bitbucket.pat` (`PNCLI_BITBUCKET_PAT`) for clone and pull, and for `pncli skills git-auth`. Bitbucket Data Center personal access tokens are usually sent with your Bitbucket username: add the marketplace with `--username <you>`, or set it later with `pncli skills marketplace update <name> --username <you>`.
@@ -65,3 +65,40 @@ pncli github resolve-thread --thread-id PRT_kwDOHfWCIM4APCA
65
65
  `list-review-threads` returns the first 100 threads with their resolution status,
66
66
  file path/line, and first 10 comments. If a PR has more than 100 threads, a warning
67
67
  is written to stderr.
68
+
69
+ ## Which token does a clone use? (`pncli git credentials`)
70
+
71
+ Classic-PAT setups usually put the token in a gitconfig rewrite such as
72
+ `url."https://<classic-PAT>@github.com/acme/".insteadOf "https://github.com/acme/"`, while Git Credential
73
+ Manager, the `gh` CLI, or the Windows Credential Manager may hold other tokens for the same host. A repo outside
74
+ every mapping silently clones anonymously and fails as "repository not found"; a mapped token may be valid but
75
+ unable to see a particular repo; a stored token may be shadowed by another helper. These commands work on any
76
+ clone, not just skills marketplaces, and never print a token — only its type and a fingerprint (`ghp_…a1b2`):
77
+
78
+ ```
79
+ pncli git credentials inspect # every remote of the current clone
80
+ pncli git credentials inspect ~/src/tools --remote upstream
81
+ pncli git credentials inspect https://github.com/acme/tools.git
82
+ pncli git credentials inspect --scan ~/src --problems-only # clones that are unmapped or lack access
83
+ pncli git credentials mappings # every insteadOf rewrite and URL-scoped helper, tokens checked
84
+ pncli git credentials stored # what the credential stores hold, and what git actually sends
85
+ pncli git credentials forget --host github.com --username octo # drop a stale stored credential
86
+ ```
87
+
88
+ - **`inspect`** — per remote: the URL as configured, the URL git uses after `insteadOf` rewriting, the mapping
89
+ that applied, and where the credential comes from (`insteadOf`, the `url` itself, a `helper`, or `none`). For a
90
+ helper it names the kind — Git Credential Manager, wincred, osxkeychain, libsecret, store, `gh`, pncli — and
91
+ GCM's backing store (`wincredman`, `dpapi`, `keychain`, `secretservice`, …). Online it runs an authenticated
92
+ `git ls-remote`, and for GitHub reports the account, a classic token missing `repo`, SAML SSO authorization,
93
+ expiry, and whether the token can see **this** repository — each problem with a concrete fix, such as the exact
94
+ `insteadOf` line to add for an unmapped org.
95
+ - **`stored`** — the Windows Credential Manager's `git:` entries (Git Credential Manager and wincred), the plaintext
96
+ `~/.git-credentials` file, and the macOS Keychain's git entries (metadata only), plus what git actually sends per
97
+ host and per stored path. Flags stored tokens that GitHub rejects or that expire soon, several accounts for one
98
+ host, plaintext storage, and **shadowed** entries — a stored credential git never sends because another helper
99
+ (typically `gh auth setup-git`) answers first.
100
+ - **`forget`** — `git credential reject` for one host (and optionally account or path), which every helper
101
+ implements; it reports the fingerprint before and after. A shadowed Windows entry cannot be reached this way —
102
+ `stored` gives the exact `cmdkey /delete:` command instead.
103
+
104
+ `--offline` skips every network check.
@@ -1,6 +1,6 @@
1
1
  # Jira
2
2
 
3
- Enables: `pncli jira get-issue`, `create-issue`, `update-issue`, `search`, `list-boards`, `list-sprints`, `set-sprint`, and more — get, create, and update issues, transitions, comments, attachments, custom fields, and sprints.
3
+ Enables: `pncli jira get-issue`, `create-issue`, `update-issue`, `search`, `list-boards`, `list-sprints`, `set-sprint`, `log-work`, and more — get, create, and update issues, transitions, comments, attachments, custom fields, sprints, and worklogs.
4
4
 
5
5
  ## Required config
6
6
 
@@ -42,6 +42,17 @@ pncli jira set-sprint --key ACME-123 --sprint <sprint-id>
42
42
 
43
43
  `list-sprints` output includes `startDate`/`endDate`/`state`/`goal` for each sprint.
44
44
 
45
+ ## Worklogs
46
+
47
+ ```
48
+ pncli jira log-work --key ACME-123 --time-spent "2h 30m" --comment "Investigated the failing build"
49
+ pncli jira log-work --key ACME-123 --time-spent "1d" --started 2024-01-15T09:00:00.000+0000
50
+ ```
51
+
52
+ `--time-spent` uses Jira's own duration format (`1d`, `2h 30m`, `45m`, ...). `--started` takes
53
+ Jira's datetime format (`yyyy-MM-dd'T'HH:mm:ss.SSSZ`, e.g. `2024-01-15T09:00:00.000+0000`) and
54
+ defaults to now when omitted.
55
+
45
56
  ## Custom fields
46
57
 
47
58
  Register a custom field once so `--field <Name>=value` and `--input-file` can address it by
@@ -60,6 +71,36 @@ mangle nested double quotes inside a single-quoted argument, which silently stor
60
71
  value. `pncli jira fields` prints what's currently registered; `pncli jira fields --discover`
61
72
  fetches field metadata straight from the Jira API instead.
62
73
 
74
+ Registration is only needed to address a field by **friendly name**, or to get automatic
75
+ value shaping from `type`. Both `--field` and `--fields-file` accept an unregistered raw
76
+ Jira field id or name directly (e.g. `--field fixVersions=@versions.json`,
77
+ `{"fixVersions": [...]}` in a `--fields-file` JSON file) — nothing needs to be pre-registered
78
+ just to use a standard field like `fixVersions` or a custom field you already know the
79
+ `customfield_NNNNN` id for. Registration only fails for a key that still has whitespace in
80
+ it and isn't a registered friendly name — that's almost always a typo.
81
+
82
+ Some select-type fields (a "Crew" picker, for example) reject the display text you see in
83
+ Jira's UI and only accept the option's numeric key. Run `pncli jira fields --discover
84
+ --project <key>` to see each field's `allowedValues`; if a field's values are `{id, value}`
85
+ pairs rather than plain strings, register it with `"type":"option-id"` and pass the numeric
86
+ `id`, not the display text. **Sprint** is not a custom field at all — don't try to set it
87
+ via `--field` or `--fields-file`; use `pncli jira set-sprint --key <key> --sprint <id>` after
88
+ the issue exists, with the id from `pncli jira list-sprints`.
89
+
90
+ ### PowerShell-safe JSON values
91
+
92
+ Passing JSON inline in `--field Name={"a":1}` is unreliable in PowerShell — its argument
93
+ parser mangles embedded quotes before pncli ever sees them. Use the `@file` form instead,
94
+ which sidesteps shell quoting entirely:
95
+
96
+ ```powershell
97
+ '{"steps":[{"action":"click"}]}' | Out-File -Encoding utf8 steps.json
98
+ pncli jira create-issue --project ACME --summary "..." --field "Test Steps=@steps.json"
99
+ ```
100
+
101
+ This also applies to `--jql` and any other flag that would otherwise need inline JSON or
102
+ nested quotes on Windows.
103
+
63
104
  ## Large fields via --input-file
64
105
 
65
106
  `create-issue` and `update-issue` accept `--input-file <path>` (`-` for stdin) instead of, or alongside, individual flags — useful for a long description or many custom fields at once. Run `pncli jira schema` to print the JSON Schema plus a runnable example. Any string value in `fields` may be `@path/to/file` to pull that field's content from a file (e.g. a big HTML description) instead of inlining it. Custom fields resolve by friendly name (if registered — see **Custom fields** above) or by raw id (`customfield_10032`) with no registration required. Individual flags (`--summary`, `--description`, `--field`, ...) override matching keys from the file; overridden keys are printed to stderr and included in the output's `meta.overrides`.
@@ -79,3 +120,6 @@ pncli jira create-issue --input-file issue.json --priority Low # --priority wi
79
120
  - `--assignee` on `create-issue`, `update-issue`, and `assign` takes a **username**, as does
80
121
  any `user`-typed custom field passed via `--field`
81
122
  - Custom fields discovered with `pncli jira fields --discover`
123
+ - `create-issue` does not check for duplicates before submitting. If a request times out or
124
+ the response is otherwise ambiguous, run `pncli jira search` for the exact summary before
125
+ retrying — a timeout does not tell you whether the issue was actually created.
@@ -27,7 +27,59 @@ pncli skills marketplace add https://bitbucket.imagile.dev/scm/ai/skills.git --n
27
27
 
28
28
  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.
29
29
 
30
- For a private repo, pass `--token <token>` (a Bitbucket or GitHub access token) — it's stored with that marketplace's entry and injected into the clone/pull URL. For a marketplace hosted on `github.com` (or the host configured as `github.baseUrl`), you can omit `--token` if you already have a working GitHub credential configured (`PNCLI_GITHUB_TOKEN`, `GITHUB_TOKEN`, or `pncli config set github.token`) — `marketplace add` and `marketplace sync` fall back to it automatically. An explicit `--token` on the marketplace always takes priority over that fallback. To rotate a marketplace's own token, re-run `marketplace add <url> --token <new-token>`; a rejected or expired token surfaces as a clear error naming the marketplace rather than raw git output.
30
+ For a private repo, pass `--token <token>` (a Bitbucket or GitHub access token) — it's stored with that marketplace's entry and supplied to git for each clone and pull; it is not left in the clone's `.git/config`. For a marketplace hosted on `github.com` (or the host configured as `github.baseUrl`), you can omit `--token` if you already have a working GitHub credential configured (`PNCLI_GITHUB_TOKEN`, `GITHUB_TOKEN`, or `pncli config set github.token`) — `marketplace add` and `marketplace sync` fall back to it automatically. An explicit `--token` on the marketplace always takes priority over that fallback. To rotate a marketplace's own token, re-run `marketplace add <url> --token <new-token>` (repeat `--keychain` if the old one was stored there, or use `pncli config keychain set marketplaces.<name>.token`); a rejected or expired token surfaces as a clear error naming the marketplace rather than raw git output.
31
+
32
+ Add `--keychain` to store the token in the OS keychain (macOS Keychain, Windows Credential Manager, Secret Service) instead of plaintext config; the marketplace entry then holds a `keychain:marketplaces.<name>.token` reference.
33
+
34
+ ### Providers: GitHub, Bitbucket, Azure DevOps
35
+
36
+ A marketplace can live on any HTTPS git host. pncli detects the provider from your configured service hosts and the URL shape (`/_git/` is Azure DevOps, `/scm/` is Bitbucket Data Center), and uses it to pick a fallback token when the marketplace has none of its own:
37
+
38
+ | Provider | Example clone URL | Fallback token (when no `--token`) |
39
+ |---|---|---|
40
+ | GitHub / GitHub Enterprise | `https://ghe.imagile.dev/ai/skills.git` | `PNCLI_GITHUB_TOKEN` / `GITHUB_TOKEN` / `github.token` (github.com or the host of `github.baseUrl`) |
41
+ | Bitbucket Data Center | `https://bitbucket.imagile.dev/scm/ai/skills.git` | `PNCLI_BITBUCKET_PAT` / `bitbucket.pat` (the host of `bitbucket.baseUrl`) |
42
+ | Azure DevOps Server | `https://ado.imagile.dev/DefaultCollection/Platform/_git/skills` | `PNCLI_ADO_PAT` / `SYSTEM_ACCESSTOKEN` / `ado.pat` (the host of `ado.baseUrl`) |
43
+ | anything else | `https://git.imagile.dev/ai/skills.git` | none; pass `--token` |
44
+
45
+ Each marketplace keeps its own `--token`, so marketplaces on the same host (or on different providers) can use different secrets. Pass `--provider github|bitbucket|ado|git` if detection guesses wrong.
46
+
47
+ The token is sent with a username: `x-access-token` on github.com, `x-token-auth` everywhere else (unchanged from earlier versions; Azure DevOps accepts any username with a PAT). **Bitbucket Data Center personal access tokens are usually sent with your Bitbucket username** — set it per marketplace:
48
+
49
+ ```
50
+ pncli skills marketplace add https://bitbucket.imagile.dev/scm/ai/skills.git --token <token> --username jdoe --all-agents
51
+ pncli skills marketplace update internal-ai --username jdoe # for one you already added
52
+ ```
53
+
54
+ ### Rotate a token or change credentials (`update`)
55
+
56
+ ```
57
+ pncli skills marketplace update internal-ai --token <new-token> [--keychain]
58
+ pncli skills marketplace update internal-ai --username jdoe
59
+ pncli skills marketplace update internal-ai --clear-token # use the provider fallback instead
60
+ pncli skills marketplace update internal-ai --provider bitbucket
61
+ ```
62
+
63
+ `update` changes the stored entry only — no re-clone, no reinstall. A keychain entry the marketplace no longer points at is deleted.
64
+
65
+ ### Let git itself authenticate (`git-auth`)
66
+
67
+ pncli's own clone and pull are covered above, but an agent host that clones a marketplace itself (e.g. Claude Code's `/plugin marketplace add`) runs plain `git`, which has no credential for it. Give it one:
68
+
69
+ ```
70
+ pncli skills git-auth enable # every marketplace that has a credential
71
+ pncli skills git-auth enable --marketplace internal-ai --mode keychain
72
+ pncli skills git-auth status # per marketplace: mode, username, token source, match
73
+ pncli skills git-auth disable [--marketplace internal-ai] [--forget-keychain]
74
+ ```
75
+
76
+ - Entries are **scoped to each marketplace's repository URL** (with and without `.git`), for example `credential.https://bitbucket.imagile.dev/scm/ai/skills.git.helper`. git consults them only for that repository, so every other repo on the same host keeps using your own login, untouched.
77
+ - `--mode helper` (default) writes an empty reset entry, `!pncli skills git-credential --marketplace '<name>'`, then whatever helpers git used for that repo before (the host's `gh auth setup-git` entry, Git Credential Manager, osxkeychain). pncli answers with that marketplace's own credential — the same username and token its clone and pull use — resolved from env → config → keychain, so nothing is copied into gitconfig and rotation needs no re-run. If pncli cannot answer, git falls through to your helpers as before.
78
+ - `--mode keychain` stores the credential in git's own credential store via `git credential approve`, keyed to the repository (a repo-scoped `useHttpPath`). It works where pncli is not on git's `PATH`, but must be re-run after rotating the token; `pncli doctor` detects the stale copy.
79
+ - `--host <host>` writes a whole-host entry instead, answered with the provider token pncli has for that host. Use it deliberately: it puts that token in front of every repo on the host.
80
+ - `disable` restores exactly what `enable` replaced; pncli records it under `gitAuth.scopes` in its global config. `enable` also rewrites any clone whose `origin` still carries an embedded token.
81
+
82
+ `pncli doctor` reports a `gitAuth` entry per marketplace: provider, mode, username, token source, whether git's credential matches pncli's, and clones with embedded tokens. Online, it runs an authenticated `git ls-remote` with exactly that username and token — which catches a wrong Bitbucket username as reliably as an expired token — and, for GitHub, reports the token kind (classic `ghp_` vs fine-grained), a missing `repo` scope, SSO authorization, and expiry within 14 days.
31
83
 
32
84
  If you upgrade pncli from a version that only supported a single marketplace, your existing config is migrated to the multi-marketplace format automatically the first time you run any `marketplace` command — no manual steps required.
33
85
 
@@ -0,0 +1,169 @@
1
+ ---
2
+ title: How skills management works
3
+ description: The mental model behind pncli skills — where skills come from, where they go, how they stay current, and how private marketplaces authenticate.
4
+ ---
5
+
6
+ # How skills management works
7
+
8
+ pncli puts **skills** — folders of instructions an AI coding agent loads on demand — where your agents will find them, and keeps them current. Read this once; after that, `pncli skills --help` and `pncli doctor` cover the day-to-day.
9
+
10
+ Print any section on its own with `pncli skills guide <section>` (for example `pncli skills guide auth`). `pncli skills guide --sections` lists them all.
11
+
12
+ ## The big picture
13
+
14
+ Skills reach your machine from two sources, and both end up in the same place:
15
+
16
+ ```
17
+ pncli (npm package) your org's marketplace repo (git)
18
+ └─ bundled "pncli" skill └─ plugins/<plugin>/skills/<skill>/SKILL.md
19
+ │ │ + instructions/AGENTS.md, CLAUDE.md
20
+ │ pncli skills install │ pncli skills marketplace add | sync
21
+ ▼ ▼
22
+ ┌─────────────────────────────────────────────────────────────────────┐
23
+ │ agent skills directories (.agents/skills, .claude/skills, …) │
24
+ │ each skill carries a provenance record: source, plugin, marketplace │
25
+ └─────────────────────────────────────────────────────────────────────┘
26
+ ▲
27
+ └── Codex, GitHub Copilot, and Claude Code read from here
28
+ ```
29
+
30
+ - The **bundled skill** is pncli's own command reference. It ships inside the npm package, so it changes when pncli does.
31
+ - **Marketplace plugins** are your org's skills, published in a git repository. pncli clones the repo once and pulls it whenever you sync.
32
+ - Every skill pncli installs is stamped with **provenance** — where it came from and which pncli version put it there. That is how `status`, `sync`, and `doctor` can tell your org's skills, pncli's own, and anything you dropped in by hand apart.
33
+
34
+ ## Agent hosts and where skills live
35
+
36
+ Each agent host reads its own directories. `--agent` picks one; `--all-agents` covers every host in one run.
37
+
38
+ | `--agent` | Project scope | User scope | Read by |
39
+ |---|---|---|---|
40
+ | `codex` (default) | `.agents/skills` | `~/.agents/skills` | Codex and GitHub Copilot |
41
+ | `github-copilot` | `.github/skills` | `~/.copilot/skills` | GitHub Copilot |
42
+ | `claude-code` (`--claude`) | `.claude/skills` | `~/.claude/skills` | Claude Code |
43
+
44
+ **Project scope** lives in the repository — commit it and everyone who clones the repo gets the skills. **User scope** lives in your home directory and applies to every repository on the machine.
45
+
46
+ - The bundled skill installs at project scope by default. Add `--scope user` to have it everywhere.
47
+ - Marketplace plugins always install at user scope. They are org-wide, not repo-specific.
48
+
49
+ `pncli skills locations` prints every one of these paths with a count of what's in it.
50
+
51
+ ## The bundled pncli skill
52
+
53
+ ```
54
+ pncli skills install --all-agents # this repo, every agent host
55
+ pncli skills install --all-agents --scope user # every repo on this machine
56
+ ```
57
+
58
+ The bundled skill is versioned with pncli. After `npm update -g @kolatts/pncli`, the copies on disk are one version behind; `pncli doctor` flags them as stale, and re-running `pncli skills install` refreshes them.
59
+
60
+ ## Marketplaces
61
+
62
+ A marketplace is a git repository your org publishes plugins from. The lifecycle is:
63
+
64
+ 1. **Add** — register, clone, and install every plugin:
65
+ `pncli skills marketplace add https://ghe.imagile.dev/ai/skills.git --all-agents`
66
+ 2. **Sync** — pull the latest and refresh what you already have. With no arguments this is non-interactive, which makes it safe for a login script or a scheduled task:
67
+ `pncli skills marketplace sync --all-agents`
68
+ 3. **Browse** — see what's there without installing anything:
69
+ `pncli skills marketplace plugins internal-ai`
70
+ 4. **Pick up something new** — plain `sync` only refreshes plugins you already have. Run `sync --force` for the interactive picker, or name the plugin:
71
+ `pncli skills marketplace sync new-plugin --all-agents`
72
+
73
+ You can register as many marketplaces as you like. Clones live in `~/.agents/marketplaces/`, and `marketplace remove` unregisters one without deleting its clone.
74
+
75
+ **What a marketplace repo looks like:** `.claude-plugin/marketplace.json` (or a `plugins/` directory), with each plugin holding a `skills/` folder of skill directories. That's the same layout Claude Code's own plugin marketplaces use, so one repo serves both.
76
+
77
+ ## Turning plugins on and off
78
+
79
+ ```
80
+ pncli skills marketplace disable some-plugin
81
+ pncli skills marketplace enable some-plugin
82
+ pncli skills marketplace manage # interactive: checkbox list of every plugin
83
+ ```
84
+
85
+ `disable` moves a plugin's skills into a hidden `.pncli-disabled/` folder next to them, so agents stop loading them. Nothing is deleted and nothing needs re-downloading. A disabled plugin stays disabled across syncs, but it still gets refreshed while it sits there.
86
+
87
+ To remove a plugin for good, use `marketplace purge-plugin`. `skills purge-user` clears an agent's whole user-level skills folder.
88
+
89
+ ## Shipped instructions (AGENTS.md / CLAUDE.md)
90
+
91
+ A marketplace can also ship org-wide agent instructions in `instructions/AGENTS.md` and `instructions/CLAUDE.md`. `add` and `sync` merge them into each agent's **user-level** instructions file (`~/.codex/AGENTS.md`, `~/.copilot/copilot-instructions.md`, `~/.claude/CLAUDE.md`).
92
+
93
+ They go in as a marked block. Your own content in that file is never touched, the block is replaced in place on every sync, and `marketplace instructions remove` strips it cleanly. Don't edit inside the markers, because the next sync overwrites them.
94
+
95
+ ## Where did this skill come from?
96
+
97
+ ```
98
+ pncli skills status # every skill → plugin → marketplace → clone URL
99
+ pncli skills status --source untracked # skills pncli did not install
100
+ pncli skills locations # every path, with counts
101
+ ```
102
+
103
+ The counts in `locations` always add up: `marketplaceSkills + bundledSkills + untrackedSkills = totalSkills`.
104
+
105
+ ## Private repos and auth
106
+
107
+ A private marketplace needs a credential in two places, and they're easy to confuse:
108
+
109
+ 1. **pncli's own clone and pull.** Pass `--token` to `marketplace add`, or let pncli fall back to the token it already has for the provider: `github.token` for GitHub and GitHub Enterprise, `bitbucket.pat` for your Bitbucket host, `ado.pat` for your Azure DevOps host. pncli hands the token to git through the environment for each call, so it never shows up on git's command line and is never left in the clone's `.git/config`.
110
+ 2. **Everyone else's git.** An agent host that clones a marketplace itself — Claude Code's `/plugin marketplace add`, for instance — runs plain `git`, and plain git has no idea about pncli's token. `git-auth` fixes that:
111
+
112
+ ```
113
+ pncli skills git-auth enable # every marketplace that has a credential
114
+ pncli skills git-auth status # per marketplace: mode, and whether git sends pncli's token
115
+ ```
116
+
117
+ `git-auth` has two modes:
118
+
119
+ | Mode | How it works | After a token rotation |
120
+ |---|---|---|
121
+ | `helper` (default) | git asks `pncli skills git-credential --marketplace <name>` on each operation | Nothing to do — git always gets pncli's current token |
122
+ | `keychain` | the token is stored in git's own credential store (Git Credential Manager, macOS Keychain, libsecret) | Re-run `git-auth enable --mode keychain`; `doctor` flags the stale copy |
123
+
124
+ Use `helper` unless something runs git without pncli on its `PATH`. Some GUI git clients and containers do that, and for those `keychain` is the right mode.
125
+
126
+ Entries are scoped to each marketplace's own repository URL, so every other repo on the same host keeps your usual login (`gh`, Git Credential Manager, the macOS Keychain), untouched. `git-auth disable` puts your previous setup back exactly. A whole-host entry (`--host`) is available, but only when you ask for it.
127
+
128
+ **Which GitHub token?** A classic personal access token (`ghp_…`) with the `repo` scope works across every repository your account can see, which suits a marketplace. A fine-grained token (`github_pat_…`) also works, but only for the repositories you selected when you created it. If your org uses SAML single sign-on, authorize the token for the org (Settings → Developer settings → Tokens → Configure SSO). `pncli doctor` checks the scope, the SSO authorization, and the expiry date for you.
129
+
130
+ **Several marketplaces, several secrets.** Each marketplace keeps its own `--token` (and `--username`), and every git path — pncli's clone and pull, the git helper, doctor's access check — uses exactly that pair. Rotate one with `pncli skills marketplace update <name> --token <new-token>`.
131
+
132
+ **Bitbucket and Azure DevOps.** Both work like GitHub. Bitbucket Data Center personal access tokens are usually sent with your Bitbucket username, so give the marketplace `--username <you>`. Azure DevOps PATs need the Code (Read) scope and accept any username. `pncli doctor` tries an authenticated `git ls-remote` for each marketplace, so a wrong username shows up the same way an expired token does.
133
+
134
+ ## Keeping credentials in the OS keychain
135
+
136
+ Diagrams of both storage options, and of both git-auth modes, are on the website: https://kolatts.github.io/pncli/credentials/
137
+
138
+ Any secret in `~/.pncli/config.json` can live in your operating system's credential store instead: the macOS Keychain, Windows Credential Manager, or the Secret Service on Linux. The config file then holds only a reference such as `"token": "keychain:github.token"`.
139
+
140
+ ```
141
+ pncli config keychain migrate --dry-run # what would move
142
+ pncli config keychain migrate # config → keychain, every plaintext secret
143
+ pncli config keychain set github.token # store one (prompts; or pipe it with --stdin)
144
+ pncli config keychain status # every reference, and whether it resolves
145
+ pncli config keychain migrate --to config # keychain → config (entries kept)
146
+ pncli config keychain migrate --to config --purge # …and delete the keychain entries
147
+ ```
148
+
149
+ - `PNCLI_*` environment variables still win over everything, so CI is unaffected. Set `PNCLI_KEYCHAIN_BACKEND=none` on a machine that should ignore references altogether.
150
+ - `migrate` reads each secret back before it rewrites your config, and leaves a `config.json.pre-keychain.bak` behind. Delete that file once `pncli config check` passes.
151
+ - `marketplace add --token … --keychain` stores a marketplace token the same way from the start.
152
+ - Lookups cost a little time. On Windows each pncli command that needs a keychain secret starts PowerShell once (typically well under a second); macOS and Linux are faster.
153
+ - The keychain and `git-auth` helper mode work together. Git asks pncli, pncli reads the keychain, and the token never sits in a file anywhere.
154
+
155
+ ## Troubleshooting
156
+
157
+ | Symptom | Try |
158
+ |---|---|
159
+ | The agent doesn't see a skill | `pncli skills status`, then check the host's directory in `pncli skills locations` |
160
+ | "I ran marketplace add but nothing shows up" | `pncli doctor` — it flags marketplaces with nothing installed from them |
161
+ | `sync` fails with "Invalid username or token" | `pncli doctor`: look for an expired token, a missing `repo` scope, or SSO not authorized |
162
+ | Claude Code's `/plugin marketplace add` can't clone | `pncli skills git-auth enable --host ghe.imagile.dev` |
163
+ | The bundled skill is out of date after an upgrade | `pncli skills install` (add `--all-agents` / `--scope user` as before) |
164
+ | A plugin added upstream never arrived | `pncli skills marketplace sync --force`, or name it explicitly |
165
+ | A command says "not configured" but the token is in the keychain | `pncli config keychain status` — the reference may point at a missing entry |
166
+ | Some ordinary clone (not a marketplace) says "repository not found" | `pncli git credentials inspect` in that clone, or `pncli git credentials inspect --scan ~/src --problems-only` |
167
+ | git keeps using the wrong account or an old token | `pncli git credentials stored` — shows shadowed and stale stored credentials, then `pncli git credentials forget` |
168
+
169
+ `pncli doctor` runs every one of these checks at once and prints a fix command next to each problem it finds.