Files
openclaude/src/services/analytics/metadata.ts

173 lines
4.4 KiB
TypeScript

import { extname } from 'path'
import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from './index.js'
/**
* Local-only analytics helpers retained for compatibility after telemetry
* export removal. These helpers only sanitize or classify values in-process.
*/
export type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS }
export function sanitizeToolNameForAnalytics(
toolName: string,
): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS {
if (toolName.startsWith('mcp__')) {
return 'mcp_tool' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
return toolName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
export function isToolDetailsLoggingEnabled(): boolean {
return false
}
export function mcpToolDetailsForAnalytics(): {
mcpServerName?: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
mcpToolName?: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
} {
return {}
}
export function extractMcpToolDetails(toolName: string):
| {
serverName: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
mcpToolName: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
| undefined {
if (!toolName.startsWith('mcp__')) {
return undefined
}
const parts = toolName.split('__')
if (parts.length < 3) {
return undefined
}
const serverName = parts[1]
const mcpToolName = parts.slice(2).join('__')
if (!serverName || !mcpToolName) {
return undefined
}
return {
serverName:
serverName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
mcpToolName:
mcpToolName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
}
}
export function extractSkillName(
toolName: string,
input: unknown,
): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS | undefined {
if (toolName !== 'Skill') {
return undefined
}
if (
typeof input === 'object' &&
input !== null &&
'skill' in input &&
typeof (input as { skill: unknown }).skill === 'string'
) {
return (input as { skill: string })
.skill as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
return undefined
}
export function extractToolInputForTelemetry(
_input: unknown,
): string | undefined {
return undefined
}
const MAX_FILE_EXTENSION_LENGTH = 10
export function getFileExtensionForAnalytics(
filePath: string,
): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS | undefined {
const ext = extname(filePath).toLowerCase()
if (!ext || ext === '.') {
return undefined
}
const extension = ext.slice(1)
if (extension.length > MAX_FILE_EXTENSION_LENGTH) {
return 'other' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
return extension as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}
const FILE_COMMANDS = new Set([
'rm',
'mv',
'cp',
'touch',
'mkdir',
'chmod',
'chown',
'cat',
'head',
'tail',
'sort',
'stat',
'diff',
'wc',
'grep',
'rg',
'sed',
])
const COMPOUND_OPERATOR_REGEX = /\s*(?:&&|\|\||[;|])\s*/
const WHITESPACE_REGEX = /\s+/
export function getFileExtensionsFromBashCommand(
command: string,
simulatedSedEditFilePath?: string,
): AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS | undefined {
if (!command.includes('.') && !simulatedSedEditFilePath) {
return undefined
}
let result: string | undefined
const seen = new Set<string>()
if (simulatedSedEditFilePath) {
const ext = getFileExtensionForAnalytics(simulatedSedEditFilePath)
if (ext) {
seen.add(ext)
result = ext
}
}
for (const subcmd of command.split(COMPOUND_OPERATOR_REGEX)) {
if (!subcmd) continue
const tokens = subcmd.split(WHITESPACE_REGEX)
if (tokens.length < 2) continue
const firstToken = tokens[0]!
const slashIdx = firstToken.lastIndexOf('/')
const baseCmd = slashIdx >= 0 ? firstToken.slice(slashIdx + 1) : firstToken
if (!FILE_COMMANDS.has(baseCmd)) continue
for (let i = 1; i < tokens.length; i++) {
const arg = tokens[i]!
if (arg.charCodeAt(0) === 45) continue
const ext = getFileExtensionForAnalytics(arg)
if (ext && !seen.has(ext)) {
seen.add(ext)
result = result ? result + ',' + ext : ext
}
}
}
if (!result) {
return undefined
}
return result as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
}