@pitcher/cli-scripts 2.12.0 → 2.13.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ p command --help
12
12
 
13
13
  ## MCP server
14
14
 
15
- Run `p mcp` to start a stdio [MCP](https://modelcontextprotocol.io) server that exposes this CLI's commands as tools to an MCP-capable host (Claude Desktop, Claude Code, etc). It wraps 113 tools, one per CLI `run*` function: every command above (including `dsr create` + `dsr bind-landing` and the full `ld` surface) except the five local `scaffold` subcommands (which just print/write a starter file and make no request). `dev-sync` is exposed as a one-shot sync only; the continuous `watch` mode is not available as a tool.
15
+ Run `p mcp` to start a stdio [MCP](https://modelcontextprotocol.io) server that exposes this CLI's commands as tools to an MCP-capable host (Claude Desktop, Claude Code, etc). It wraps 114 tools, one per CLI `run*` function: every command above (including `dsr create` + `dsr bind-landing` and the full `ld` surface) except the five local `scaffold` subcommands (which just print/write a starter file and make no request). `dev-sync` is exposed as a one-shot sync only; the continuous `watch` mode is not available as a tool.
16
16
 
17
17
  ```bash
18
18
  p mcp
@@ -55,7 +55,7 @@ yarn mcpb:pack # → pitcher.mcpb (validated + packed)
55
55
 
56
56
  Install by double-clicking `pitcher.mcpb` (or Settings → Extensions → Install Extension). Claude Desktop prompts for the API key (stored in the OS keychain) and organization; both are editable afterward, so switching orgs needs no reinstall.
57
57
 
58
- The bundle reuses the same server as `p mcp` but registers a **content-tool subset (110)** — it omits the developer-only `publish-app` and `dev-sync`/`dev-sync-revert`. The `organization` field accepts a subdomain (`acme`), a bare hostname (`acme.my.pitcher.com`), or a full `https://` URL. Build details (esbuild single-file, version injection) live in `mcpb/` and `CLAUDE.md`.
58
+ The bundle reuses the same server as `p mcp` but registers a **content-tool subset (111)** — it omits the developer-only `publish-app` and `dev-sync`/`dev-sync-revert`. The `organization` field accepts a subdomain (`acme`), a bare hostname (`acme.my.pitcher.com`), or a full `https://` URL. Build details (esbuild single-file, version injection) live in `mcpb/` and `CLAUDE.md`.
59
59
 
60
60
  This section is a reference only. For app-development conventions (modules, settings, mount points, SFDC), see the `pitcher-apps` skill, not this README.
61
61
 
@@ -360,6 +360,14 @@ p analytics org --api-key myapikey
360
360
 
361
361
  # Instance rollups (instance-admin or org-admin key required)
362
362
  p analytics instance --instance-id 01... --api-key myapikey
363
+
364
+ # KPI metrics from the clickhouse analytics service (PIT-7647).
365
+ # Access follows the key user's real role on the instance; --org/--url pick the
366
+ # env exactly as for other commands (they route via x-original-domain).
367
+ # Activity metrics need a date window; inventory counts (total-members, ...) do not.
368
+ p analytics kpi --instance-id 01... --type total-members --api-key myapikey
369
+ p analytics kpi --instance-id 01... --type total-active-users \
370
+ --start-date 2026-01-01 --end-date 2026-01-31 --api-key myapikey
363
371
  ```
364
372
 
365
373
  ## To run the `users` command:
@@ -9,4 +9,20 @@ export declare function runAnalyticsOrg(opts: CommonOpts, deps?: AnalyticsDeps):
9
9
  export declare function runAnalyticsInstance(opts: CommonOpts & {
10
10
  instanceId?: string;
11
11
  }, deps?: AnalyticsDeps): Promise<Envelope<unknown>>;
12
+ export interface AnalyticsKpiOpts extends CommonOpts {
13
+ instanceId?: string;
14
+ type?: string;
15
+ startDate?: string;
16
+ endDate?: string;
17
+ groupIds?: string;
18
+ userEmails?: string;
19
+ }
20
+ /**
21
+ * KPI metrics from the clickhouse-api analytics service (PIT-7647). Unlike
22
+ * org/instance rollups (Django), this hits `clickhouse.pitcher.com` with the
23
+ * org api-key; the caller inherits the key user's real role. Dates are required
24
+ * by the server for activity-metric types (inventory counts like
25
+ * `total-members` need none) — that validation stays server-side.
26
+ */
27
+ export declare function runAnalyticsKpi(opts: AnalyticsKpiOpts, deps?: AnalyticsDeps): Promise<Envelope<unknown>>;
12
28
  export declare function createAnalyticsCommand(): Command;
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import { clientFor, toCliError } from '../core/http.js';
2
+ import { clickhouseClientFor, clientFor, toCliError } from '../core/http.js';
3
3
  import { ok, fail } from '../core/envelope.js';
4
4
  import { createCliError } from '../core/errors.js';
5
5
  import { emitEnvelope } from '../core/output.js';
@@ -26,6 +26,37 @@ export async function runAnalyticsInstance(opts, deps = {}) {
26
26
  return fail(toCliError(e));
27
27
  }
28
28
  }
29
+ /**
30
+ * KPI metrics from the clickhouse-api analytics service (PIT-7647). Unlike
31
+ * org/instance rollups (Django), this hits `clickhouse.pitcher.com` with the
32
+ * org api-key; the caller inherits the key user's real role. Dates are required
33
+ * by the server for activity-metric types (inventory counts like
34
+ * `total-members` need none) — that validation stays server-side.
35
+ */
36
+ export async function runAnalyticsKpi(opts, deps = {}) {
37
+ try {
38
+ if (!opts.instanceId)
39
+ throw createCliError('VALIDATION', '--instance-id is required for analytics kpi');
40
+ const client = clickhouseClientFor(opts, deps);
41
+ const params = {
42
+ instance_id: opts.instanceId,
43
+ type: opts.type || 'all',
44
+ };
45
+ if (opts.startDate)
46
+ params.start_date = opts.startDate;
47
+ if (opts.endDate)
48
+ params.end_date = opts.endDate;
49
+ if (opts.groupIds)
50
+ params.group_ids = opts.groupIds;
51
+ if (opts.userEmails)
52
+ params.user_emails = opts.userEmails;
53
+ const res = await client.get('/analytics/kpi', { params });
54
+ return ok(res.data);
55
+ }
56
+ catch (e) {
57
+ return fail(toCliError(e));
58
+ }
59
+ }
29
60
  export function createAnalyticsCommand() {
30
61
  const cmd = new Command('analytics').description('read rollup analytics totals (requires an org-admin API key)');
31
62
  withAuthFlags(cmd.command('org'))
@@ -41,5 +72,17 @@ export function createAnalyticsCommand() {
41
72
  const globals = command.optsWithGlobals();
42
73
  emitEnvelope(await runAnalyticsInstance({ ...options, quiet: globals.quiet }), globals);
43
74
  });
75
+ withAuthFlags(cmd.command('kpi'))
76
+ .option('--instance-id <id>', 'Instance ID (required)')
77
+ .option('--type <type>', "KPI type, e.g. total-members, total-active-users (default 'all')")
78
+ .option('--start-date <iso>', 'Window start (ISO date; required by the server for activity metrics)')
79
+ .option('--end-date <iso>', 'Window end (ISO date; required by the server for activity metrics)')
80
+ .option('--group-ids <csv>', 'Comma-separated distribution-group IDs to scope by')
81
+ .option('--user-emails <csv>', 'Comma-separated user emails to scope by')
82
+ .description('KPI metrics from the clickhouse analytics service (role follows the key user)')
83
+ .action(async (options, command) => {
84
+ const globals = command.optsWithGlobals();
85
+ emitEnvelope(await runAnalyticsKpi({ ...options, quiet: globals.quiet }), globals);
86
+ });
44
87
  return cmd;
45
88
  }
@@ -11,6 +11,16 @@ export interface CommonOpts {
11
11
  export declare function clientFor(opts: CommonOpts, deps?: {
12
12
  client?: AxiosInstance;
13
13
  }): AxiosInstance;
14
+ export declare const CLICKHOUSE_API_BASE_URL = "https://clickhouse.pitcher.com";
15
+ /**
16
+ * Client for the clickhouse-api analytics service (PIT-7647). The service lives
17
+ * on ONE host for every env/region; `x-original-domain` (the same `--org`/`--url`
18
+ * resolution as Django calls) is what routes the request to the right core for
19
+ * key validation + tenant scoping, so the usual flags select test vs prod.
20
+ */
21
+ export declare function clickhouseClientFor(opts: CommonOpts, deps?: {
22
+ client?: AxiosInstance;
23
+ }): AxiosInstance;
14
24
  /**
15
25
  * Build a human-readable message from a server error body. Handles DRF shapes:
16
26
  * a `detail`/`error` string, `non_field_errors`, and field-level error arrays
@@ -15,6 +15,26 @@ export function makeClient(baseUrl, apiKey) {
15
15
  export function clientFor(opts, deps = {}) {
16
16
  return deps.client ?? makeClient(resolveBaseUrl({ org: opts.org, url: opts.url }), resolveApiKey(opts));
17
17
  }
18
+ export const CLICKHOUSE_API_BASE_URL = 'https://clickhouse.pitcher.com';
19
+ /**
20
+ * Client for the clickhouse-api analytics service (PIT-7647). The service lives
21
+ * on ONE host for every env/region; `x-original-domain` (the same `--org`/`--url`
22
+ * resolution as Django calls) is what routes the request to the right core for
23
+ * key validation + tenant scoping, so the usual flags select test vs prod.
24
+ */
25
+ export function clickhouseClientFor(opts, deps = {}) {
26
+ if (deps.client)
27
+ return deps.client;
28
+ const originalDomain = new URL(resolveBaseUrl({ org: opts.org, url: opts.url })).hostname;
29
+ return axios.create({
30
+ baseURL: CLICKHOUSE_API_BASE_URL,
31
+ headers: {
32
+ accept: 'application/json',
33
+ 'x-api-key': resolveApiKey(opts),
34
+ 'x-original-domain': originalDomain,
35
+ },
36
+ });
37
+ }
18
38
  /**
19
39
  * Build a human-readable message from a server error body. Handles DRF shapes:
20
40
  * a `detail`/`error` string, `non_field_errors`, and field-level error arrays
@@ -1,7 +1,7 @@
1
1
  import { allTools } from './registry.js';
2
2
  // Developer-only tools excluded from the consumer .mcpb bundle. `publish_app` is alwaysDestructive
3
3
  // (creates a live, org-visible app release); `dev_sync`/`dev_sync_revert` mutate remote S3 dev state.
4
- // None are relevant to a non-technical adopter installing the extension. The CLI `p mcp` keeps all 113.
4
+ // None are relevant to a non-technical adopter installing the extension. The CLI `p mcp` keeps all 114.
5
5
  export const BUNDLE_EXCLUDED_TOOLS = new Set(['pitcher_publish_app', 'pitcher_dev_sync', 'pitcher_dev_sync_revert']);
6
6
  // The tool set the .mcpb bundle registers.
7
7
  export const bundledTools = allTools.filter((t) => !BUNDLE_EXCLUDED_TOOLS.has(t.name));
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { runAnalyticsOrg, runAnalyticsInstance } from '../../commands/analytics.js';
2
+ import { runAnalyticsOrg, runAnalyticsInstance, runAnalyticsKpi } from '../../commands/analytics.js';
3
3
  export const analyticsTools = [
4
4
  {
5
5
  name: 'pitcher_analytics_org',
@@ -17,4 +17,21 @@ export const analyticsTools = [
17
17
  run: runAnalyticsInstance,
18
18
  readOnly: true,
19
19
  },
20
+ {
21
+ name: 'pitcher_analytics_kpi',
22
+ title: 'Instance KPI metrics',
23
+ description: 'Read KPI metrics for an instance from the clickhouse analytics service (PIT-7647). ' +
24
+ 'Access follows the API key user’s real role; activity-metric types need start/end dates ' +
25
+ '(inventory counts like total-members do not).',
26
+ inputShape: {
27
+ instanceId: z.string().describe('Instance ID (required)'),
28
+ type: z.string().optional().describe("KPI type, e.g. total-members, total-active-users (default 'all')"),
29
+ startDate: z.string().optional().describe('Window start, ISO date (required by the server for activity metrics)'),
30
+ endDate: z.string().optional().describe('Window end, ISO date (required by the server for activity metrics)'),
31
+ groupIds: z.string().optional().describe('Comma-separated distribution-group IDs to scope by'),
32
+ userEmails: z.string().optional().describe('Comma-separated user emails to scope by'),
33
+ },
34
+ run: runAnalyticsKpi,
35
+ readOnly: true,
36
+ },
20
37
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pitcher/cli-scripts",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "The Pitcher CLI for various tasks in its ecosystem.",
5
5
  "author": "Pitcher AG",
6
6
  "license": "MIT",