diff --git a/docs/commands.md b/docs/commands.md index c0d5117..6987ca0 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -5,7 +5,7 @@ description: Full command reference for the pdcli command-line interface. -Reference for `pdcli` v0.22.0 (154 commands). Every command also accepts the global flags `--output table|json|yaml|csv`, `--profile`, `--no-color`, `--verbose`, `--no-retry`, `--timeout`, and `--limit`. +Reference for `pdcli` v0.22.0 (154 commands). Every command also accepts the global flags `--output table|json|yaml|csv`, `--jq`, `--fields`, `--resolve-fields`, `--profile`, `--no-color`, `--verbose`, `--no-retry`, `--timeout`, and `--limit`. ## Top-level diff --git a/scripts/gen-commands.mjs b/scripts/gen-commands.mjs index 0f4da79..b5eb1be 100644 --- a/scripts/gen-commands.mjs +++ b/scripts/gen-commands.mjs @@ -20,6 +20,28 @@ export function groupByTopic(manifest) { const nonGlobalFlags = (c) => Object.entries(c.flags || {}).filter(([, f]) => f.helpGroup !== 'GLOBAL') +// The global flags every command inherits (BaseCommand.baseFlags, tagged +// helpGroup:'GLOBAL'). Derived from the manifest so the reference intro can't +// drift from the code — no hand-kept list to forget `--resolve-fields` again. +// `withOptions` renders `--output`'s value enum inline (GitHub-facing style). +const globalFlagTokens = (manifest, { withOptions = false } = {}) => { + const cmd = Object.values(manifest.commands).find((c) => + Object.values(c.flags || {}).some((f) => f.helpGroup === 'GLOBAL'), + ) + return Object.entries(cmd?.flags || {}) + .filter(([, f]) => f.helpGroup === 'GLOBAL') + .map(([name, f]) => { + const opts = withOptions && f.options ? ` ${f.options.join('|')}` : '' + return `\`--${name}${opts}\`` + }) +} + +// Join with an Oxford "and" before the last item: "a, b, and c". +const andList = (items) => + items.length > 1 + ? `${items.slice(0, -1).join(', ')}, and ${items.at(-1)}` + : items.join('') + const argString = (c) => Object.entries(c.args || {}) .map(([name, a]) => (a.required ? ` <${name}>` : ` [${name}]`)) @@ -48,7 +70,7 @@ description: Full command reference for the pdcli command-line interface. -Reference for \`${bin}\` v${manifest.version} (${commands.length} commands). Every command also accepts the global flags \`--output table|json|yaml|csv\`, \`--profile\`, \`--no-color\`, \`--verbose\`, \`--no-retry\`, \`--timeout\`, and \`--limit\`. +Reference for \`${bin}\` v${manifest.version} (${commands.length} commands). Every command also accepts the global flags ${andList(globalFlagTokens(manifest, { withOptions: true }))}. ` for (const topic of Object.keys(byTopic).sort()) { @@ -98,9 +120,8 @@ description: Every ${bin} command, flag, and example — generated from the CLI {/* AUTO-GENERATED from the oclif manifest by scripts/gen-commands.mjs — do not edit by hand. */} All ${commands.length} commands in \`${bin}\` v${manifest.version}. Every command also -accepts the [global flags](/pdcli/reference/config/) \`--output\`, \`--jq\`, -\`--fields\`, \`--profile\`, \`--limit\`, \`--no-color\`, \`--verbose\`, -\`--no-retry\`, and \`--timeout\`. Run \`${bin} --help\` for the live version. +accepts the [global flags](/pdcli/reference/config/) ${andList(globalFlagTokens(manifest))}. +Run \`${bin} --help\` for the live version. ` const topics = Object.keys(byTopic).sort() diff --git a/website/astro.config.mjs b/website/astro.config.mjs index e3b3c69..4f5dca7 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -1,5 +1,6 @@ // @ts-check import { defineConfig } from 'astro/config' +import { unified } from '@astrojs/markdown-remark' import starlight from '@astrojs/starlight' import starlightLlmsTxt from 'starlight-llms-txt' @@ -9,10 +10,20 @@ export default defineConfig({ site: 'https://wavyx.github.io', base: '/pdcli', - // GFM tables in .md/.mdx (the MDX pipeline inherits these classic options, - // unlike a custom `processor`); smartypants off so code examples keep - // literal `--flags` and straight quotes. - markdown: { gfm: true, smartypants: false }, + // GFM tables in .md/.mdx; smartypants OFF so prose keeps literal `--flags`, + // `--`, and straight quotes (Astro's smart punctuation would turn `--` into + // an en/em dash). Astro 6 deprecated the top-level `markdown.gfm` / + // `markdown.smartypants` booleans — configure them on the unified processor + // instead (removed in a future major otherwise). + // + // NOTE: the build still prints ONE `markdown.gfm`/`smartypants` deprecation + // line during `/llms-*.txt` generation. That is NOT from this config: the + // `starlight-llms-txt` plugin renders via the experimental Astro Container, + // which calls `validateConfig(ASTRO_CONFIG_DEFAULTS, …)` (astro/dist/container/ + // index.js), and Astro's own defaults object still carries explicit + // `gfm`/`smartypants` keys — so it trips its own deprecation check. It is + // unfixable from here; it clears when Astro drops those keys from the defaults. + markdown: { processor: unified({ gfm: true, smartypants: false }) }, integrations: [ starlight({ diff --git a/website/src/components/Home.astro b/website/src/components/Home.astro index 59b6717..a758848 100644 --- a/website/src/components/Home.astro +++ b/website/src/components/Home.astro @@ -130,10 +130,9 @@ const showcaseTerm = `$ pdcli € 8,500 Proposal 4710 Globex pilot € 4,200 Qualified 4699 Initech seats € 2,750 Contact - 4 open deals · €27,450 open value $ pdcli deal update 4821 --status won - Acme renewal → Won · activity logged + Updated deal 4821 (Acme renewal → Won) $ `; --- @@ -437,24 +436,20 @@ const showcaseTerm = `$ pdcli ┌ SALES PIPELINE ───────────────── Q2 ┐ - Qualified 18 deals €142,000 - Contact 11 deals € 98,500 - Proposal 7 deals € 76,200 - Negotiation 4 deals € 51,000 - ───────────────────────────────────── - weighted forecast €221,480 - win rate 32% · avg cycle 24d`, + cmd: 'pdcli pipeline health --pipeline 1', + out: ` STAGE OPEN VALUE STALE >14d NO NEXT STEP + Qualified 18 €142,000 3 5 + Proposal 7 € 76,200 1 2 + Negotiation 4 € 51,000 0 1`, }, { cmd: "pdcli deal list --status open --jq '.[].id' | pdcli deal bulk-update --stage 5", out: ` 40 open deals moved → Negotiation`, }, { - cmd: 'pdcli person import leads.csv --dry-run', - out: ` +212 new ~18 updates !3 conflicts - dry run · nothing written · custom fields matched by name`, + cmd: 'pdcli person import leads.csv --upsert --match-on email --dry-run', + out: ` 194 create · 18 update · nothing written + dry run · custom fields matched by name`, }, { cmd: 'pdcli mcp serve', diff --git a/website/src/content/docs/automation/exit-codes.mdx b/website/src/content/docs/automation/exit-codes.mdx index 9cc9e08..907454e 100644 --- a/website/src/content/docs/automation/exit-codes.mdx +++ b/website/src/content/docs/automation/exit-codes.mdx @@ -21,7 +21,7 @@ command shares the same ladder. | `75` | Rate limited | `429` | Token budget exhausted. pdcli retries 429s with backoff; if they never clear it surfaces `75` (not `69`), and `--no-retry` surfaces the first one. Back off and retry after the reset window. | | `77` | Auth / permission | `401`, `403` | Token is invalid, expired, or lacks scope — including a **failed OAuth refresh** (`invalid_grant`). Re-authenticate (`pdcli auth login`). Don't loop. A `403` after repeated `429`s is a rate-limit hard stop — wait for the reset, don't retry. | | `78` | Config / account | `402`, missing domain/token, host-lock violation, no keychain | The CLI or account is misconfigured: no company domain, no keychain to write to, a `pdcli api` URL outside your host, a redirect off your host, or a `402` (plan lacks the feature). Fix config or the account — don't retry. | -| `8` | Findings present (`watch` only) | — | `pdcli watch` exits `8` when it surfaces new anomalies, so `pdcli watch \|\| notify` fires only on findings. Not part of the general ladder — specific to `watch`. | +| `8` | Findings present (`watch` only) | — | `pdcli watch` exits `8` when it surfaces new anomalies. Test for it explicitly (`pdcli watch; [ $? -eq 8 ] && notify`) — a bare `pdcli watch \|\| notify` also fires on any other failure, not just findings. Not part of the general ladder — specific to `watch`. | The HTTP-status mapping lives in `src/lib/errors.js` (`exitCodeForStatus`): `400/422 → 65`, `401/403 → 77`, `402 → 78`, `429 → 75`, `5xx → 69`. On top of that: an oclif parse error @@ -56,7 +56,7 @@ human form; `--verbose` there adds the request path, status code, and `error_inf ## Branching on the code ```bash -pdcli deal get 42 --output json > deal.json +pdcli lookup deal --field "PO Number" --value PO-1234 --output json > deal.json case $? in 0) echo "ok" ;; 3) echo "no match — create it" ;; @@ -69,7 +69,7 @@ case $? in esac ``` -`pdcli` also prints `127` (via the command-not-found hook) when you invoke a command name +`pdcli` also exits `127` (via the command-not-found hook) when you invoke a command name that doesn't exist. See also: [Troubleshooting](/pdcli/reference/troubleshooting/) for what to do per failure, diff --git a/website/src/content/docs/automation/output.mdx b/website/src/content/docs/automation/output.mdx index 1853c0b..c5211af 100644 --- a/website/src/content/docs/automation/output.mdx +++ b/website/src/content/docs/automation/output.mdx @@ -53,8 +53,9 @@ produces. ## Pick columns with `--fields` -`--fields` limits a `table` or `csv` to the columns you name (by their data key, not -the header): +`--fields` limits the output to the columns you name (by their data key, not the +header). It projects `table` and `csv` columns, and also narrows each `json`/`yaml` +record to just those keys: ```bash pdcli deal list --fields id,title,value @@ -129,7 +130,7 @@ stage_id: 3 ## Resolving custom fields in machine output By default `json`, `yaml`, and `csv` keep custom-field values raw — hash keys and numeric -option IDs — so scripts have a stable shape to parse. On single-record `get` commands you can +option IDs — so scripts have a stable shape to parse. On `get` and core `list` commands you can opt into readable names with `--resolve-fields`, which swaps hash keys for field names and option IDs for labels. See [Custom fields](/pdcli/guides/custom-fields/) for the details. diff --git a/website/src/content/docs/concepts/api-model.mdx b/website/src/content/docs/concepts/api-model.mdx index ed16e47..0fd1b17 100644 --- a/website/src/content/docs/concepts/api-model.mdx +++ b/website/src/content/docs/concepts/api-model.mdx @@ -12,7 +12,7 @@ Pipedrive runs two API versions. `pdcli` routes each topic to the right one. | Topic | API | | ----- | --- | -| deals, persons, organizations, products, pipelines, stages, activities, projects, fields, search | **v2** | +| deals, persons, organizations, products, pipelines, stages, activities, projects, tasks, fields, search | **v2** | | leads, notes, files, filters, webhooks, goals, users, mail | **v1** | Core CRM is on **v2** because Pipedrive deprecated ~59 v1 core endpoints after 2025-12-31, so @@ -55,12 +55,10 @@ cost depends on the verb: | POST / PUT / PATCH | 10 | | DELETE one | 6 | | DELETE list | 10 | -| Search | 40 | +| Search | 20 | There's a rolling **2-second burst window** plus a **daily budget** (scales with plan and -seats, resets at midnight server time). On a `429`, pdcli reads `x-ratelimit-reset` -(falling back to `Retry-After`, then a 2s default) to decide how long to wait before -retrying. +seats, resets at midnight server time). Inspect the remaining budget with **`pdcli quota`** (alias `ratelimit`): it reports the daily token budget remaining/limit and gates CI with `--min`/`--threshold` (exit `75` when diff --git a/website/src/content/docs/concepts/security.mdx b/website/src/content/docs/concepts/security.mdx index 4055c18..99d8d9a 100644 --- a/website/src/content/docs/concepts/security.mdx +++ b/website/src/content/docs/concepts/security.mdx @@ -73,7 +73,8 @@ applies to file downloads and uploads. `Authorization: Bearer` for OAuth) and are never echoed in logs, errors, or `--verbose` output. `--verbose` shows the request path, status, and Pipedrive's `error_info`, but not credentials. -- **User-Agent.** Every request identifies itself as `pdcli/` (e.g. `pdcli/0.5.0`). +- **User-Agent.** Every request identifies itself as `pdcli/`, where + `` is the installed release. For where each setting is stored and the full precedence order, see [Config & environment](/pdcli/reference/config/). diff --git a/website/src/content/docs/guides/analytics.mdx b/website/src/content/docs/guides/analytics.mdx index 646dd6e..3b1194f 100644 --- a/website/src/content/docs/guides/analytics.mdx +++ b/website/src/content/docs/guides/analytics.mdx @@ -48,7 +48,8 @@ If a lever can't be computed (no decided deals, no won deals, or a zero cycle), A one-call rollup of deal value, computed **server-side**: Pipedrive returns per-currency totals, a probability-weighted total, and a deal count, so there's no list to page through. -It's the cheapest way to ask "what's my pipeline worth right now?" +It's one 40-token call regardless of deal count — the way to ask "what's my pipeline worth +right now?" without paging every deal. ```bash pdcli deal summary @@ -137,9 +138,14 @@ pipeline, inferred otherwise. Days-in-current-stage for every open deal, bucketed, so you can see at a glance how much value is going stale and where. For each stage it also mines the **completed** dwell -distribution (entry → next-entry across all deals) and reports per-stage **p50/p90**, then -flags how many open deals have now sat in the stage longer than its own p90 — the deals most -likely to be quietly dying. +distribution (entry → next-entry) and reports per-stage **p50/p90**, then flags how many open +deals have now sat in the stage longer than its own p90 — the deals most likely to be quietly +dying. + +The dwell baseline is mined from the **open** deals it fetches, not the whole account, so it's +a "deals that are still around" sample: it skips the dwells of deals that already closed, which +can bias the p50/p90 lower than the true historical distribution. Read the p90 flag as a +relative signal, not a calibrated benchmark. ```bash pdcli metrics aging --pipeline 1 --buckets 30,60,90 @@ -390,4 +396,6 @@ digest never fails for that reason). `--format md|html` renders the packet as a shareable document — pipe it to Slack/email from cron, or write it to a file with `--out`. These artifact formats are distinct from the global -`--output table|json|yaml|csv` (which stays for scripting the structured packet). +`--output table|json|yaml|csv` (which stays for scripting the structured packet), and +**mutually exclusive** with it: passing `--format` together with `--output`, `--jq`, or +`--fields` exits 64. Pick the document artifact or the machine format, not both. diff --git a/website/src/content/docs/guides/authentication.mdx b/website/src/content/docs/guides/authentication.mdx index 762b505..637a1a5 100644 --- a/website/src/content/docs/guides/authentication.mdx +++ b/website/src/content/docs/guides/authentication.mdx @@ -28,8 +28,10 @@ Non-interactively: pdcli auth login --company acme --api-token ``` -Prefer the prompt or an environment variable over `--api-token` so the token stays -out of your shell history. +Prefer the interactive prompt over `--api-token` so the token stays out of your shell +history. If you'd rather not store anything in the keychain at all, skip `auth login` +entirely and pass credentials per run with the `PDCLI_*` [environment +variables](#ci-and-headless) — `auth login` does not read them. ## OAuth mode @@ -92,6 +94,10 @@ Log out to clear stored credentials for the active profile (both modes): pdcli auth logout ``` +Any auth failure — missing or expired credentials, or a failed OAuth refresh — exits with +code `77`, so a script can branch on re-authentication deterministically. See +[Exit codes](/pdcli/automation/exit-codes/). + ## CI and headless For pipelines and agents, skip the keychain entirely and pass credentials via the diff --git a/website/src/content/docs/guides/backup.mdx b/website/src/content/docs/guides/backup.mdx index af351e4..e95659c 100644 --- a/website/src/content/docs/guides/backup.mdx +++ b/website/src/content/docs/guides/backup.mdx @@ -136,9 +136,14 @@ pdcli sync warehouse --dir ./warehouse --full # rebuild from scratch Each of the five incremental entities (deals, persons, organizations, activities, products) appends to `.ndjson` (one JSON object per line) and advances its **own** high-water -mark in `manifest.json`. The watermark moves to the newest `update_time` seen **+ 1 second** -(the API's `updated_since` is inclusive, so this avoids re-emitting the boundary record), and -only after the append succeeds — an interrupted run replays rather than skips. `--since` +mark in `warehouse-manifest.json` (kept deliberately distinct from `backup`'s own +`manifest.json`, so a warehouse and a backup can share a directory). The watermark moves to +the newest `update_time` seen **exactly** — not +1s. Since `updated_since` is inclusive, the +boundary record is re-emitted on the next run: the feed is **at-least-once**, so dedupe +downstream by `(entity, id)`. Emitting a row twice is harmless; a +1s skip could silently +drop a record saved later in the same boundary second. The mark only advances after the +append succeeds — an interrupted run replays rather than skips — and it **never moves +backward**, so a one-off `--since` backfill can't rewind the maintained cursor. `--since` overrides the start for every entity. :::caution[Hard deletes are not captured] diff --git a/website/src/content/docs/guides/bulk.mdx b/website/src/content/docs/guides/bulk.mdx index 58a8468..e2b5349 100644 --- a/website/src/content/docs/guides/bulk.mdx +++ b/website/src/content/docs/guides/bulk.mdx @@ -161,8 +161,7 @@ pdcli org upsert "D-42" --by "External ID" --field "Status=Active" ``` The match value is the positional argument; `--by` names the field to match on — a built-in -key or a **searchable** custom field (`address`, `varchar`, `text`, `double`, `monetary`, -`phone`): +key or a **searchable** custom field (`varchar`, `varchar_auto`, `text`, `double`, `phone`): | Entity | Built-in `--by` keys | | ------ | --------------------- | @@ -170,6 +169,10 @@ key or a **searchable** custom field (`address`, `varchar`, `text`, `double`, `m | org | `name` | | deal | `title` | +`address` and `monetary` custom fields are deliberately **refused** with exit 64: v2 returns +those as objects (`{ value, currency }` / `{ value, … }`), so the scalar compare would never +match and every run would create a duplicate. + ### Why it refuses instead of guessing Pipedrive's `exact_match` search is **not** a unique-key lookup — it's case-insensitive, and @@ -239,3 +242,8 @@ fi It resolves a human field name to its custom-field key for you (deal, person, org, product, lead). Matching is **case-sensitive**, and — like upsert — the search index is eventually consistent, so a `lookup`-then-`create` loop can still double-create in fast pipelines. + +Beyond the default exact match, `--match beginning|middle` does a prefix or substring search +(also case-sensitive; these modes need a value of **at least 2 characters**). Any mode returns +**at most 100 rows** — the per-entity `/search` endpoint's hard cap — so tighten the value if +you're brushing that ceiling. diff --git a/website/src/content/docs/guides/deal-products.mdx b/website/src/content/docs/guides/deal-products.mdx index 46be87a..2593b43 100644 --- a/website/src/content/docs/guides/deal-products.mdx +++ b/website/src/content/docs/guides/deal-products.mdx @@ -63,9 +63,16 @@ Pass at least one field flag, or it's exit 64 (`Nothing to update`). Any of `--p combined; the server recomputes `sum` from the new values. :::note -There is **no per-line duration or billing-cycle flag**. Pipedrive replaced the old -`duration`/`duration_unit` line-item fields with a product-level `billing_frequency` in 2024, -so recurring terms are configured on the product (`product`), not on each deal attachment. +pdcli has **no per-line billing-cycle flag yet** — but the v2 API does support it. `POST`/`PATCH +/api/v2/deals/{id}/products` accept per-line `billing_frequency`, `billing_frequency_cycles`, +and `billing_start_date` (a Growth-plan-and-above feature), so recurring terms can be set on the +individual attachment, not just the catalog product. Until pdcli exposes flags for them, reach +for the raw [`pdcli api`](/pdcli/guides/api/) escape hatch: + +```bash +pdcli api PATCH /api/v2/deals/42/products/3 \ + --body '{"billing_frequency":"monthly","billing_frequency_cycles":12}' +``` ::: ## Remove a line item diff --git a/website/src/content/docs/guides/relations.mdx b/website/src/content/docs/guides/relations.mdx index 42150b7..124be0d 100644 --- a/website/src/content/docs/guides/relations.mdx +++ b/website/src/content/docs/guides/relations.mdx @@ -84,13 +84,17 @@ pdcli org relationship list --org 1481 ``` ```text -┌────┬────────┬───────────┬───────────┬─────────┐ +┌────┬────────┬───────────┬────────────┬─────────┐ │ ID │ Type │ Owner Org │ Linked Org │ Related │ -├────┼────────┼───────────┼───────────┼─────────┤ -│ 7 │ parent │ 1481 │ 1480 │ Globex │ -└────┴────────┴───────────┴───────────┴─────────┘ +├────┼────────┼───────────┼────────────┼─────────┤ +│ 7 │ parent │ Initech │ Initech UK │ Globex │ +└────┴────────┴───────────┴────────────┴─────────┘ ``` +The `Owner Org` / `Linked Org` columns render the organization **names** (the API returns +each side as a nested object), not their IDs. `add` and `remove` still take numeric IDs; pass +`--output json` to see the raw org IDs on the relationship record. + Create a link with `--type parent|related`, naming the two orgs with `--owner` and `--linked`. **For a `parent` relationship the `--owner` is the parent and `--linked` is the daughter**; for `related` the two are interchangeable peers: @@ -108,3 +112,10 @@ pdcli org relationship remove 7 --yes ``` It confirms first; `-y`/`--yes` skips the prompt for scripts. + +## See also + +- [Command reference](/pdcli/reference/commands/) — full flag lists for `deal participant`, + `follower`, `org relationship`, and `deal merge` / `person merge` / `org merge` (fold a + duplicate and its links into one record). +- [Data-hygiene audit](/pdcli/guides/audit/) — surface orphaned or neglected records. diff --git a/website/src/content/docs/reference/commands.mdx b/website/src/content/docs/reference/commands.mdx index c5ce7d6..f23730c 100644 --- a/website/src/content/docs/reference/commands.mdx +++ b/website/src/content/docs/reference/commands.mdx @@ -6,9 +6,8 @@ description: Every pdcli command, flag, and example — generated from the CLI m {/* AUTO-GENERATED from the oclif manifest by scripts/gen-commands.mjs — do not edit by hand. */} All 154 commands in `pdcli` v0.22.0. Every command also -accepts the [global flags](/pdcli/reference/config/) `--output`, `--jq`, -`--fields`, `--profile`, `--limit`, `--no-color`, `--verbose`, -`--no-retry`, and `--timeout`. Run `pdcli --help` for the live version. +accepts the [global flags](/pdcli/reference/config/) `--output`, `--jq`, `--fields`, `--resolve-fields`, `--profile`, `--no-color`, `--verbose`, `--no-retry`, `--timeout`, and `--limit`. +Run `pdcli --help` for the live version. ## Top-level commands diff --git a/website/src/content/docs/reference/config.mdx b/website/src/content/docs/reference/config.mdx index 284c9b4..86a281d 100644 --- a/website/src/content/docs/reference/config.mdx +++ b/website/src/content/docs/reference/config.mdx @@ -12,8 +12,7 @@ A flat reference for how `pdcli` is configured. For the workflow, see exist only on `pdcli auth login`.) 2. **Environment variables** — `PDCLI_COMPANY_DOMAIN`, `PDCLI_API_TOKEN`, `PDCLI_PROFILE`, … 3. **Profile config** — per-profile keys in the config file. -4. **Global config** — shared defaults. -5. **Built-in defaults.** +4. **Built-in defaults.** The company domain and the token resolve **independently**, each down this chain. So a profile domain plus an env token (`PDCLI_API_TOKEN=… pdcli deal list`), or an env domain plus the @@ -26,6 +25,7 @@ keychain token, both work. | `PDCLI_COMPANY_DOMAIN` | Company subdomain (`acme` from `acme.pipedrive.com`). Forms and locks the API host. | | `PDCLI_API_TOKEN` | Personal API token, sent as `x-api-token`. Preferred over `--api-token` so it stays out of shell history. | | `PDCLI_PROFILE` | Active profile name (same as `--profile`). | +| `PDCLI_CONFIG_DIR` | Override the directory that holds `config.json` (takes precedence over the platform default and `$XDG_CONFIG_HOME`). | | `PDCLI_CLIENT_ID` | OAuth app client ID (used with `auth login --oauth`). | | `PDCLI_CLIENT_SECRET` | OAuth app client secret (used with `auth login --oauth`). | | `NO_COLOR` | Any value disables colored output (same as `--no-color`). | @@ -43,7 +43,8 @@ Every command accepts these. Run any command with `--help` to confirm. | `--output`, `-o` | table (TTY) / json (piped) | Output format: `table`, `json`, `yaml`, or `csv`. | | `--jq ` | — | Filter output through a jq expression. | | `--fields ` | — | Comma-separated columns to display. | -| `--profile ` | `default` | Named auth profile (env `PDCLI_PROFILE`). | +| `--resolve-fields` | off | Resolve custom-field hash keys to names (and option ids to labels) in `json`/`yaml`/`csv` output of `get` and core `list` commands. | +| `--profile ` | active profile | Named auth profile (env `PDCLI_PROFILE`). Defaults to the stored `activeProfile`. | | `--no-color` | off | Disable colored output. | | `--verbose` | off | Show request path, status, and `error_info` on errors; enables `pd:*` debug. | | `--no-retry` | off | Disable automatic retry on `429` and `5xx`. | @@ -80,10 +81,14 @@ Config is managed by [`conf`](https://www.npmjs.com/package/conf) under the proj | Platform | Path | | -------- | ---- | -| Linux | `~/.config/pdcli/config.json` (XDG) | +| Linux | `~/.config/pdcli-nodejs/config.json` (XDG) | | macOS | `~/Library/Preferences/pdcli-nodejs/config.json` | | Windows | `%APPDATA%\pdcli-nodejs\Config\config.json` | +On Linux the base directory follows `$XDG_CONFIG_HOME` when set. To relocate the config +directory on any platform, set `PDCLI_CONFIG_DIR` — it wins over both the platform default +and `$XDG_CONFIG_HOME`. + It holds only `activeProfile`, the non-secret per-profile keys above, and any command [aliases](/pdcli/guides/configuration/) under the global `aliases` key (shared across profiles). Credentials are in the OS keychain, not this file. diff --git a/website/src/content/docs/start/distribution.mdx b/website/src/content/docs/start/distribution.mdx index 277cced..fbf3377 100644 --- a/website/src/content/docs/start/distribution.mdx +++ b/website/src/content/docs/start/distribution.mdx @@ -17,10 +17,14 @@ path (npm) plus completions and the doctor. This page is the full menu. | **npm (global)** | Daily use on your own machine | Yes (20+) | | **npx** | A one-off, or a CI step you don't want to install | Yes (20+) | | **Docker** | CI runners and servers with no Node, reproducible pins | No | -| **Homebrew** | macOS / Linux users who live in `brew` | No | -| **Scoop** | Windows users who live in `scoop` | No | +| **Homebrew** _(coming soon)_ | macOS / Linux users who live in `brew` | No | +| **Scoop** _(coming soon)_ | Windows users who live in `scoop` | No | | **Standalone tarball** | Air-gapped or Node-free hosts, manual pinning | No | +The verified, working-today channels are **npm**, **npx**, **Docker**, and the +**standalone tarballs**. Homebrew and Scoop are planned but not yet published — see +their sections below. + ## Authentication, in one line Two ways to get a token to pdcli, and the choice usually follows the channel: @@ -99,8 +103,14 @@ through as arguments. Auth: env vars only (there's no keychain in a container). ## Homebrew -For macOS and Linux users on Homebrew. Installs a self-contained binary, no Node -required. +:::caution[Coming soon: not yet published] +The Homebrew tap is planned but not live yet. There is no `pdcli` formula in +`wavyx/tap`, so the command below will not work today. Until it ships, install with +[npm](#npm-global), [Docker](#docker), or a [standalone tarball](#standalone-tarballs). +::: + +For macOS and Linux users on Homebrew. Once published, it will install a self-contained +binary, no Node required: ```bash brew install wavyx/tap/pdcli @@ -112,7 +122,14 @@ pdcli version ## Scoop -For Windows users on Scoop. Also a self-contained binary, no Node required. +:::caution[Coming soon: not yet published] +The Scoop bucket is planned but not live yet. `wavyx/scoop-pdcli` does not exist, so the +commands below will not work today. Until it ships, install with [npm](#npm-global), +[Docker](#docker), or a [standalone tarball](#standalone-tarballs). +::: + +For Windows users on Scoop. Once published, it will also install a self-contained binary, +no Node required: ```powershell scoop bucket add wavyx https://github.com/wavyx/scoop-pdcli diff --git a/website/src/content/docs/start/installation.mdx b/website/src/content/docs/start/installation.mdx index 14191b3..df39d74 100644 --- a/website/src/content/docs/start/installation.mdx +++ b/website/src/content/docs/start/installation.mdx @@ -29,6 +29,9 @@ npx @wavyx/pdcli deal list `npx` is handy for CI or a one-off, but the global install is faster for daily use. +No Node on the box? The [Distribution](/pdcli/start/distribution/) page covers the +Node-free channels: Docker (`ghcr.io/wavyx/pdcli`) and the standalone tarballs. + ## Verify the install `pdcli version` prints the version and environment: @@ -38,7 +41,7 @@ pdcli version ``` ```text -pdcli 0.5.0 +pdcli 0.22.0 Node: v20.11.1 API base: https://acme.pipedrive.com Platform: darwin-arm64