Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
11 changes: 10 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@ export default tseslint.config(
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'no-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],
'no-restricted-syntax': [
'error',
...commonRestrictedSyntaxRules,
{
selector:
'UnaryExpression[operator="typeof"] > MemberExpression[computed=true][property.type="Literal"]',
message:
'Do not use typeof to check object properties. Define a TypeScript interface and a type guard function instead.',
},
],
'no-unsafe-finally': 'error',
'no-unused-expressions': 'off', // Disable base rule
'@typescript-eslint/no-unused-expressions': [
Expand Down
2 changes: 2 additions & 0 deletions packages/a2a-server/src/agent/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,9 @@ export class Task {
if (
part.kind !== 'data' ||
!part.data ||
// eslint-disable-next-line no-restricted-syntax
typeof part.data['callId'] !== 'string' ||
// eslint-disable-next-line no-restricted-syntax
typeof part.data['outcome'] !== 'string'
) {
return false;
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/commands/hooks/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function migrateClaudeHook(claudeHook: unknown): unknown {
migrated['command'] = hook['command'];

// Replace CLAUDE_PROJECT_DIR with GEMINI_PROJECT_DIR in command
// eslint-disable-next-line no-restricted-syntax
if (typeof migrated['command'] === 'string') {
migrated['command'] = migrated['command'].replace(
/\$CLAUDE_PROJECT_DIR/g,
Expand All @@ -93,6 +94,7 @@ function migrateClaudeHook(claudeHook: unknown): unknown {
}

// Map timeout field (Claude uses seconds, Gemini uses seconds)
// eslint-disable-next-line no-restricted-syntax
if ('timeout' in hook && typeof hook['timeout'] === 'number') {
migrated['timeout'] = hook['timeout'];
}
Expand Down Expand Up @@ -140,6 +142,7 @@ function migrateClaudeHooks(claudeConfig: unknown): Record<string, unknown> {
// Transform matcher
if (
'matcher' in definition &&
// eslint-disable-next-line no-restricted-syntax
typeof definition['matcher'] === 'string'
) {
migratedDef['matcher'] = transformMatcher(definition['matcher']);
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/test-utils/mockDebugLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function mockCoreDebugLogger<T extends Record<string, unknown>>(
return {
...actual,
coreEvents: {
// eslint-disable-next-line no-restricted-syntax
...(typeof actual['coreEvents'] === 'object' &&
actual['coreEvents'] !== null
? actual['coreEvents']
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/test-utils/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function isInkRenderMetrics(
typeof m === 'object' &&
m !== null &&
'output' in m &&
// eslint-disable-next-line no-restricted-syntax
typeof m['output'] === 'string'
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/ui/hooks/slashCommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,9 @@ export const useSlashCommandProcessor = (
const props = result.props as Record<string, unknown>;
if (
!props ||
// eslint-disable-next-line no-restricted-syntax
typeof props['name'] !== 'string' ||
// eslint-disable-next-line no-restricted-syntax
typeof props['displayName'] !== 'string' ||
!props['definition']
) {
Expand Down
10 changes: 6 additions & 4 deletions packages/cli/src/utils/activityLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,10 @@ export class ActivityLogger extends EventEmitter {

req.write = function (chunk: string | Uint8Array, ...etc: unknown[]) {
if (chunk) {
const arg0 = etc[0];
const encoding =
typeof etc[0] === 'string' && Buffer.isEncoding(etc[0])
? etc[0]
typeof arg0 === 'string' && Buffer.isEncoding(arg0)
? arg0
: undefined;
requestChunks.push(
Buffer.isBuffer(chunk)
Expand All @@ -519,9 +520,10 @@ export class ActivityLogger extends EventEmitter {
) {
const chunk = typeof chunkOrCb === 'function' ? undefined : chunkOrCb;
if (chunk) {
const arg0 = etc[0];
const encoding =
typeof etc[0] === 'string' && Buffer.isEncoding(etc[0])
? etc[0]
typeof arg0 === 'string' && Buffer.isEncoding(arg0)
? arg0
: undefined;
requestChunks.push(
Buffer.isBuffer(chunk)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export class BrowserAgentInvocation extends BaseToolInvocation<

if (
activity.type === 'THOUGHT_CHUNK' &&
// eslint-disable-next-line no-restricted-syntax
typeof activity.data['text'] === 'string'
) {
updateOutput(`🌐💭 ${activity.data['text']}`);
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/agents/browser/mcpToolWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ class TypeTextDeclarativeTool extends DeclarativeTool<
params: Record<string, unknown>,
): ToolInvocation<Record<string, unknown>, ToolResult> {
const submitKey =
// eslint-disable-next-line no-restricted-syntax
typeof params['submitKey'] === 'string' && params['submitKey']
? params['submitKey']
: undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/hooks/hookAggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export class HookAggregator {
// Extract additionalContext from various hook types
if (
'additionalContext' in specific &&
// eslint-disable-next-line no-restricted-syntax
typeof specific['additionalContext'] === 'string'
) {
contexts.push(specific['additionalContext']);
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/services/FolderTrustDiscoveryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,11 @@ export class FolderTrustDiscoveryService {
for (const event of Object.values(hooksConfig)) {
if (!Array.isArray(event)) continue;
for (const hook of event) {
if (this.isRecord(hook) && typeof hook['command'] === 'string') {
if (
this.isRecord(hook) &&
// eslint-disable-next-line no-restricted-syntax
typeof hook['command'] === 'string'
) {
hooks.add(hook['command']);
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/services/chatCompressionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@ async function truncateHistoryToBudget(
} else if (responseObj && typeof responseObj === 'object') {
if (
'output' in responseObj &&
// eslint-disable-next-line no-restricted-syntax
typeof responseObj['output'] === 'string'
) {
contentStr = responseObj['output'];
} else if (
'content' in responseObj &&
// eslint-disable-next-line no-restricted-syntax
typeof responseObj['content'] === 'string'
) {
contentStr = responseObj['content'];
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/services/loopDetectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -579,10 +579,12 @@ export class LoopDetectionService {
}

const flashConfidence =
// eslint-disable-next-line no-restricted-syntax
typeof flashResult['unproductive_state_confidence'] === 'number'
? flashResult['unproductive_state_confidence']
: 0;
const flashAnalysis =
// eslint-disable-next-line no-restricted-syntax
typeof flashResult['unproductive_state_analysis'] === 'string'
? flashResult['unproductive_state_analysis']
: '';
Expand Down Expand Up @@ -628,11 +630,13 @@ export class LoopDetectionService {

const mainModelConfidence =
mainModelResult &&
// eslint-disable-next-line no-restricted-syntax
typeof mainModelResult['unproductive_state_confidence'] === 'number'
? mainModelResult['unproductive_state_confidence']
: 0;
const mainModelAnalysis =
mainModelResult &&
// eslint-disable-next-line no-restricted-syntax
typeof mainModelResult['unproductive_state_analysis'] === 'string'
? mainModelResult['unproductive_state_analysis']
: undefined;
Expand Down Expand Up @@ -681,6 +685,7 @@ export class LoopDetectionService {

if (
result &&
// eslint-disable-next-line no-restricted-syntax
typeof result['unproductive_state_confidence'] === 'number'
) {
return result;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/telemetry/semantic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
}
} else if (part instanceof GenericPart) {
// eslint-disable-next-line no-restricted-syntax
if (part.type === 'executableCode' && typeof part['code'] === 'string') {
refs.push({
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
Expand All @@ -73,6 +74,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
} else if (
part.type === 'codeExecutionResult' &&
// eslint-disable-next-line no-restricted-syntax
typeof part['output'] === 'string'
) {
refs.push({
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/tools/mcp-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export function isMcpToolAnnotation(
return (
typeof annotation === 'object' &&
annotation !== null &&
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion, no-restricted-syntax
typeof (annotation as Record<string, unknown>)['_serverName'] === 'string'
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/editCorrector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ Return ONLY the corrected string in the specified JSON format with the key 'corr

if (
result &&
// eslint-disable-next-line no-restricted-syntax
typeof result['corrected_string_escaping'] === 'string' &&
result['corrected_string_escaping'].length > 0
) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/googleErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export function parseGoogleApiError(error: unknown): GoogleApiError | null {
}
// Basic structural check before casting.
// Since the proto definitions are loose, we primarily rely on @type presence.
// eslint-disable-next-line no-restricted-syntax
if (typeof detailObj['@type'] === 'string') {
// We can just cast it; the consumer will have to switch on @type
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/utils/oauth-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,19 +361,24 @@ async function parseTokenEndpointResponse(
data &&
typeof data === 'object' &&
'access_token' in data &&
// eslint-disable-next-line no-restricted-syntax
typeof (data as Record<string, unknown>)['access_token'] === 'string'
) {
const obj = data as Record<string, unknown>;
const result: OAuthTokenResponse = {
access_token: String(obj['access_token']),
token_type:
// eslint-disable-next-line no-restricted-syntax
typeof obj['token_type'] === 'string' ? obj['token_type'] : 'Bearer',
expires_in:
// eslint-disable-next-line no-restricted-syntax
typeof obj['expires_in'] === 'number' ? obj['expires_in'] : undefined,
refresh_token:
// eslint-disable-next-line no-restricted-syntax
typeof obj['refresh_token'] === 'string'
? obj['refresh_token']
: undefined,
// eslint-disable-next-line no-restricted-syntax
scope: typeof obj['scope'] === 'string' ? obj['scope'] : undefined,
};
return result;
Expand Down
Loading