feat: task-level commands, filter DSL, and chart create fix (v0.4.0)#1
feat: task-level commands, filter DSL, and chart create fix (v0.4.0)#1vishaldubey01 wants to merge 2 commits intomainfrom
Conversation
- Fix charts create to use query_dataset → save_chart_edits (create_chart doesn't exist)
- Add flag-based chart creation: --event, --metric, --interval, --range, --filter, --group-by, --save
- New filter DSL parser: "user:country is US" → MCP filter JSON
- New top-level amp funnel command with positional steps
- New top-level amp retention command
- Enhanced dashboard create with --charts flag for auto-layout
- Fix saveChart() to wrap in { charts: [...] } array as MCP expects
- Fix extractEditId to also check chartEditId field
- Bump version to 0.4.0
| w: "week", | ||
| m: "month", | ||
| }; | ||
| return { value, unit: unitMap[suffix] }; |
There was a problem hiding this comment.
Conversion window "m" maps to "month" not "minute"
High Severity
The unitMap in parseConversionWindow maps "m" to "month", but the help text documents "30m" as an example clearly meaning 30 minutes. A user passing --conversion-window 30m would get a 30-month conversion window instead of 30 minutes, producing wildly incorrect funnel results.
Additional Locations (1)
| "greater", | ||
| "less", | ||
| "is", | ||
| ]; |
There was a problem hiding this comment.
Operator order makes "set is not" unreachable
Medium Severity
In the OPERATORS array, "is not" (index 0) appears before "set is not" (index 4). Since the matching loop breaks on first match and " is not " is a substring found within " set is not ", a filter like "user:tags set is not active" matches "is not" first, yielding property key "tags set" instead of "tags" with operator "set is not".
Additional Locations (1)
| const valueStr = rest.slice(matchedIdx + 1 + matchedOp.length).trim(); | ||
| const values = valueStr ? valueStr.split(",").map((v) => v.trim()).filter(Boolean) : []; | ||
|
|
||
| const group_type = scope === "user" ? "User" : "User"; // always "User" for group_type |
There was a problem hiding this comment.
Dead ternary always returns same value for group_type
Low Severity
parseFilter has scope === "user" ? "User" : "User" which always evaluates to "User" regardless of scope. In contrast, parseGroupBy returns "User" or "Event" based on scope. This dead ternary either masks a real bug (event-scoped filters getting the wrong group_type) or is needlessly misleading.
- charts: wrap in {type, params} with app injected by queryDataset()
- funnel: use 'order' not 'funnelOrder', wrap events/segments in params
- retention: use 'retentionEvents' array, 'retentionMethod', 'retentionBrackets'
- mcp-client: inject definition.app from projectId in queryDataset()
- mcp-client: make description required (empty string) in saveChart()
All commands tested live against Amplitude MCP server.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| return obj; | ||
| } | ||
| return undefined; | ||
| } |
There was a problem hiding this comment.
buildDateRange is exported but never called anywhere
Low Severity
buildDateRange is a new exported function imported into charts.ts, funnel.ts, and retention.ts but never actually called in any of them. All three commands build date range parameters inline instead. This is dead code — both the function definition and all three imports are unused.


What changed
Overhaul of the CLI to add task-level commands that abstract away multi-step MCP workflows and raw JSON construction.
New features
Flag-based chart creation (
charts create)Filter DSL — human-readable filters instead of JSON:
Top-level
funnelcommandTop-level
retentioncommandamp retention --start-event _new --return-event _active \ --range "Last 90 Days" --interval 7 --method nday --saveDashboard create with
--chartsflagamp dashboards create --name "KPIs" --charts abc123 def456 ghi789 --cols 3Fixes
charts createfixed — now usesquery_dataset → save_chart_editsinstead of the nonexistentcreate_chartMCP toolsaveChart()in mcp-client.ts — wraps in{ charts: [...] }array as the MCP tool actually expectsextractEditId— also checkschartEditIdfield from query_dataset responsesNew files
src/utils/filters.ts— Filter DSL parser, group-by parser, conversion window parser, bracket parser, date range buildersrc/commands/funnel.ts— Top-level funnel commandsrc/commands/retention.ts— Top-level retention commandVersion bump
0.3.2 → 0.4.0
Note
Medium Risk
Changes the MCP request shapes for
query_datasetandsave_chart_editsand reroutescharts createthrough the query+save flow, which could break existing CLI workflows if the MCP contract differs. New top-level commands add additional dataset query paths that need validation across chart types and option parsing.Overview
Adds task-level CLI commands to build and query common analyses without hand-writing JSON: a top-level
amp funnelandamp retention, plus afiltersDSL (--filter,--group-by, conversion windows, bracket parsing) to generate chart definitions from flags.Reworks
charts createto support flag-based definitions and to query viaquery_datasetand optionally persist viasave_chart_edits(new--save), instead of directly callingcreate_chart;dashboards createcan now accept--chartsand auto-generate a row layout.Updates MCP client payloads to match expected tool contracts (
definition.appinjection forquery_dataset,{ charts: [...] }forsave_chart_edits) and improvesextractEditIdto recognizechartEditId; bumps version to0.4.0.Written by Cursor Bugbot for commit 3c13b4d. This will update automatically on new commits. Configure here.