镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

feat(cli): introduce events commands - #97

Merged
bespoyasov merged 21 commits into
mainfrom
feat/events-commands
Oct 5, 2026
Merged

bespoyasov merged 21 commits into
mainfrom
feat/events-commands

Conversation

@bespoyasov

Copy link
Copy Markdown
Collaborator
  • Adds event management commands to the CLI: confidence events list|get|create|update|delete|usage
  • Adds generic MCP client in packages/core/src/mcp/ using @modelcontextprotocol/sdk, reusable for future command groups
  • Adds generic REST API client in packages/core/src/api/ (unused by events, ready for future commands)
  • Events commands call the confidence-flags MCP server tools (listEventDefinitions, getEventDefinition, createEventDefinition, updateEventDefinition, deleteEventDefinition, queryEventsUsage)
  • delete prompts for confirmation via @inquirer/confirm
  • Splits MSW test handlers into per-domain files under packages/testing/src/msw/handlers/
  • Exports extractRegion from core's auth barrel

Noticed that REST for events isn't supported yet, so had to introduce the MCP client in core, but I decided to keep the REST client in this PR as well (as it will be needed for other features anyways).


Commands

# List all event definitions
confidence events list

# Get details for a specific event
confidence events get page-viewed

# Create an event definition with typed fields
confidence events create --name purchase-completed \
  --field amount:double \
  --field currency:string \
  --field item_count:int

# Create from a JSON schema file
confidence events create --name signup --from-file schema.json

# Add fields to an existing event definition
confidence events update page-viewed --field referrer:string --field duration:double

# Show publish and validation stats (last 3 days)
confidence events usage page-viewed --days 3

# Delete an event definition (prompts for confirmation)
confidence events delete old-event

# JSON output (all commands)
confidence events list --json
confidence events get page-viewed --json

# Dry-run mode (create only)
confidence events create --name test-event --field page:string --dry-run

JSON output

--json wraps the MCP server's text response in a { "data": "..." } envelope. The output is human-readable text, not structured JSON, because the MCP server returns text formatted for AI agents. Structured JSON output might become available if a REST API is added.

@filipmyllari filipmyllari left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review notes (AI-assisted). Inline comments below.

Comment thread packages/cli/src/network/events.ts Outdated
Comment on lines +16 to +19
const result = await mcpCallTool(serverOpts(token), 'listEventDefinitions', {
pageToken: opts?.pageToken,
});
return extractText(result);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mcpCallTool returns isError: true results without throwing, and extractText just returns the error text. A server-side failure (e.g. get missing-event) is printed as success and exits 0. Check result.isError and throw (applies to all six wrappers).

Comment on lines +17 to +18
if (format === 'json') {
message(formatJson(text));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatJson(text) is given a string, so --json likely prints an escaped string literal instead of a JSON object (breaks \| jq). Parse first, e.g. parseToolJson. Same in get/create/update/usage.

Comment on lines +12 to +15
const confirmed = await confirm({
message: `Delete event definition "${name}"? This cannot be undone.`,
default: false,
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirm() runs unconditionally: it throws or hangs without a TTY (CI/pipes), and --dry-run is ignored. Add --yes, fail when non-interactive without it, and respect --dry-run.

Comment on lines +77 to +78
const schemaKey = `${type}Schema`;
return [name, { [schemaKey]: {} }];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field type isn't validated: amount:dobule sends { dobuleSchema: {} }. Check against an allow-list of supported types.

Comment on lines +35 to +36
const fieldSpecs = (argv.field as string[] | undefined) ?? [];
schema = Object.fromEntries(fieldSpecs.map(parseFieldArg));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No --field and no --from-file creates an event with an empty schema. update rejects this case, so create should too.

"@features/*": ["./src/features/*"],
"@output/*": ["./src/output/*"],
"@api/*": ["./src/api/*"]
"@network/*": ["./src/network/*"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@api/* was renamed to @network/*. CLAUDE.md and the cli skill still list @api/*.

): (argv: Record<string, unknown>) => Promise<void> {
return async (argv) => {
try {
await fn(argv as Record<string, unknown>);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant cast. Also, every handler already catches its own errors, so safely only covers requireAuth throwing.

@bespoyasov bespoyasov Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but safely also formats the error message as fail call. I'd say the unification is worth it, especially since an additional try-catch doesn't really affect the performance that much

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. As a catch-all it guarantees consistent fail output and exit code for anything that slips past the handler's own try/catch, so it's worth keeping. The only remaining nit is the redundant argv as Record<string, unknown> cast; feel free to ignore.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beep boop

import { formatJson } from '@output/json.js';
import { resolveFormat } from '@output/detect.js';
import { requireAuth } from './require-auth.js';
import { parseFieldArg } from './create.js';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing parseFieldArg from create.ts. Move it to its own field-spec.ts.

Comment on lines +16 to +21
const format = resolveFormat(extractFlags(argv));
if (format === 'json') {
message(formatJson(text));
} else {
message(text);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This format/print block is copy-pasted five times. Extract a helper like printToolText(argv, text).

Comment thread packages/cli/src/commands/events.ts Outdated
)
.demandCommand(
1,
'Available actions: setup, list, get, create, update, delete, usage. Run "confidence events --help" for details.',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The action list is hand-maintained and will drift as actions are added.

bespoyasov and others added 10 commits October 5, 2026 10:18
extractText ignored CallToolResult.isError, silently returning error
text as a successful response. Commands like `events get missing-event`
would print the error message to stdout and exit 0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Network wrappers now return raw CallToolResult, and a shared
printMcpResult helper handles format-aware output. For --json,
the MCP text is parsed so the envelope contains a real object
instead of an escaped string literal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add --force/-f to skip confirmation, fail with a clear message when
stdin is not a TTY and --force is absent, and respect --dry-run by
printing the request body without calling the server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reject unknown types like "dobule" with a clear error listing the
supported types (string, int, double, bool, struct).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without --field or --from-file the command silently sent an empty
schema. Now it fails early, matching the update command's behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reject --days outside 1-7 in events usage. Extract isDefined type
guard into shared-kernel to replace loose/truthiness undefined checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The MCP client sent a hard-coded '1.0.0' version. Add clientVersion
to McpClientOptions and pass the CLI package version so server-side
telemetry reflects the actual release.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moves the field parsing logic out of create.ts into its own module
so both create and update import from a shared location instead of
update reaching into create.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Yargs already prints available commands on missing action, so the
hard-coded lists in events and mcp were redundant and prone to drift.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bespoyasov

Copy link
Copy Markdown
Collaborator Author

Thanks for the review, @filipmyllari! Updated the code according to most of the comments, left responses to some 🙌

@bespoyasov
bespoyasov merged commit 00cd135 into main Oct 5, 2026
6 checks passed
@bespoyasov
bespoyasov deleted the feat/events-commands branch October 5, 2026 09:17
@github-actions github-actions Bot mentioned this pull request Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants