@codemieai/code 0.2.0 → 0.3.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 +38 -7
- package/dist/agents/core/session/ensure-session.d.ts.map +1 -1
- package/dist/agents/core/session/ensure-session.js +14 -11
- package/dist/agents/core/session/ensure-session.js.map +1 -1
- package/dist/agents/plugins/claude/plugin/{codemie-statusline.mjs → session-status.mjs} +1 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/SKILL.md +641 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/references/leaderboard-dashboard-report.md +225 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/references/people-spending-dashboard-report.md +746 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/references/people-spending-dashboard-template.html +3270 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/scripts/analytics-cli.js +893 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/scripts/inspect-schema.js +211 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-html-report/README.md +39 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-html-report/SKILL.md +117 -26
- package/dist/agents/plugins/claude/plugin/skills/codemie-html-report/scripts/inject-css.js +40 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-html-report/scripts/inject-data.js +68 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-html-report/style-guide/css/bundle.css +1 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/SKILL.md +240 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/assistants.md +256 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/categories.md +101 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/datasources.md +401 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/integrations.md +242 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/skills.md +191 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/users.md +38 -0
- package/dist/agents/plugins/claude/plugin/skills/codemie-sdk/examples/workflows.md +151 -0
- package/dist/agents/plugins/claude/plugin/skills/msgraph/scripts/msgraph.js +12 -2
- package/dist/agents/plugins/claude/plugin/statusline.mjs +216 -0
- package/dist/agents/plugins/claude/statusline-installer.d.ts +8 -0
- package/dist/agents/plugins/claude/statusline-installer.d.ts.map +1 -0
- package/dist/agents/plugins/claude/statusline-installer.js +127 -0
- package/dist/agents/plugins/claude/statusline-installer.js.map +1 -0
- package/dist/agents/plugins/codemie-code.plugin.d.ts.map +1 -1
- package/dist/agents/plugins/codemie-code.plugin.js +5 -0
- package/dist/agents/plugins/codemie-code.plugin.js.map +1 -1
- package/dist/cli/commands/assistants/chat/index.d.ts.map +1 -1
- package/dist/cli/commands/assistants/chat/index.js +8 -2
- package/dist/cli/commands/assistants/chat/index.js.map +1 -1
- package/dist/cli/commands/assistants/setup/generators/claude-agent-generator.d.ts +3 -2
- package/dist/cli/commands/assistants/setup/generators/claude-agent-generator.d.ts.map +1 -1
- package/dist/cli/commands/assistants/setup/generators/claude-agent-generator.js +5 -4
- package/dist/cli/commands/assistants/setup/generators/claude-agent-generator.js.map +1 -1
- package/dist/cli/commands/assistants/setup/generators/claude-skill-generator.d.ts +3 -2
- package/dist/cli/commands/assistants/setup/generators/claude-skill-generator.d.ts.map +1 -1
- package/dist/cli/commands/assistants/setup/generators/claude-skill-generator.js +8 -6
- package/dist/cli/commands/assistants/setup/generators/claude-skill-generator.js.map +1 -1
- package/dist/cli/commands/assistants/setup/helpers.d.ts +3 -2
- package/dist/cli/commands/assistants/setup/helpers.d.ts.map +1 -1
- package/dist/cli/commands/assistants/setup/helpers.js +3 -2
- package/dist/cli/commands/assistants/setup/helpers.js.map +1 -1
- package/dist/cli/commands/assistants/setup/index.d.ts.map +1 -1
- package/dist/cli/commands/assistants/setup/index.js +7 -13
- package/dist/cli/commands/assistants/setup/index.js.map +1 -1
- package/dist/cli/commands/assistants/setup/summary/index.d.ts +3 -3
- package/dist/cli/commands/assistants/setup/summary/index.d.ts.map +1 -1
- package/dist/cli/commands/assistants/setup/summary/index.js +5 -5
- package/dist/cli/commands/assistants/setup/summary/index.js.map +1 -1
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +40 -0
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/profile/display.d.ts.map +1 -1
- package/dist/cli/commands/profile/display.js +1 -0
- package/dist/cli/commands/profile/display.js.map +1 -1
- package/dist/cli/commands/proxy/connectors/desktop-managed-mcp-servers.json +0 -6
- package/dist/cli/commands/proxy/connectors/desktop.d.ts.map +1 -1
- package/dist/cli/commands/proxy/connectors/desktop.js +20 -10
- package/dist/cli/commands/proxy/connectors/desktop.js.map +1 -1
- package/dist/cli/commands/sdk/assistants.d.ts +3 -0
- package/dist/cli/commands/sdk/assistants.d.ts.map +1 -0
- package/dist/cli/commands/sdk/assistants.js +211 -0
- package/dist/cli/commands/sdk/assistants.js.map +1 -0
- package/dist/cli/commands/sdk/categories.d.ts +3 -0
- package/dist/cli/commands/sdk/categories.d.ts.map +1 -0
- package/dist/cli/commands/sdk/categories.js +186 -0
- package/dist/cli/commands/sdk/categories.js.map +1 -0
- package/dist/cli/commands/sdk/datasources.d.ts +3 -0
- package/dist/cli/commands/sdk/datasources.d.ts.map +1 -0
- package/dist/cli/commands/sdk/datasources.js +276 -0
- package/dist/cli/commands/sdk/datasources.js.map +1 -0
- package/dist/cli/commands/sdk/index.d.ts +3 -0
- package/dist/cli/commands/sdk/index.d.ts.map +1 -0
- package/dist/cli/commands/sdk/index.js +23 -0
- package/dist/cli/commands/sdk/index.js.map +1 -0
- package/dist/cli/commands/sdk/integrations.d.ts +3 -0
- package/dist/cli/commands/sdk/integrations.d.ts.map +1 -0
- package/dist/cli/commands/sdk/integrations.js +220 -0
- package/dist/cli/commands/sdk/integrations.js.map +1 -0
- package/dist/cli/commands/sdk/llm.d.ts +3 -0
- package/dist/cli/commands/sdk/llm.d.ts.map +1 -0
- package/dist/cli/commands/sdk/llm.js +48 -0
- package/dist/cli/commands/sdk/llm.js.map +1 -0
- package/dist/cli/commands/sdk/services/assistants.d.ts +13 -0
- package/dist/cli/commands/sdk/services/assistants.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/assistants.js +60 -0
- package/dist/cli/commands/sdk/services/assistants.js.map +1 -0
- package/dist/cli/commands/sdk/services/categories.d.ts +8 -0
- package/dist/cli/commands/sdk/services/categories.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/categories.js +19 -0
- package/dist/cli/commands/sdk/services/categories.js.map +1 -0
- package/dist/cli/commands/sdk/services/datasources.d.ts +33 -0
- package/dist/cli/commands/sdk/services/datasources.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/datasources.js +268 -0
- package/dist/cli/commands/sdk/services/datasources.js.map +1 -0
- package/dist/cli/commands/sdk/services/index.d.ts +6 -0
- package/dist/cli/commands/sdk/services/index.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/index.js +6 -0
- package/dist/cli/commands/sdk/services/index.js.map +1 -0
- package/dist/cli/commands/sdk/services/integrations.d.ts +27 -0
- package/dist/cli/commands/sdk/services/integrations.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/integrations.js +59 -0
- package/dist/cli/commands/sdk/services/integrations.js.map +1 -0
- package/dist/cli/commands/sdk/services/llm.d.ts +4 -0
- package/dist/cli/commands/sdk/services/llm.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/llm.js +7 -0
- package/dist/cli/commands/sdk/services/llm.js.map +1 -0
- package/dist/cli/commands/sdk/services/skills.d.ts +23 -0
- package/dist/cli/commands/sdk/services/skills.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/skills.js +69 -0
- package/dist/cli/commands/sdk/services/skills.js.map +1 -0
- package/dist/cli/commands/sdk/services/users.d.ts +4 -0
- package/dist/cli/commands/sdk/services/users.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/users.js +7 -0
- package/dist/cli/commands/sdk/services/users.js.map +1 -0
- package/dist/cli/commands/sdk/services/workflows.d.ts +7 -0
- package/dist/cli/commands/sdk/services/workflows.d.ts.map +1 -0
- package/dist/cli/commands/sdk/services/workflows.js +34 -0
- package/dist/cli/commands/sdk/services/workflows.js.map +1 -0
- package/dist/cli/commands/sdk/skills.d.ts +3 -0
- package/dist/cli/commands/sdk/skills.d.ts.map +1 -0
- package/dist/cli/commands/sdk/skills.js +492 -0
- package/dist/cli/commands/sdk/skills.js.map +1 -0
- package/dist/cli/commands/sdk/users.d.ts +3 -0
- package/dist/cli/commands/sdk/users.d.ts.map +1 -0
- package/dist/cli/commands/sdk/users.js +81 -0
- package/dist/cli/commands/sdk/users.js.map +1 -0
- package/dist/cli/commands/sdk/utils/cli-utils.d.ts +35 -0
- package/dist/cli/commands/sdk/utils/cli-utils.d.ts.map +1 -0
- package/dist/cli/commands/sdk/utils/cli-utils.js +110 -0
- package/dist/cli/commands/sdk/utils/cli-utils.js.map +1 -0
- package/dist/cli/commands/sdk/utils/datasource-types.d.ts +9 -0
- package/dist/cli/commands/sdk/utils/datasource-types.d.ts.map +1 -0
- package/dist/cli/commands/sdk/utils/datasource-types.js +61 -0
- package/dist/cli/commands/sdk/utils/datasource-types.js.map +1 -0
- package/dist/cli/commands/sdk/utils/file-utils.d.ts +8 -0
- package/dist/cli/commands/sdk/utils/file-utils.d.ts.map +1 -0
- package/dist/cli/commands/sdk/utils/file-utils.js +21 -0
- package/dist/cli/commands/sdk/utils/file-utils.js.map +1 -0
- package/dist/cli/commands/sdk/utils/render.d.ts +82 -0
- package/dist/cli/commands/sdk/utils/render.d.ts.map +1 -0
- package/dist/cli/commands/sdk/utils/render.js +149 -0
- package/dist/cli/commands/sdk/utils/render.js.map +1 -0
- package/dist/cli/commands/sdk/workflows.d.ts +3 -0
- package/dist/cli/commands/sdk/workflows.d.ts.map +1 -0
- package/dist/cli/commands/sdk/workflows.js +170 -0
- package/dist/cli/commands/sdk/workflows.js.map +1 -0
- package/dist/cli/commands/setup.js +4 -0
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/shared/prompts/storage-scope.d.ts +2 -1
- package/dist/cli/commands/shared/prompts/storage-scope.d.ts.map +1 -1
- package/dist/cli/commands/shared/prompts/storage-scope.js +4 -3
- package/dist/cli/commands/shared/prompts/storage-scope.js.map +1 -1
- package/dist/cli/commands/skills/add.d.ts.map +1 -1
- package/dist/cli/commands/skills/add.js +28 -9
- package/dist/cli/commands/skills/add.js.map +1 -1
- package/dist/cli/commands/skills/lib/skills-sh-telemetry.d.ts +5 -0
- package/dist/cli/commands/skills/lib/skills-sh-telemetry.d.ts.map +1 -1
- package/dist/cli/commands/skills/lib/skills-sh-telemetry.js +22 -4
- package/dist/cli/commands/skills/lib/skills-sh-telemetry.js.map +1 -1
- package/dist/cli/commands/skills/setup/generators/claude-skill-generator.d.ts +3 -2
- package/dist/cli/commands/skills/setup/generators/claude-skill-generator.d.ts.map +1 -1
- package/dist/cli/commands/skills/setup/generators/claude-skill-generator.js +29 -14
- package/dist/cli/commands/skills/setup/generators/claude-skill-generator.js.map +1 -1
- package/dist/cli/commands/skills/setup/helpers.d.ts +3 -2
- package/dist/cli/commands/skills/setup/helpers.d.ts.map +1 -1
- package/dist/cli/commands/skills/setup/helpers.js +6 -8
- package/dist/cli/commands/skills/setup/helpers.js.map +1 -1
- package/dist/cli/commands/skills/setup/index.js +8 -16
- package/dist/cli/commands/skills/setup/index.js.map +1 -1
- package/dist/cli/commands/skills/setup/sync.d.ts.map +1 -1
- package/dist/cli/commands/skills/setup/sync.js +6 -5
- package/dist/cli/commands/skills/setup/sync.js.map +1 -1
- package/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/dist/cli/commands/uninstall.js +17 -0
- package/dist/cli/commands/uninstall.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/env/types.d.ts +11 -4
- package/dist/env/types.d.ts.map +1 -1
- package/dist/env/types.js +5 -0
- package/dist/env/types.js.map +1 -1
- package/dist/migrations/004-skills-assistants-top-level.migration.d.ts +10 -0
- package/dist/migrations/004-skills-assistants-top-level.migration.d.ts.map +1 -0
- package/dist/migrations/004-skills-assistants-top-level.migration.js +65 -0
- package/dist/migrations/004-skills-assistants-top-level.migration.js.map +1 -0
- package/dist/migrations/005-skill-slug-format.migration.d.ts +10 -0
- package/dist/migrations/005-skill-slug-format.migration.d.ts.map +1 -0
- package/dist/migrations/005-skill-slug-format.migration.js +82 -0
- package/dist/migrations/005-skill-slug-format.migration.js.map +1 -0
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +2 -2
- package/dist/migrations/index.js.map +1 -1
- package/dist/providers/core/codemie-auth-helpers.d.ts +4 -1
- package/dist/providers/core/codemie-auth-helpers.d.ts.map +1 -1
- package/dist/providers/core/codemie-auth-helpers.js +21 -18
- package/dist/providers/core/codemie-auth-helpers.js.map +1 -1
- package/dist/providers/plugins/anthropic-subscription/anthropic-subscription.setup-steps.d.ts.map +1 -1
- package/dist/providers/plugins/anthropic-subscription/anthropic-subscription.setup-steps.js +4 -2
- package/dist/providers/plugins/anthropic-subscription/anthropic-subscription.setup-steps.js.map +1 -1
- package/dist/providers/plugins/sso/proxy/plugins/endpoint-blocker.plugin.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/plugins/endpoint-blocker.plugin.js +14 -6
- package/dist/providers/plugins/sso/proxy/plugins/endpoint-blocker.plugin.js.map +1 -1
- package/dist/providers/plugins/sso/proxy/plugins/index.d.ts +1 -0
- package/dist/providers/plugins/sso/proxy/plugins/index.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/plugins/index.js +3 -0
- package/dist/providers/plugins/sso/proxy/plugins/index.js.map +1 -1
- package/dist/providers/plugins/sso/proxy/plugins/session-expiry-handler.plugin.d.ts +9 -0
- package/dist/providers/plugins/sso/proxy/plugins/session-expiry-handler.plugin.d.ts.map +1 -0
- package/dist/providers/plugins/sso/proxy/plugins/session-expiry-handler.plugin.js +23 -0
- package/dist/providers/plugins/sso/proxy/plugins/session-expiry-handler.plugin.js.map +1 -0
- package/dist/providers/plugins/sso/proxy/proxy-errors.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/proxy-errors.js +1 -2
- package/dist/providers/plugins/sso/proxy/proxy-errors.js.map +1 -1
- package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts +10 -0
- package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/sso.proxy.js +77 -2
- package/dist/providers/plugins/sso/proxy/sso.proxy.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-aggregator.js +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-aggregator.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.js +2 -2
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-api-client.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-sync-processor.js +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-sync-processor.js.map +1 -1
- package/dist/providers/plugins/sso/sso.auth.d.ts.map +1 -1
- package/dist/providers/plugins/sso/sso.auth.js +10 -2
- package/dist/providers/plugins/sso/sso.auth.js.map +1 -1
- package/dist/providers/plugins/sso/sso.setup-steps.d.ts.map +1 -1
- package/dist/providers/plugins/sso/sso.setup-steps.js +3 -1
- package/dist/providers/plugins/sso/sso.setup-steps.js.map +1 -1
- package/dist/utils/config.d.ts +16 -11
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +87 -82
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/paths.d.ts +5 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -0
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/profile.d.ts +0 -2
- package/dist/utils/profile.d.ts.map +1 -1
- package/dist/utils/profile.js +0 -5
- package/dist/utils/profile.js.map +1 -1
- package/dist/utils/security.d.ts.map +1 -1
- package/dist/utils/security.js +18 -8
- package/dist/utils/security.js.map +1 -1
- package/dist/utils/slug.d.ts +2 -0
- package/dist/utils/slug.d.ts.map +1 -0
- package/dist/utils/slug.js +6 -0
- package/dist/utils/slug.js.map +1 -0
- package/package.json +4 -2
- package/scripts/postinstall.mjs +52 -0
|
@@ -0,0 +1,893 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CodeMie Analytics CLI
|
|
4
|
+
* Generic, flexible Node.js script for querying CodeMie and LiteLLM APIs.
|
|
5
|
+
*
|
|
6
|
+
* Auth mirrors the `codemie assistants chat` flow exactly:
|
|
7
|
+
* 1. Load config from ~/.codemie/codemie-cli.config.json (active profile)
|
|
8
|
+
* 2. Extract codeMieUrl (or baseUrl) from profile
|
|
9
|
+
* 3. Normalize URL to protocol://host
|
|
10
|
+
* 4. Look up per-URL SSO credentials from encrypted file
|
|
11
|
+
* 5. Fall back to global SSO credentials (verify apiUrl matches)
|
|
12
|
+
* 6. Check credential expiry
|
|
13
|
+
* 7. Send cookies as Cookie header on every API request
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* node analytics-cli.js <command> [options]
|
|
17
|
+
*
|
|
18
|
+
* Commands:
|
|
19
|
+
* summaries Overall token/cost/user summary
|
|
20
|
+
* leaderboard AI champions leaderboard (entries, with filters)
|
|
21
|
+
* leaderboard-summary Leaderboard KPI summary (totals, tier counts)
|
|
22
|
+
* leaderboard-user <id|email> Single user leaderboard profile with dimension breakdown
|
|
23
|
+
* leaderboard-tiers Tier distribution (name, count, %)
|
|
24
|
+
* leaderboard-dimensions Average scores per dimension (D1–D6)
|
|
25
|
+
* leaderboard-top <limit> Top N performers by total score (default 10)
|
|
26
|
+
* leaderboard-scores Score histogram in 10-point bins
|
|
27
|
+
* leaderboard-framework Static metadata: dimensions, tiers, intents, scoring
|
|
28
|
+
* leaderboard-snapshots List computation snapshots
|
|
29
|
+
* leaderboard-seasons Available seasonal periods (monthly/quarterly)
|
|
30
|
+
* cli-insights CLI usage: agents, repos, tools, errors, top-performers
|
|
31
|
+
* cli-insights-users CLI user classification & top spenders
|
|
32
|
+
* cli-insights-user <name> Detailed CLI profile for a single user
|
|
33
|
+
* cli-insights-projects CLI project classification & top projects by cost
|
|
34
|
+
* cli-insights-patterns Weekday + hourly + session-depth usage patterns
|
|
35
|
+
* users List users + activity
|
|
36
|
+
* projects-spending Per-project spending
|
|
37
|
+
* projects-activity Per-project activity time-series
|
|
38
|
+
* llms-usage LLM model usage breakdown
|
|
39
|
+
* tools-usage Tool usage analytics
|
|
40
|
+
* workflows Workflow execution analytics
|
|
41
|
+
* agents-usage Agent execution analytics
|
|
42
|
+
* embeddings-usage Embedding model usage
|
|
43
|
+
* assistants-chats Chat assistant conversations
|
|
44
|
+
* webhooks-usage Webhook invocation analytics
|
|
45
|
+
* mcp-servers MCP server usage
|
|
46
|
+
* mcp-servers-by-users MCP server usage broken down by user
|
|
47
|
+
* power-users Power user analytics
|
|
48
|
+
* knowledge-sharing Knowledge sharing metrics
|
|
49
|
+
* top-agents Top agents by usage
|
|
50
|
+
* top-workflows Top workflows by usage
|
|
51
|
+
* marketplace Assets published to marketplace
|
|
52
|
+
* budget Budget limits (soft + hard)
|
|
53
|
+
* spending Current user spending & budget (personal)
|
|
54
|
+
* spending-by-users Per-user spending breakdown (platform + cli)
|
|
55
|
+
* engagement Weekly engagement histogram
|
|
56
|
+
* litellm-customer [user_id] LiteLLM customer/info (needs LITELLM_URL + LITELLM_KEY)
|
|
57
|
+
* litellm-spend LiteLLM /spend/logs (needs LITELLM_URL + LITELLM_KEY)
|
|
58
|
+
* litellm-keys LiteLLM /key/info for all virtual keys
|
|
59
|
+
* custom <path> Fallback for unlisted endpoints — prefer a named command if one exists
|
|
60
|
+
* enrich-csv <file> Read CSV/Excel, lookup each user in LiteLLM, output enriched data
|
|
61
|
+
*
|
|
62
|
+
* Filters (most commands):
|
|
63
|
+
* --time-period last_hour | last_6_hours | last_24_hours | last_7_days | last_30_days | last_60_days | last_year
|
|
64
|
+
* --start-date ISO8601 e.g. 2024-01-01T00:00:00
|
|
65
|
+
* --end-date ISO8601
|
|
66
|
+
* --users comma-separated usernames
|
|
67
|
+
* --projects comma-separated project names
|
|
68
|
+
* --page page number (default 1)
|
|
69
|
+
* --per-page results per page (default 50)
|
|
70
|
+
* --output json | table | csv (default json)
|
|
71
|
+
* --pretty pretty-print JSON (flag)
|
|
72
|
+
*
|
|
73
|
+
* Leaderboard-specific filters:
|
|
74
|
+
* --view current | monthly | quarterly (default current)
|
|
75
|
+
* --season-key e.g. 2026-03 or 2026-Q1
|
|
76
|
+
* --snapshot-id explicit snapshot ID
|
|
77
|
+
* --tier pioneer | expert | advanced | practitioner | newcomer
|
|
78
|
+
* --intent cli_focused | platform_focused | hybrid | sdlc_unicorn
|
|
79
|
+
* --search partial name/email search
|
|
80
|
+
* --sort-by rank | total_score | user_name | tier_level (default rank)
|
|
81
|
+
* --sort-order asc | desc (default asc)
|
|
82
|
+
* --limit max entries for top-performers (default 10, max 50)
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
import { createDecipheriv, createHash } from 'crypto';
|
|
86
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
87
|
+
import { homedir, hostname, platform, arch } from 'os';
|
|
88
|
+
import { join, resolve, dirname } from 'path';
|
|
89
|
+
import { fileURLToPath } from 'url';
|
|
90
|
+
|
|
91
|
+
// ─── Argument Parsing ────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
const args = process.argv.slice(2);
|
|
94
|
+
const command = args[0];
|
|
95
|
+
|
|
96
|
+
function parseArgs(argv) {
|
|
97
|
+
const opts = { _: [] };
|
|
98
|
+
for (let i = 0; i < argv.length; i++) {
|
|
99
|
+
if (argv[i].startsWith('--')) {
|
|
100
|
+
const key = argv[i].slice(2).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
101
|
+
const val = argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : true;
|
|
102
|
+
opts[key] = val;
|
|
103
|
+
} else {
|
|
104
|
+
opts._.push(argv[i]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return opts;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const opts = parseArgs(args.slice(1));
|
|
111
|
+
|
|
112
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
const CODEMIE_HOME = process.env.CODEMIE_HOME || join(homedir(), '.codemie');
|
|
115
|
+
const CREDENTIALS_DIR = join(CODEMIE_HOME, 'credentials');
|
|
116
|
+
const GLOBAL_SSO_FILE = join(CODEMIE_HOME, 'sso-credentials.enc');
|
|
117
|
+
const CONFIG_FILE = join(CODEMIE_HOME, 'codemie-cli.config.json');
|
|
118
|
+
|
|
119
|
+
// ─── Encryption (matches CredentialStore in codemie-code exactly) ────────────
|
|
120
|
+
|
|
121
|
+
function getAESKey() {
|
|
122
|
+
const machineId = hostname() + platform() + arch();
|
|
123
|
+
const encryptionKeyHex = createHash('sha256').update(machineId).digest('hex');
|
|
124
|
+
return createHash('sha256').update(encryptionKeyHex).digest();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function decrypt(text) {
|
|
128
|
+
const colonIndex = text.indexOf(':');
|
|
129
|
+
if (colonIndex === -1) return null;
|
|
130
|
+
const ivHex = text.slice(0, colonIndex);
|
|
131
|
+
const encryptedHex = text.slice(colonIndex + 1);
|
|
132
|
+
const iv = Buffer.from(ivHex, 'hex');
|
|
133
|
+
const key = getAESKey();
|
|
134
|
+
const decipher = createDecipheriv('aes-256-cbc', key, iv);
|
|
135
|
+
let decrypted = decipher.update(encryptedHex, 'hex', 'utf8');
|
|
136
|
+
decrypted += decipher.final('utf8');
|
|
137
|
+
return decrypted;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function readEncryptedFile(filePath) {
|
|
141
|
+
if (!existsSync(filePath)) return null;
|
|
142
|
+
try {
|
|
143
|
+
const text = readFileSync(filePath, 'utf8');
|
|
144
|
+
const json = decrypt(text);
|
|
145
|
+
return json ? JSON.parse(json) : null;
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ─── URL Normalization ──────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
function normalizeToBase(url) {
|
|
154
|
+
try {
|
|
155
|
+
const parsed = new URL(url);
|
|
156
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
157
|
+
} catch {
|
|
158
|
+
return url;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function getUrlStorageKey(baseUrl) {
|
|
163
|
+
const normalized = baseUrl.replace(/\/$/, '').toLowerCase();
|
|
164
|
+
return `sso-${createHash('sha256').update(normalized).digest('hex')}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ─── Security helpers ───────────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
const SENSITIVE_PATTERNS = /\b(Bearer\s+\S+|sk-[a-zA-Z0-9_-]{20,}|token[=:]\S+|cookie[=:]\S+|password[=:]\S+|api[_-]?key[=:]\S+)\b/gi;
|
|
170
|
+
|
|
171
|
+
function sanitizeErrorText(text) {
|
|
172
|
+
if (!text) return '';
|
|
173
|
+
return text.replace(SENSITIVE_PATTERNS, '[REDACTED]');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const REDACT_KEYS = new Set(['token', 'key', 'api_key', 'secret', 'master_key', 'hashed_token']);
|
|
177
|
+
|
|
178
|
+
function redactSensitiveFields(data) {
|
|
179
|
+
if (data === null || data === undefined) return data;
|
|
180
|
+
if (Array.isArray(data)) return data.map(redactSensitiveFields);
|
|
181
|
+
if (typeof data === 'object') {
|
|
182
|
+
const out = {};
|
|
183
|
+
for (const [k, v] of Object.entries(data)) {
|
|
184
|
+
if (REDACT_KEYS.has(k) && typeof v === 'string' && v.length > 0) {
|
|
185
|
+
out[k] = v.slice(0, 4) + '...' + v.slice(-4);
|
|
186
|
+
} else {
|
|
187
|
+
out[k] = redactSensitiveFields(v);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
return data;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ─── Config Loading ──────────────────────────────────────────────────────────
|
|
196
|
+
|
|
197
|
+
function loadConfig() {
|
|
198
|
+
const localConfig = join(process.cwd(), '.codemie', 'codemie-cli.config.json');
|
|
199
|
+
const configs = [];
|
|
200
|
+
if (existsSync(CONFIG_FILE)) {
|
|
201
|
+
try { configs.push(JSON.parse(readFileSync(CONFIG_FILE, 'utf8'))); } catch {}
|
|
202
|
+
}
|
|
203
|
+
if (existsSync(localConfig)) {
|
|
204
|
+
try { configs.push(JSON.parse(readFileSync(localConfig, 'utf8'))); } catch {}
|
|
205
|
+
}
|
|
206
|
+
if (configs.length === 0) return null;
|
|
207
|
+
return configs[configs.length - 1] || configs[0];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getActiveProfile(config) {
|
|
211
|
+
if (!config) return null;
|
|
212
|
+
if (config.version === 2 && config.profiles) {
|
|
213
|
+
const name = config.activeProfile || Object.keys(config.profiles)[0];
|
|
214
|
+
return config.profiles[name] || null;
|
|
215
|
+
}
|
|
216
|
+
return config;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ─── Credential Resolution ──────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
function resolveAuth() {
|
|
222
|
+
const SENTINEL_KEYS = new Set(['sso-provided', 'proxy-handled']);
|
|
223
|
+
if (process.env.CODEMIE_API_KEY && !SENTINEL_KEYS.has(process.env.CODEMIE_API_KEY) && process.env.CODEMIE_URL) {
|
|
224
|
+
const baseUrl = process.env.CODEMIE_URL.replace(/\/$/, '');
|
|
225
|
+
const apiUrl = baseUrl.includes('/code-assistant-api') ? baseUrl : `${baseUrl}/code-assistant-api`;
|
|
226
|
+
return { type: 'bearer', token: process.env.CODEMIE_API_KEY, baseUrl: apiUrl };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const config = loadConfig();
|
|
230
|
+
const profile = getActiveProfile(config);
|
|
231
|
+
const codeMieUrl = process.env.CODEMIE_URL || profile?.codeMieUrl || profile?.baseUrl;
|
|
232
|
+
if (!codeMieUrl) return null;
|
|
233
|
+
|
|
234
|
+
const normalizedBase = normalizeToBase(codeMieUrl);
|
|
235
|
+
const storageKey = getUrlStorageKey(normalizedBase);
|
|
236
|
+
const perUrlFile = join(CREDENTIALS_DIR, `${storageKey}.enc`);
|
|
237
|
+
let credentials = readEncryptedFile(perUrlFile);
|
|
238
|
+
|
|
239
|
+
if (!credentials) {
|
|
240
|
+
credentials = readEncryptedFile(GLOBAL_SSO_FILE);
|
|
241
|
+
if (credentials && credentials.apiUrl) {
|
|
242
|
+
const credentialBase = normalizeToBase(credentials.apiUrl);
|
|
243
|
+
if (credentialBase !== normalizedBase) credentials = null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!credentials || !credentials.cookies || !credentials.apiUrl) {
|
|
248
|
+
if (profile?.apiKey) {
|
|
249
|
+
const apiUrl = codeMieUrl.includes('/code-assistant-api')
|
|
250
|
+
? codeMieUrl
|
|
251
|
+
: `${codeMieUrl}/code-assistant-api`;
|
|
252
|
+
return { type: 'bearer', token: profile.apiKey, baseUrl: apiUrl };
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (credentials.expiresAt && Date.now() > credentials.expiresAt) {
|
|
258
|
+
process.stderr.write('[analytics-cli] SSO credentials expired. Run `codemie setup` to re-authenticate.\n');
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const cookieStr = Object.entries(credentials.cookies)
|
|
263
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
264
|
+
.join('; ');
|
|
265
|
+
|
|
266
|
+
return { type: 'cookie', cookie: cookieStr, baseUrl: credentials.apiUrl };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ─── HTTP Client ─────────────────────────────────────────────────────────────
|
|
270
|
+
|
|
271
|
+
async function apiFetch(url, { method = 'GET', body, auth, extraHeaders = {} } = {}) {
|
|
272
|
+
const headers = {
|
|
273
|
+
'Content-Type': 'application/json',
|
|
274
|
+
'X-CodeMie-Client': 'codemie-cli',
|
|
275
|
+
...extraHeaders,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
if (auth?.type === 'cookie') {
|
|
279
|
+
headers['Cookie'] = auth.cookie;
|
|
280
|
+
} else if (auth?.type === 'bearer') {
|
|
281
|
+
headers['Authorization'] = `Bearer ${auth.token}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const fetchOpts = { method, headers };
|
|
285
|
+
if (body) fetchOpts.body = JSON.stringify(body);
|
|
286
|
+
|
|
287
|
+
const res = await fetch(url, fetchOpts);
|
|
288
|
+
|
|
289
|
+
if (!res.ok) {
|
|
290
|
+
const text = await res.text().catch(() => '');
|
|
291
|
+
// Strip the URL to avoid leaking query params that may contain tokens
|
|
292
|
+
const safeUrl = url.split('?')[0];
|
|
293
|
+
throw new Error(`HTTP ${res.status} ${res.statusText} for ${safeUrl}\n${sanitizeErrorText(text)}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const ct = res.headers.get('content-type') || '';
|
|
297
|
+
if (ct.includes('application/json')) return res.json();
|
|
298
|
+
return res.text();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ─── CodeMie API helpers ─────────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
function buildQuery(opts) {
|
|
304
|
+
const params = new URLSearchParams();
|
|
305
|
+
if (opts.timePeriod) params.set('time_period', opts.timePeriod);
|
|
306
|
+
if (opts.startDate) params.set('start_date', opts.startDate);
|
|
307
|
+
if (opts.endDate) params.set('end_date', opts.endDate);
|
|
308
|
+
if (opts.users) params.set('users', opts.users);
|
|
309
|
+
if (opts.projects) params.set('projects', opts.projects);
|
|
310
|
+
if (opts.page) params.set('page', opts.page);
|
|
311
|
+
if (opts.perPage) params.set('per_page', opts.perPage);
|
|
312
|
+
return params.toString() ? `?${params}` : '';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function buildLeaderboardQuery(opts) {
|
|
316
|
+
const params = new URLSearchParams();
|
|
317
|
+
if (opts.snapshotId) params.set('snapshot_id', opts.snapshotId);
|
|
318
|
+
if (opts.view) params.set('view', opts.view);
|
|
319
|
+
if (opts.seasonKey) params.set('season_key', opts.seasonKey);
|
|
320
|
+
if (opts.tier) params.set('tier', opts.tier);
|
|
321
|
+
if (opts.intent) params.set('intent', opts.intent);
|
|
322
|
+
if (opts.search) params.set('search', opts.search);
|
|
323
|
+
if (opts.sortBy) params.set('sort_by', opts.sortBy);
|
|
324
|
+
if (opts.sortOrder) params.set('sort_order', opts.sortOrder);
|
|
325
|
+
if (opts.page) params.set('page', opts.page);
|
|
326
|
+
if (opts.perPage) params.set('per_page', opts.perPage);
|
|
327
|
+
if (opts.limit) params.set('limit', opts.limit);
|
|
328
|
+
return params.toString() ? `?${params}` : '';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function analyticsGet(auth, path, opts) {
|
|
332
|
+
const qs = buildQuery(opts);
|
|
333
|
+
const url = `${auth.baseUrl}${path}${qs}`;
|
|
334
|
+
return apiFetch(url, { auth });
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async function analyticsLeaderboardGet(auth, path, opts) {
|
|
338
|
+
const qs = buildLeaderboardQuery(opts);
|
|
339
|
+
const url = `${auth.baseUrl}${path}${qs}`;
|
|
340
|
+
return apiFetch(url, { auth });
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async function analyticsPost(auth, path, bodyExtra = {}, opts) {
|
|
344
|
+
const body = {};
|
|
345
|
+
if (opts.timePeriod) body.time_period = opts.timePeriod;
|
|
346
|
+
if (opts.startDate) body.start_date = opts.startDate;
|
|
347
|
+
if (opts.endDate) body.end_date = opts.endDate;
|
|
348
|
+
if (opts.users) body.users = opts.users.split(',');
|
|
349
|
+
if (opts.projects) body.projects = opts.projects.split(',');
|
|
350
|
+
if (opts.page) body.page = parseInt(opts.page);
|
|
351
|
+
if (opts.perPage) body.per_page = parseInt(opts.perPage);
|
|
352
|
+
Object.assign(body, bodyExtra);
|
|
353
|
+
const url = `${auth.baseUrl}${path}`;
|
|
354
|
+
return apiFetch(url, { method: 'POST', body, auth });
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ─── LiteLLM helpers ─────────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
function getLiteLLMAuth() {
|
|
360
|
+
const url = process.env.LITELLM_URL;
|
|
361
|
+
const key = process.env.LITELLM_KEY;
|
|
362
|
+
if (!url || !key) {
|
|
363
|
+
throw new Error('LITELLM_URL and LITELLM_KEY env vars are required for LiteLLM commands');
|
|
364
|
+
}
|
|
365
|
+
return { url: url.replace(/\/$/, ''), key };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function litellmFetch(llm, path, { method = 'GET', body, params } = {}) {
|
|
369
|
+
let url = `${llm.url}${path}`;
|
|
370
|
+
if (params) {
|
|
371
|
+
const qs = new URLSearchParams(params).toString();
|
|
372
|
+
if (qs) url += `?${qs}`;
|
|
373
|
+
}
|
|
374
|
+
return apiFetch(url, {
|
|
375
|
+
method,
|
|
376
|
+
body,
|
|
377
|
+
auth: { type: 'bearer', token: llm.key },
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ─── CSV/Excel parsing ───────────────────────────────────────────────────────
|
|
382
|
+
|
|
383
|
+
async function parseInputFile(filePath) {
|
|
384
|
+
const resolvedPath = resolve(filePath);
|
|
385
|
+
if (!existsSync(resolvedPath)) {
|
|
386
|
+
throw new Error(`File not found: ${resolvedPath}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const ext = resolvedPath.split('.').pop().toLowerCase();
|
|
390
|
+
|
|
391
|
+
if (ext === 'csv') {
|
|
392
|
+
const text = readFileSync(resolvedPath, 'utf8');
|
|
393
|
+
const lines = text.trim().split(/\r?\n/);
|
|
394
|
+
const headers = lines[0].split(',').map(h => h.trim().replace(/^"|"$/g, ''));
|
|
395
|
+
return lines.slice(1).map(line => {
|
|
396
|
+
const vals = line.split(',').map(v => v.trim().replace(/^"|"$/g, ''));
|
|
397
|
+
return Object.fromEntries(headers.map((h, i) => [h, vals[i] ?? '']));
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (ext === 'xlsx' || ext === 'xls') {
|
|
402
|
+
try {
|
|
403
|
+
const XLSX = await import('xlsx').catch(() => null);
|
|
404
|
+
if (!XLSX) throw new Error('xlsx package not installed. Run: npm install -g xlsx');
|
|
405
|
+
const workbook = XLSX.default.readFile(resolvedPath);
|
|
406
|
+
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
407
|
+
return XLSX.default.utils.sheet_to_json(sheet);
|
|
408
|
+
} catch (e) {
|
|
409
|
+
throw new Error(`Cannot parse Excel file: ${e.message}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
throw new Error(`Unsupported file type: .${ext}. Use .csv, .xlsx, or .xls`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ─── Output helpers ──────────────────────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
function output(data) {
|
|
419
|
+
if (opts.save) {
|
|
420
|
+
const filePath = resolve(opts.save);
|
|
421
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
422
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
423
|
+
console.log(`✓ Saved → ${filePath}`);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const fmt = opts.output || 'json';
|
|
428
|
+
if (fmt === 'json' || !fmt) {
|
|
429
|
+
if (opts.pretty) {
|
|
430
|
+
console.log(JSON.stringify(data, null, 2));
|
|
431
|
+
} else {
|
|
432
|
+
console.log(JSON.stringify(data));
|
|
433
|
+
}
|
|
434
|
+
} else if (fmt === 'table') {
|
|
435
|
+
printTable(data);
|
|
436
|
+
} else if (fmt === 'csv') {
|
|
437
|
+
printCSV(data);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function printTable(data) {
|
|
442
|
+
const rows = Array.isArray(data) ? data : (data?.data || data?.items || [data]);
|
|
443
|
+
if (!rows.length) { console.log('(no data)'); return; }
|
|
444
|
+
const keys = Object.keys(rows[0]);
|
|
445
|
+
const widths = keys.map(k => Math.max(k.length, ...rows.map(r => String(r[k] ?? '').slice(0, 40).length)));
|
|
446
|
+
const header = keys.map((k, i) => k.padEnd(widths[i])).join(' | ');
|
|
447
|
+
console.log(header);
|
|
448
|
+
console.log(widths.map(w => '-'.repeat(w)).join('-+-'));
|
|
449
|
+
rows.forEach(row => {
|
|
450
|
+
console.log(keys.map((k, i) => String(row[k] ?? '').slice(0, 40).padEnd(widths[i])).join(' | '));
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function printCSV(data) {
|
|
455
|
+
const rows = Array.isArray(data) ? data : (data?.data || data?.items || [data]);
|
|
456
|
+
if (!rows.length) return;
|
|
457
|
+
const keys = Object.keys(rows[0]);
|
|
458
|
+
console.log(keys.join(','));
|
|
459
|
+
rows.forEach(row => console.log(keys.map(k => JSON.stringify(row[k] ?? '')).join(',')));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// ─── Commands ────────────────────────────────────────────────────────────────
|
|
463
|
+
|
|
464
|
+
// --- Summaries ---
|
|
465
|
+
|
|
466
|
+
async function cmdSummaries(auth) {
|
|
467
|
+
const data = await analyticsGet(auth, '/v1/analytics/summaries', opts);
|
|
468
|
+
output(data);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// --- Leaderboard family (uses /v1/analytics/leaderboard/*) ---
|
|
472
|
+
|
|
473
|
+
async function cmdLeaderboard(auth) {
|
|
474
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/entries', opts);
|
|
475
|
+
output(data);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async function cmdLeaderboardSummary(auth) {
|
|
479
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/summary', opts);
|
|
480
|
+
output(data);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function cmdLeaderboardUser(auth) {
|
|
484
|
+
const userId = opts._[0];
|
|
485
|
+
if (!userId) throw new Error('Usage: leaderboard-user <user_id_or_email>');
|
|
486
|
+
const qs = buildLeaderboardQuery(opts);
|
|
487
|
+
const url = `${auth.baseUrl}/v1/analytics/leaderboard/user/${encodeURIComponent(userId)}${qs}`;
|
|
488
|
+
const data = await apiFetch(url, { auth });
|
|
489
|
+
output(data);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async function cmdLeaderboardTiers(auth) {
|
|
493
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/tiers', opts);
|
|
494
|
+
output(data);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async function cmdLeaderboardDimensions(auth) {
|
|
498
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/dimensions', opts);
|
|
499
|
+
output(data);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async function cmdLeaderboardTop(auth) {
|
|
503
|
+
if (!opts.limit) opts.limit = opts._[0] || '10';
|
|
504
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/top-performers', opts);
|
|
505
|
+
output(data);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async function cmdLeaderboardScores(auth) {
|
|
509
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/scores', opts);
|
|
510
|
+
output(data);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async function cmdLeaderboardFramework(auth) {
|
|
514
|
+
const url = `${auth.baseUrl}/v1/analytics/leaderboard/framework`;
|
|
515
|
+
const data = await apiFetch(url, { auth });
|
|
516
|
+
output(data);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
async function cmdLeaderboardSnapshots(auth) {
|
|
520
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/snapshots', opts);
|
|
521
|
+
output(data);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function cmdLeaderboardSeasons(auth) {
|
|
525
|
+
if (!opts.view) throw new Error('Usage: leaderboard-seasons --view monthly|quarterly');
|
|
526
|
+
const data = await analyticsLeaderboardGet(auth, '/v1/analytics/leaderboard/seasons', opts);
|
|
527
|
+
output(data);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// --- CLI Insights family ---
|
|
531
|
+
|
|
532
|
+
async function cmdCliInsights(auth) {
|
|
533
|
+
const [summary, agents, llms, users, errors, repos, tools, topVersions, topEndpoints] = await Promise.all([
|
|
534
|
+
analyticsGet(auth, '/v1/analytics/cli-summary', opts),
|
|
535
|
+
analyticsGet(auth, '/v1/analytics/cli-agents', opts),
|
|
536
|
+
analyticsGet(auth, '/v1/analytics/cli-llms', opts),
|
|
537
|
+
analyticsGet(auth, '/v1/analytics/cli-users', opts),
|
|
538
|
+
analyticsGet(auth, '/v1/analytics/cli-errors', opts),
|
|
539
|
+
analyticsGet(auth, '/v1/analytics/cli-repositories', opts),
|
|
540
|
+
analyticsGet(auth, '/v1/analytics/cli-tools', opts),
|
|
541
|
+
analyticsGet(auth, '/v1/analytics/cli-top-versions', opts).catch(() => null),
|
|
542
|
+
analyticsGet(auth, '/v1/analytics/cli-top-proxy-endpoints', opts).catch(() => null),
|
|
543
|
+
]);
|
|
544
|
+
output({ summary, agents, llms, users, errors, repos, tools, topVersions, topEndpoints });
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async function cmdCliInsightsUsers(auth) {
|
|
548
|
+
const [classification, topBySpend, topSpenders, userList] = await Promise.all([
|
|
549
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-user-classification', opts).catch(() => null),
|
|
550
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-top-users-by-cost', opts).catch(() => null),
|
|
551
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-top-spenders', opts).catch(() => null),
|
|
552
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-users', opts).catch(() => null),
|
|
553
|
+
]);
|
|
554
|
+
output({ classification, topBySpend, topSpenders, userList });
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function cmdCliInsightsUser(auth) {
|
|
558
|
+
const userName = opts._[0] || opts.userName;
|
|
559
|
+
if (!userName) throw new Error('Usage: cli-insights-user <user_name> [--user-id <id>]');
|
|
560
|
+
const userQs = new URLSearchParams();
|
|
561
|
+
userQs.set('user_name', userName);
|
|
562
|
+
if (opts.userId) userQs.set('user_id', opts.userId);
|
|
563
|
+
// Add time filters
|
|
564
|
+
if (opts.timePeriod) userQs.set('time_period', opts.timePeriod);
|
|
565
|
+
if (opts.startDate) userQs.set('start_date', opts.startDate);
|
|
566
|
+
if (opts.endDate) userQs.set('end_date', opts.endDate);
|
|
567
|
+
const qs = userQs.toString() ? `?${userQs}` : '';
|
|
568
|
+
|
|
569
|
+
const base = auth.baseUrl;
|
|
570
|
+
const [detail, keyMetrics, tools, models, workflowIntent, classDetail, categoryBreakdown, repos] = await Promise.all([
|
|
571
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-detail${qs}`, { auth }),
|
|
572
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-key-metrics${qs}`, { auth }).catch(() => null),
|
|
573
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-tools${qs}`, { auth }).catch(() => null),
|
|
574
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-models${qs}`, { auth }).catch(() => null),
|
|
575
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-workflow-intent${qs}`, { auth }).catch(() => null),
|
|
576
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-classification-detail${qs}`, { auth }).catch(() => null),
|
|
577
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-category-breakdown${qs}`, { auth }).catch(() => null),
|
|
578
|
+
apiFetch(`${base}/v1/analytics/cli-insights-user-repositories${qs}`, { auth }).catch(() => null),
|
|
579
|
+
]);
|
|
580
|
+
output({ detail, keyMetrics, tools, models, workflowIntent, classDetail, categoryBreakdown, repos });
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
async function cmdCliInsightsProjects(auth) {
|
|
584
|
+
const [classification, topBySpend] = await Promise.all([
|
|
585
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-project-classification', opts).catch(() => null),
|
|
586
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-top-projects-by-cost', opts).catch(() => null),
|
|
587
|
+
]);
|
|
588
|
+
output({ classification, topBySpend });
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async function cmdCliInsightsPatterns(auth) {
|
|
592
|
+
const [weekday, hourly, sessionDepth] = await Promise.all([
|
|
593
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-weekday-pattern', opts).catch(() => null),
|
|
594
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-hourly-usage', opts).catch(() => null),
|
|
595
|
+
analyticsGet(auth, '/v1/analytics/cli-insights-session-depth', opts).catch(() => null),
|
|
596
|
+
]);
|
|
597
|
+
output({ weekday, hourly, sessionDepth });
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// --- Standard analytics ---
|
|
601
|
+
|
|
602
|
+
async function cmdUsers(auth) {
|
|
603
|
+
const [users, activity, uniqueDaily] = await Promise.all([
|
|
604
|
+
analyticsGet(auth, '/v1/analytics/users', opts),
|
|
605
|
+
analyticsGet(auth, '/v1/analytics/users-activity', opts),
|
|
606
|
+
analyticsGet(auth, '/v1/analytics/users-unique-daily', opts),
|
|
607
|
+
]);
|
|
608
|
+
output({ users, activity, uniqueDaily });
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
async function cmdProjectsSpending(auth) {
|
|
612
|
+
const data = await analyticsGet(auth, '/v1/analytics/projects-spending', opts);
|
|
613
|
+
output(data);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
async function cmdLlmsUsage(auth) {
|
|
617
|
+
const data = await analyticsGet(auth, '/v1/analytics/llms-usage', opts);
|
|
618
|
+
output(data);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
async function cmdToolsUsage(auth) {
|
|
622
|
+
const data = await analyticsGet(auth, '/v1/analytics/tools-usage', opts);
|
|
623
|
+
output(data);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
async function cmdWorkflows(auth) {
|
|
627
|
+
const data = await analyticsGet(auth, '/v1/analytics/workflows', opts);
|
|
628
|
+
output(data);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
async function cmdBudget(auth) {
|
|
632
|
+
const [soft, hard] = await Promise.all([
|
|
633
|
+
analyticsGet(auth, '/v1/analytics/budget-soft-limit', opts),
|
|
634
|
+
analyticsGet(auth, '/v1/analytics/budget-hard-limit', opts),
|
|
635
|
+
]);
|
|
636
|
+
output({ soft, hard });
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
async function cmdSpending(auth) {
|
|
640
|
+
const [spending, budgetUsage] = await Promise.all([
|
|
641
|
+
analyticsGet(auth, '/v1/analytics/spending', opts),
|
|
642
|
+
analyticsGet(auth, '/v1/analytics/budget_usage', opts).catch(() => null),
|
|
643
|
+
]);
|
|
644
|
+
output({ spending, budgetUsage });
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
async function cmdSpendingByUsers(auth) {
|
|
648
|
+
const [platform, cli] = await Promise.all([
|
|
649
|
+
analyticsGet(auth, '/v1/analytics/spending/by-users/platform', opts),
|
|
650
|
+
analyticsGet(auth, '/v1/analytics/spending/by-users/cli', opts),
|
|
651
|
+
]);
|
|
652
|
+
output({ platform, cli });
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
async function cmdEngagement(auth) {
|
|
656
|
+
const data = await analyticsGet(auth, '/v1/analytics/engagement/weekly-histogram', opts);
|
|
657
|
+
output(data);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
async function cmdProjectsActivity(auth) {
|
|
661
|
+
const [activity, uniqueDaily] = await Promise.all([
|
|
662
|
+
analyticsGet(auth, '/v1/analytics/projects-activity', opts),
|
|
663
|
+
analyticsGet(auth, '/v1/analytics/projects-unique-daily', opts).catch(() => null),
|
|
664
|
+
]);
|
|
665
|
+
output({ activity, uniqueDaily });
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
async function cmdAgentsUsage(auth) {
|
|
669
|
+
const data = await analyticsGet(auth, '/v1/analytics/agents-usage', opts);
|
|
670
|
+
output(data);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
async function cmdEmbeddingsUsage(auth) {
|
|
674
|
+
const data = await analyticsGet(auth, '/v1/analytics/embeddings-usage', opts);
|
|
675
|
+
output(data);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
async function cmdAssistantsChats(auth) {
|
|
679
|
+
const data = await analyticsGet(auth, '/v1/analytics/assistants-chats', opts);
|
|
680
|
+
output(data);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async function cmdWebhooksUsage(auth) {
|
|
684
|
+
const data = await analyticsGet(auth, '/v1/analytics/webhooks-invocation', opts);
|
|
685
|
+
output(data);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
async function cmdMcpServers(auth) {
|
|
689
|
+
const data = await analyticsGet(auth, '/v1/analytics/mcp-servers', opts);
|
|
690
|
+
output(data);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
async function cmdMcpServersByUsers(auth) {
|
|
694
|
+
const data = await analyticsGet(auth, '/v1/analytics/mcp-servers-by-users', opts);
|
|
695
|
+
output(data);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async function cmdPowerUsers(auth) {
|
|
699
|
+
const data = await analyticsGet(auth, '/v1/analytics/power-users', opts);
|
|
700
|
+
output(data);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
async function cmdKnowledgeSharing(auth) {
|
|
704
|
+
const data = await analyticsGet(auth, '/v1/analytics/knowledge-sharing', opts);
|
|
705
|
+
output(data);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
async function cmdTopAgents(auth) {
|
|
709
|
+
const data = await analyticsGet(auth, '/v1/analytics/top-agents-usage', opts);
|
|
710
|
+
output(data);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
async function cmdTopWorkflows(auth) {
|
|
714
|
+
const data = await analyticsGet(auth, '/v1/analytics/top-workflow-usage', opts);
|
|
715
|
+
output(data);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
async function cmdMarketplace(auth) {
|
|
719
|
+
const data = await analyticsGet(auth, '/v1/analytics/published-to-marketplace', opts);
|
|
720
|
+
output(data);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// --- Custom ---
|
|
724
|
+
|
|
725
|
+
async function cmdCustom(auth) {
|
|
726
|
+
const path = opts._[0];
|
|
727
|
+
if (!path) throw new Error(
|
|
728
|
+
'Usage: custom <endpoint-path>\n' +
|
|
729
|
+
'NOTE: prefer a named command over custom when one exists (run with "help" to list them).\n' +
|
|
730
|
+
'Example: custom /v1/analytics/some-new-endpoint'
|
|
731
|
+
);
|
|
732
|
+
const method = (opts.method || 'GET').toUpperCase();
|
|
733
|
+
let data;
|
|
734
|
+
if (method === 'POST') {
|
|
735
|
+
data = await analyticsPost(auth, path, {}, opts);
|
|
736
|
+
} else {
|
|
737
|
+
data = await analyticsGet(auth, path, opts);
|
|
738
|
+
}
|
|
739
|
+
output(data);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// --- LiteLLM ---
|
|
743
|
+
|
|
744
|
+
async function cmdLitellmCustomer() {
|
|
745
|
+
const llm = getLiteLLMAuth();
|
|
746
|
+
const userId = opts._[0] || opts.user;
|
|
747
|
+
const params = userId ? { user_id: userId } : undefined;
|
|
748
|
+
const data = await litellmFetch(llm, '/customer/info', { params });
|
|
749
|
+
output(data);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
async function cmdLitellmSpend() {
|
|
753
|
+
const llm = getLiteLLMAuth();
|
|
754
|
+
const params = {};
|
|
755
|
+
if (opts.startDate) params.start_date = opts.startDate;
|
|
756
|
+
if (opts.endDate) params.end_date = opts.endDate;
|
|
757
|
+
if (opts.users) params.user_id = opts.users;
|
|
758
|
+
const data = await litellmFetch(llm, '/spend/logs', { params });
|
|
759
|
+
output(data);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
async function cmdLitellmKeys() {
|
|
763
|
+
const llm = getLiteLLMAuth();
|
|
764
|
+
const data = await litellmFetch(llm, '/key/info');
|
|
765
|
+
output(redactSensitiveFields(data));
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
async function cmdEnrichCSV() {
|
|
769
|
+
const filePath = opts._[0];
|
|
770
|
+
if (!filePath) throw new Error('Usage: enrich-csv <path-to-file.csv|xlsx>');
|
|
771
|
+
|
|
772
|
+
const llm = getLiteLLMAuth();
|
|
773
|
+
const rows = await parseInputFile(filePath);
|
|
774
|
+
|
|
775
|
+
const userCol = ['user', 'user_id', 'email', 'username', 'User', 'Email'].find(c => rows[0]?.[c] !== undefined);
|
|
776
|
+
if (!userCol) {
|
|
777
|
+
throw new Error(`Cannot find user column. Available columns: ${Object.keys(rows[0] || {}).join(', ')}`);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const enriched = [];
|
|
781
|
+
for (const row of rows) {
|
|
782
|
+
const userId = row[userCol];
|
|
783
|
+
let litellmInfo = null;
|
|
784
|
+
try {
|
|
785
|
+
litellmInfo = await litellmFetch(llm, '/customer/info', { params: { user_id: userId } });
|
|
786
|
+
} catch {
|
|
787
|
+
litellmInfo = { error: 'not_found' };
|
|
788
|
+
}
|
|
789
|
+
enriched.push({
|
|
790
|
+
...row,
|
|
791
|
+
litellm_spend: litellmInfo?.spend ?? litellmInfo?.total_spend ?? null,
|
|
792
|
+
litellm_max_budget: litellmInfo?.max_budget ?? null,
|
|
793
|
+
litellm_models: Array.isArray(litellmInfo?.allowed_model_region)
|
|
794
|
+
? litellmInfo.allowed_model_region.join(';')
|
|
795
|
+
: null,
|
|
796
|
+
litellm_raw: JSON.stringify(litellmInfo),
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
output(enriched);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
804
|
+
|
|
805
|
+
const LITELLM_COMMANDS = ['litellm-customer', 'litellm-spend', 'litellm-keys'];
|
|
806
|
+
|
|
807
|
+
async function main() {
|
|
808
|
+
if (!command || command === 'help') {
|
|
809
|
+
const src = readFileSync(fileURLToPath(import.meta.url), 'utf8');
|
|
810
|
+
const docBlock = src.match(/\/\*\*([\s\S]*?)\*\//)?.[0] ?? '';
|
|
811
|
+
console.log(docBlock);
|
|
812
|
+
process.exit(0);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// LiteLLM-only commands
|
|
816
|
+
if (command === 'enrich-csv') return cmdEnrichCSV();
|
|
817
|
+
|
|
818
|
+
if (LITELLM_COMMANDS.includes(command)) {
|
|
819
|
+
switch (command) {
|
|
820
|
+
case 'litellm-customer': return cmdLitellmCustomer();
|
|
821
|
+
case 'litellm-spend': return cmdLitellmSpend();
|
|
822
|
+
case 'litellm-keys': return cmdLitellmKeys();
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// CodeMie API commands
|
|
827
|
+
const auth = resolveAuth();
|
|
828
|
+
if (!auth) {
|
|
829
|
+
throw new Error(
|
|
830
|
+
'No CodeMie credentials found. Either:\n' +
|
|
831
|
+
' 1. Run `codemie setup` with SSO provider to store credentials\n' +
|
|
832
|
+
' 2. Set CODEMIE_API_KEY + CODEMIE_URL env vars'
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
switch (command) {
|
|
837
|
+
// Summaries
|
|
838
|
+
case 'summaries': return cmdSummaries(auth);
|
|
839
|
+
|
|
840
|
+
// Leaderboard
|
|
841
|
+
case 'leaderboard': return cmdLeaderboard(auth);
|
|
842
|
+
case 'leaderboard-summary': return cmdLeaderboardSummary(auth);
|
|
843
|
+
case 'leaderboard-user': return cmdLeaderboardUser(auth);
|
|
844
|
+
case 'leaderboard-tiers': return cmdLeaderboardTiers(auth);
|
|
845
|
+
case 'leaderboard-dimensions': return cmdLeaderboardDimensions(auth);
|
|
846
|
+
case 'leaderboard-top': return cmdLeaderboardTop(auth);
|
|
847
|
+
case 'leaderboard-scores': return cmdLeaderboardScores(auth);
|
|
848
|
+
case 'leaderboard-framework': return cmdLeaderboardFramework(auth);
|
|
849
|
+
case 'leaderboard-snapshots': return cmdLeaderboardSnapshots(auth);
|
|
850
|
+
case 'leaderboard-seasons': return cmdLeaderboardSeasons(auth);
|
|
851
|
+
|
|
852
|
+
// CLI Insights
|
|
853
|
+
case 'cli-insights': return cmdCliInsights(auth);
|
|
854
|
+
case 'cli-insights-users': return cmdCliInsightsUsers(auth);
|
|
855
|
+
case 'cli-insights-user': return cmdCliInsightsUser(auth);
|
|
856
|
+
case 'cli-insights-projects': return cmdCliInsightsProjects(auth);
|
|
857
|
+
case 'cli-insights-patterns': return cmdCliInsightsPatterns(auth);
|
|
858
|
+
|
|
859
|
+
// Standard analytics
|
|
860
|
+
case 'users': return cmdUsers(auth);
|
|
861
|
+
case 'projects-spending': return cmdProjectsSpending(auth);
|
|
862
|
+
case 'projects-activity': return cmdProjectsActivity(auth);
|
|
863
|
+
case 'llms-usage': return cmdLlmsUsage(auth);
|
|
864
|
+
case 'tools-usage': return cmdToolsUsage(auth);
|
|
865
|
+
case 'workflows': return cmdWorkflows(auth);
|
|
866
|
+
case 'agents-usage': return cmdAgentsUsage(auth);
|
|
867
|
+
case 'embeddings-usage': return cmdEmbeddingsUsage(auth);
|
|
868
|
+
case 'assistants-chats': return cmdAssistantsChats(auth);
|
|
869
|
+
case 'webhooks-usage': return cmdWebhooksUsage(auth);
|
|
870
|
+
case 'mcp-servers': return cmdMcpServers(auth);
|
|
871
|
+
case 'mcp-servers-by-users': return cmdMcpServersByUsers(auth);
|
|
872
|
+
case 'power-users': return cmdPowerUsers(auth);
|
|
873
|
+
case 'knowledge-sharing': return cmdKnowledgeSharing(auth);
|
|
874
|
+
case 'top-agents': return cmdTopAgents(auth);
|
|
875
|
+
case 'top-workflows': return cmdTopWorkflows(auth);
|
|
876
|
+
case 'marketplace': return cmdMarketplace(auth);
|
|
877
|
+
case 'budget': return cmdBudget(auth);
|
|
878
|
+
case 'spending': return cmdSpending(auth);
|
|
879
|
+
case 'spending-by-users': return cmdSpendingByUsers(auth);
|
|
880
|
+
case 'engagement': return cmdEngagement(auth);
|
|
881
|
+
|
|
882
|
+
// Custom — use only for endpoints without a dedicated command
|
|
883
|
+
case 'custom': return cmdCustom(auth);
|
|
884
|
+
|
|
885
|
+
default:
|
|
886
|
+
throw new Error(`Unknown command: ${command}\nRun with 'help' for usage.`);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
main().catch(err => {
|
|
891
|
+
console.error('[analytics-cli] Error:', err.message);
|
|
892
|
+
process.exit(1);
|
|
893
|
+
});
|