@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 +10 -2
- package/dist/src/commands/analytics.d.ts +16 -0
- package/dist/src/commands/analytics.js +44 -1
- package/dist/src/core/http.d.ts +10 -0
- package/dist/src/core/http.js +20 -0
- package/dist/src/mcp/bundled.js +1 -1
- package/dist/src/mcp/tools/analytics.js +18 -1
- package/package.json +1 -1
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
|
|
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 (
|
|
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
|
}
|
package/dist/src/core/http.d.ts
CHANGED
|
@@ -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
|
package/dist/src/core/http.js
CHANGED
|
@@ -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
|
package/dist/src/mcp/bundled.js
CHANGED
|
@@ -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
|
|
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
|
];
|