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
2 changes: 1 addition & 1 deletion packages/cli/src/acp-integration/acpAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class QwenAgent implements Agent {
return {
protocolVersion: PROTOCOL_VERSION,
agentInfo: {
name: 'qwen-code',
name: 'proto-cli',
title: 'proto',
version,
},
Expand Down
14 changes: 0 additions & 14 deletions packages/core/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { setGeminiMdFilename as mockSetGeminiMdFilename } from '../tools/memoryT
import {
DEFAULT_TELEMETRY_TARGET,
DEFAULT_OTLP_ENDPOINT,
QwenLogger,
} from '../telemetry/index.js';
import type {
ContentGenerator,
Expand Down Expand Up @@ -235,9 +234,6 @@ describe('Server Config (config.ts)', () => {
beforeEach(() => {
// Reset mocks if necessary
vi.clearAllMocks();
vi.spyOn(QwenLogger.prototype, 'logStartSessionEvent').mockImplementation(
async () => undefined,
);

// Setup default mock for resolveContentGeneratorConfigWithSources
vi.mocked(resolveContentGeneratorConfigWithSources).mockImplementation(
Expand Down Expand Up @@ -635,16 +631,6 @@ describe('Server Config (config.ts)', () => {
expect(config.getUsageStatisticsEnabled()).toBe(enabled);
},
);

it('logs the session start event', async () => {
const config = new Config({
...baseParams,
usageStatisticsEnabled: true,
});
await config.initialize();

expect(QwenLogger.prototype.logStartSessionEvent).toHaveBeenCalledOnce();
});
});

describe('Telemetry Settings', () => {
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/core/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ vi.mock('../telemetry/index.js', async (importOriginal) => {
...actual,
uiTelemetryService: mockUiTelemetryService,
// We keep the real implementations of logChatCompression, etc.
// but we can spy on QwenLogger if needed
};
});
vi.mock('../ide/ideContext.js');
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/core/openaiContentGenerator/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type { ErrorHandler, RequestContext } from './errorHandler.js';
import { createDebugLogger } from '../../utils/debugLogger.js';

const debugLogger = createDebugLogger('OPENAI_PIPELINE');
const tracer = trace.getTracer('qwen-code.openai-pipeline', '1.0.0');
const tracer = trace.getTracer('proto.openai-pipeline', '1.0.0');

/**
* Error thrown when the API returns an error embedded as stream content
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/extension/marketplace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async function fetchGitHubMarketplaceConfig(
// Primary: GitHub API (works for private repos, but has rate limits)
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/.claude-plugin/marketplace.json`;
const apiHeaders: Record<string, string> = {
'User-Agent': 'qwen-code',
'User-Agent': 'proto-cli',
Accept: 'application/vnd.github.v3.raw',
};
if (token) {
Expand All @@ -169,7 +169,7 @@ async function fetchGitHubMarketplaceConfig(
if (!content) {
const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/HEAD/.claude-plugin/marketplace.json`;
const rawHeaders: Record<string, string> = {
'User-Agent': 'qwen-code',
'User-Agent': 'proto-cli',
};
content = await fetchUrl(rawUrl, rawHeaders);
}
Expand Down
6 changes: 0 additions & 6 deletions packages/core/src/hooks/hookEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,16 +652,10 @@ export class HookEventHandler {
return config.name || 'unknown-hook';
}

/**
* Get hook name from execution result for telemetry
*/
private getHookNameFromResult(result: HookExecutionResult): string {
return this.getHookName(result.hookConfig);
}

/**
* Get hook type from execution result for telemetry
*/
private getHookTypeFromResult(result: HookExecutionResult): 'command' {
return result.hookConfig.type as 'command';
}
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ export type {
// Telemetry
// ============================================================================

export { QwenLogger } from './telemetry/qwen-logger/qwen-logger.js';
export * from './telemetry/index.js';
export {
logAuth,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/mcp/token-storage/file-token-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export class FileTokenStorage extends BaseTokenStorage {
}

private deriveEncryptionKey(): Buffer {
const salt = `${os.hostname()}-${os.userInfo().username}-qwen-code`;
return crypto.scryptSync('qwen-code-oauth', salt, 32);
const salt = `${os.hostname()}-${os.userInfo().username}-proto-cli`;
return crypto.scryptSync('proto-cli-oauth', salt, 32);
Comment on lines +26 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve a legacy decryption path for existing file tokens.

Changing both the scrypt password and salt changes the AES key, but the token file path stays ~/.qwen/mcp-oauth-tokens-v2.json. Existing encrypted files will now fail decrypt() and surface as Token file corrupted until users reauthenticate, so this needs a fallback or an on-read migration strategy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/mcp/token-storage/file-token-storage.ts` around lines 26 -
27, The change to the scrypt password/salt broke existing AES keys so decrypt()
will fail for legacy token files; implement a fallback read/migration: in the
file-token-storage module (where the key is derived and decrypt() is invoked,
e.g., the derive/crypto.scryptSync usage and decryptToken/decrypt functions),
first attempt decryption with the new key, and if that fails with a bad
padding/invalid auth tag error, attempt derivation with the previous password
and salt values and retry decryption; if the legacy key succeeds, re-encrypt and
overwrite the token file with the new key (so future reads use the new
derivation) and return the token, otherwise surface the existing "Token file
corrupted" error. Ensure you reference the same key-derivation call sites and
decrypt() path for the fallback and migration save.

}

private encrypt(text: string): string {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/mcp/token-storage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ export * from './base-token-storage.js';
export * from './file-token-storage.js';
export * from './hybrid-token-storage.js';

export const DEFAULT_SERVICE_NAME = 'qwen-code-oauth';
export const DEFAULT_SERVICE_NAME = 'proto-cli-oauth';
export const FORCE_ENCRYPTED_FILE_ENV_VAR =
'QWEN_CODE_FORCE_ENCRYPTED_FILE_STORAGE';
'PROTO_CLI_FORCE_ENCRYPTED_FILE_STORAGE';
Comment on lines +12 to +14

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

This token-storage rename still breaks existing installs.

DEFAULT_SERVICE_NAME = 'proto-cli-oauth' will strand credentials stored under the old service identifier, and packages/core/src/mcp/token-storage/hybrid-token-storage.ts:12-24 still reads QWEN_CODE_FORCE_FILE_STORAGE, so the new PROTO_CLI_FORCE_ENCRYPTED_FILE_STORAGE knob is ignored there. Please keep a legacy alias/fallback before flipping the default.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/mcp/token-storage/index.ts` around lines 12 - 14,
DEFAULT_SERVICE_NAME was changed to 'proto-cli-oauth' and the new env var
FORCE_ENCRYPTED_FILE_ENV_VAR was added, but old credentials and the legacy env
var (QWEN_CODE_FORCE_FILE_STORAGE) are still in use; restore compatibility by
adding a legacy fallback: keep the old service identifier as a fallback when
reading/storing credentials (use DEFAULT_SERVICE_NAME but if no creds found, try
the legacy name), and update the hybrid-token-storage logic (the code
referencing QWEN_CODE_FORCE_FILE_STORAGE) to accept either env var (check
FORCE_ENCRYPTED_FILE_ENV_VAR first, then QWEN_CODE_FORCE_FILE_STORAGE) so the
old knob is honored until the rename is fully rolled out.

84 changes: 42 additions & 42 deletions packages/core/src/telemetry/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,49 @@
* SPDX-License-Identifier: Apache-2.0
*/

export const SERVICE_NAME = 'qwen-code';
export const SERVICE_NAME = 'proto-cli';

export const EVENT_USER_PROMPT = 'qwen-code.user_prompt';
export const EVENT_USER_RETRY = 'qwen-code.user_retry';
export const EVENT_TOOL_CALL = 'qwen-code.tool_call';
export const EVENT_API_REQUEST = 'qwen-code.api_request';
export const EVENT_API_ERROR = 'qwen-code.api_error';
export const EVENT_API_CANCEL = 'qwen-code.api_cancel';
export const EVENT_API_RESPONSE = 'qwen-code.api_response';
export const EVENT_CLI_CONFIG = 'qwen-code.config';
export const EVENT_EXTENSION_DISABLE = 'qwen-code.extension_disable';
export const EVENT_EXTENSION_ENABLE = 'qwen-code.extension_enable';
export const EVENT_EXTENSION_INSTALL = 'qwen-code.extension_install';
export const EVENT_EXTENSION_UNINSTALL = 'qwen-code.extension_uninstall';
export const EVENT_EXTENSION_UPDATE = 'qwen-code.extension_update';
export const EVENT_FLASH_FALLBACK = 'qwen-code.flash_fallback';
export const EVENT_RIPGREP_FALLBACK = 'qwen-code.ripgrep_fallback';
export const EVENT_NEXT_SPEAKER_CHECK = 'qwen-code.next_speaker_check';
export const EVENT_SLASH_COMMAND = 'qwen-code.slash_command';
export const EVENT_IDE_CONNECTION = 'qwen-code.ide_connection';
export const EVENT_CHAT_COMPRESSION = 'qwen-code.chat_compression';
export const EVENT_INVALID_CHUNK = 'qwen-code.chat.invalid_chunk';
export const EVENT_CONTENT_RETRY = 'qwen-code.chat.content_retry';
export const EVENT_CONTENT_RETRY_FAILURE =
'qwen-code.chat.content_retry_failure';
export const EVENT_CONVERSATION_FINISHED = 'qwen-code.conversation_finished';
export const EVENT_MALFORMED_JSON_RESPONSE =
'qwen-code.malformed_json_response';
export const EVENT_FILE_OPERATION = 'qwen-code.file_operation';
export const EVENT_MODEL_SLASH_COMMAND = 'qwen-code.slash_command.model';
export const EVENT_SUBAGENT_EXECUTION = 'qwen-code.subagent_execution';
export const EVENT_SKILL_LAUNCH = 'qwen-code.skill_launch';
export const EVENT_AUTH = 'qwen-code.auth';
export const EVENT_USER_FEEDBACK = 'qwen-code.user_feedback';
export const EVENT_USER_PROMPT = 'proto.user_prompt';
export const EVENT_USER_RETRY = 'proto.user_retry';
export const EVENT_TOOL_CALL = 'proto.tool_call';
export const EVENT_API_REQUEST = 'proto.api_request';
Comment on lines +9 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Finish the proto.* rename in types.ts too.

These constants now define the new namespace, but several event classes in packages/core/src/telemetry/types.ts still hardcode stale names ('user_prompt', 'tool_call', 'api_request', 'arena_session_started', 'arena_agent_completed', 'arena_session_ended'). Any path that forwards the event instance before loggers.ts overwrites event.name will still emit the old identifiers, so the telemetry rebrand is only partial. Prefer importing these constants there instead of duplicating string literals.

Also applies to: 47-49

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/telemetry/constants.ts` around lines 9 - 12, Replace
hardcoded event name literals in packages/core/src/telemetry/types.ts with the
exported constants from packages/core/src/telemetry/constants.ts (e.g., use
EVENT_USER_PROMPT, EVENT_USER_RETRY, EVENT_TOOL_CALL, EVENT_API_REQUEST and any
arena-related constant equivalents) so classes that currently set event.name =
'user_prompt' / 'tool_call' / 'api_request' / 'arena_session_started' /
'arena_agent_completed' / 'arena_session_ended' instead import and use the
corresponding constants; update import statements at the top of types.ts and
assign the constants (not raw strings) in the relevant event classes and factory
functions to ensure all forwarded events carry the new proto.* namespace
consistently.

export const EVENT_API_ERROR = 'proto.api_error';
export const EVENT_API_CANCEL = 'proto.api_cancel';
export const EVENT_API_RESPONSE = 'proto.api_response';
export const EVENT_CLI_CONFIG = 'proto.config';
export const EVENT_EXTENSION_DISABLE = 'proto.extension_disable';
export const EVENT_EXTENSION_ENABLE = 'proto.extension_enable';
export const EVENT_EXTENSION_INSTALL = 'proto.extension_install';
export const EVENT_EXTENSION_UNINSTALL = 'proto.extension_uninstall';
export const EVENT_EXTENSION_UPDATE = 'proto.extension_update';
export const EVENT_FLASH_FALLBACK = 'proto.flash_fallback';
export const EVENT_RIPGREP_FALLBACK = 'proto.ripgrep_fallback';
export const EVENT_NEXT_SPEAKER_CHECK = 'proto.next_speaker_check';
export const EVENT_SLASH_COMMAND = 'proto.slash_command';
export const EVENT_IDE_CONNECTION = 'proto.ide_connection';
export const EVENT_CHAT_COMPRESSION = 'proto.chat_compression';
export const EVENT_INVALID_CHUNK = 'proto.chat.invalid_chunk';
export const EVENT_CONTENT_RETRY = 'proto.chat.content_retry';
export const EVENT_CONTENT_RETRY_FAILURE = 'proto.chat.content_retry_failure';
export const EVENT_CONVERSATION_FINISHED = 'proto.conversation_finished';
export const EVENT_MALFORMED_JSON_RESPONSE = 'proto.malformed_json_response';
export const EVENT_FILE_OPERATION = 'proto.file_operation';
export const EVENT_MODEL_SLASH_COMMAND = 'proto.slash_command.model';
export const EVENT_SUBAGENT_EXECUTION = 'proto.subagent_execution';
export const EVENT_SKILL_LAUNCH = 'proto.skill_launch';
export const EVENT_HOOK_CALL = 'proto.hook_call';
export const EVENT_LOOP_DETECTION_DISABLED = 'proto.loop_detection_disabled';
export const EVENT_AUTH = 'proto.auth';
export const EVENT_USER_FEEDBACK = 'proto.user_feedback';

// Prompt Suggestion Events
export const EVENT_PROMPT_SUGGESTION = 'qwen-code.prompt_suggestion';
export const EVENT_SPECULATION = 'qwen-code.speculation';
export const EVENT_PROMPT_SUGGESTION = 'proto.prompt_suggestion';
export const EVENT_SPECULATION = 'proto.speculation';

// Arena Events
export const EVENT_ARENA_SESSION_STARTED = 'qwen-code.arena_session_started';
export const EVENT_ARENA_AGENT_COMPLETED = 'qwen-code.arena_agent_completed';
export const EVENT_ARENA_SESSION_ENDED = 'qwen-code.arena_session_ended';
export const EVENT_ARENA_SESSION_STARTED = 'proto.arena_session_started';
export const EVENT_ARENA_AGENT_COMPLETED = 'proto.arena_agent_completed';
export const EVENT_ARENA_SESSION_ENDED = 'proto.arena_session_ended';

// Harness Events — captured for Langfuse fine-tuning datasets
export const EVENT_HARNESS_DOOM_LOOP = 'proto.harness.doom_loop';
Expand All @@ -59,7 +59,7 @@ export const EVENT_HARNESS_SPRINT_CONTRACT = 'proto.harness.sprint_contract';
export const EVENT_HARNESS_REMINDER = 'proto.harness.reminder';

// Performance Events
export const EVENT_STARTUP_PERFORMANCE = 'qwen-code.startup.performance';
export const EVENT_MEMORY_USAGE = 'qwen-code.memory.usage';
export const EVENT_PERFORMANCE_BASELINE = 'qwen-code.performance.baseline';
export const EVENT_PERFORMANCE_REGRESSION = 'qwen-code.performance.regression';
export const EVENT_STARTUP_PERFORMANCE = 'proto.startup.performance';
export const EVENT_MEMORY_USAGE = 'proto.memory.usage';
export const EVENT_PERFORMANCE_BASELINE = 'proto.performance.baseline';
export const EVENT_PERFORMANCE_REGRESSION = 'proto.performance.regression';
1 change: 0 additions & 1 deletion packages/core/src/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export {
ApiRequestPhase,
FileOperation,
} from './metrics.js';
export { QwenLogger } from './qwen-logger/qwen-logger.js';
export { sanitizeHookName } from './sanitize.js';
export {
startTurnSpan,
Expand Down
111 changes: 0 additions & 111 deletions packages/core/src/telemetry/integration.test.circular.ts

This file was deleted.

Loading
Loading