Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/docs/content/docs/cli/usage-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ workspace ids, error messages, environment variable values, credentials, or the
address of the deployment you talk to. The report leaves your machine from a
separate short-lived process that is not given your API key.

## Location

The report carries no location of its own. The analytics service derives an
approximate location (country and city) from the address the report arrived
from, the way any HTTP request exposes one, and Sim uses that only to see
which regions use the CLI.

## Identity

The first run mints a random device id and stores it in `telemetry.json` under
Expand Down
16 changes: 15 additions & 1 deletion packages/sim-cli/src/telemetry/coding-agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,21 @@ describe('detectCodingAgent', () => {
})

it('lets an agent declare its own name over every vendor marker', () => {
expect(detectCodingAgent({ AI_AGENT: 'Some-Agent_2', CLAUDECODE: '1' })).toBe('some-agent_2')
expect(detectCodingAgent({ AI_AGENT: 'Some-Agent', CLAUDECODE: '1' })).toBe('some-agent')
})

it('keeps only the name from a declaration that carries a version and role', () => {
expect(detectCodingAgent({ AI_AGENT: 'claude-code_2-1-268_agent', CLAUDECODE: '1' })).toBe(
'claude-code'
)
})

it('keeps an underscored name that carries no version', () => {
expect(detectCodingAgent({ AI_AGENT: 'github_copilot_vscode_agent' })).toBe(
'github_copilot_vscode_agent'
)
expect(detectCodingAgent({ AI_AGENT: 'my_agent_2' })).toBe('my_agent')
expect(detectCodingAgent({ AI_AGENT: '_', CLAUDECODE: '1' })).toBe('_')
})

it('ignores a declared name that is not a well-formed token', () => {
Expand Down
19 changes: 17 additions & 2 deletions packages/sim-cli/src/telemetry/coding-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,26 @@ const AGENT_MARKERS: readonly AgentMarker[] = [
{ name: 'crush', matches: anyOf('CRUSH') },
]

/** A name an agent declared for itself, when it is a well-formed token. */
/**
* The shape Claude Code declares itself in: the name, its version with dots
* replaced by dashes, and a role, joined by underscores — the form the Stripe
* CLI's parser also expects. Only this shape is trimmed to its name; an
* underscore anywhere else is part of the name.
*/
const VERSIONED_DECLARATION = /^(.+?)_\d+(?:-\d+)*(?:_[a-z0-9-]+)?$/

/**
* A name an agent declared for itself, when it is a well-formed token.
*
* A declaration that carries a version and role (`claude-code_2-1-268_agent`)
* is reduced to its name, so a breakdown by agent does not split into one
* slice per release. Any other declaration is kept whole, underscores included.
*/
function declaredAgentName(value: string | undefined): string | undefined {
const trimmed = value?.trim().toLowerCase()
if (!trimmed || trimmed.length > MAX_AGENT_NAME_LENGTH) return undefined
return AGENT_NAME_PATTERN.test(trimmed) ? trimmed : undefined
if (!AGENT_NAME_PATTERN.test(trimmed)) return undefined
return VERSIONED_DECLARATION.exec(trimmed)?.[1] ?? trimmed
}

/**
Expand Down
Loading