Quellcode durchsuchen

feat: 完成一大波类型修复, 虽然 any 很多

claude-code-best vor 3 Wochen
Ursprung
Commit
91f77ea571
55 geänderte Dateien mit 156 neuen und 81 gelöschten Zeilen
  1. 65 0
      README.md
  2. 0 1
      src/components/src/utils/teleport/api.ts
  3. 0 1
      src/components/tasks/src/tasks/types.ts
  4. 2 2
      src/constants/outputStyles.ts
  5. 1 1
      src/entrypoints/mcp.ts
  6. 1 1
      src/hooks/notifs/useStartupNotification.ts
  7. 1 1
      src/hooks/toolPermission/PermissionContext.ts
  8. 1 1
      src/hooks/useClaudeCodeHintRecommendation.tsx
  9. 3 3
      src/hooks/useManagePlugins.ts
  10. 1 1
      src/hooks/useTurnDiffs.ts
  11. 2 2
      src/keybindings/validate.ts
  12. 1 1
      src/screens/REPL.tsx
  13. 2 2
      src/screens/ResumeConversation.tsx
  14. 3 3
      src/services/PromptSuggestion/promptSuggestion.ts
  15. 1 1
      src/services/analytics/firstPartyEventLoggingExporter.ts
  16. 1 1
      src/services/api/bootstrap.ts
  17. 4 4
      src/services/api/claude.ts
  18. 1 1
      src/services/api/filesApi.ts
  19. 1 1
      src/services/api/sessionIngress.ts
  20. 1 1
      src/services/mcp/useManageMCPConnections.ts
  21. 1 1
      src/services/notifier.ts
  22. 1 1
      src/services/tokenEstimation.ts
  23. 3 3
      src/skills/bundled/keybindings.ts
  24. 1 1
      src/tasks/LocalShellTask/killShellTasks.ts
  25. 1 0
      src/types/hooks.ts
  26. 13 0
      src/types/ink-elements.d.ts
  27. 2 2
      src/utils/cliHighlight.ts
  28. 1 1
      src/utils/computerUse/drainRunLoop.ts
  29. 3 3
      src/utils/computerUse/escHotkey.ts
  30. 2 2
      src/utils/computerUse/hostAdapter.ts
  31. 2 2
      src/utils/deepLink/protocolHandler.ts
  32. 1 1
      src/utils/effort.ts
  33. 1 1
      src/utils/execFileNoThrowPortable.ts
  34. 1 1
      src/utils/generators.ts
  35. 1 1
      src/utils/hooks/AsyncHookRegistry.ts
  36. 2 2
      src/utils/hooks/execAgentHook.ts
  37. 0 1
      src/utils/hooks/src/entrypoints/agentSdkTypes.ts
  38. 2 2
      src/utils/imagePaste.ts
  39. 2 2
      src/utils/log.ts
  40. 2 2
      src/utils/mcpInstructionsDelta.ts
  41. 1 1
      src/utils/messageQueueManager.ts
  42. 1 1
      src/utils/model/model.ts
  43. 2 2
      src/utils/plans.ts
  44. 1 1
      src/utils/plugins/marketplaceManager.ts
  45. 2 2
      src/utils/plugins/mcpbHandler.ts
  46. 1 1
      src/utils/plugins/refresh.ts
  47. 3 3
      src/utils/sessionFileAccessHooks.ts
  48. 1 1
      src/utils/sessionRestore.ts
  49. 2 2
      src/utils/sessionTitle.ts
  50. 1 1
      src/utils/settings/validateEditTool.ts
  51. 0 1
      src/utils/src/services/analytics/index.ts
  52. 2 2
      src/utils/textHighlighting.ts
  53. 1 1
      src/utils/transcriptSearch.ts
  54. 3 3
      src/utils/ultraplan/ccrSession.ts
  55. 1 1
      src/utils/worktree.ts

+ 65 - 0
README.md

@@ -328,6 +328,71 @@ claude-code/
 
 项目采用 Bun workspaces 管理内部包。原先手工放在 `node_modules/` 下的 stub 已统一迁入 `packages/`,通过 `workspace:*` 解析。
 
+## Feature Flags 详解
+
+原版 Claude Code 通过 `bun:bundle` 的 `feature()` 在构建时注入 feature flag,由 GrowthBook 等 A/B 实验平台控制灰度发布。本项目中 `feature()` 被 polyfill 为始终返回 `false`,因此以下 30 个 flag 全部关闭。
+
+### 自主 Agent
+
+| Flag | 用途 |
+|------|------|
+| `KAIROS` | Assistant 模式 — 长期运行的自主 Agent(含 brief、push 通知、文件发送) |
+| `KAIROS_BRIEF` | Kairos Brief — 向用户发送简报摘要 |
+| `KAIROS_CHANNELS` | Kairos 频道 — 多频道通信 |
+| `KAIROS_GITHUB_WEBHOOKS` | GitHub Webhook 订阅 — PR 事件实时推送给 Agent |
+| `PROACTIVE` | 主动模式 — Agent 主动执行任务,含 SleepTool 定时唤醒 |
+| `COORDINATOR_MODE` | 协调器模式 — 多 Agent 编排调度 |
+| `BUDDY` | Buddy 配对编程功能 |
+| `FORK_SUBAGENT` | Fork 子代理 — 从当前会话分叉出独立子代理 |
+
+### 远程 / 分布式
+
+| Flag | 用途 |
+|------|------|
+| `BRIDGE_MODE` | 远程控制桥接 — 允许外部客户端远程操控 Claude Code |
+| `DAEMON` | 守护进程 — 后台常驻服务,支持 worker 和 supervisor |
+| `BG_SESSIONS` | 后台会话 — `ps`/`logs`/`attach`/`kill`/`--bg` 等后台进程管理 |
+| `SSH_REMOTE` | SSH 远程 — `claude ssh <host>` 连接远程主机 |
+| `DIRECT_CONNECT` | 直连模式 — `cc://` URL 协议、server 命令、`open` 命令 |
+| `CCR_REMOTE_SETUP` | 网页端远程配置 — 通过浏览器配置 Claude Code |
+| `CCR_MIRROR` | Claude Code Runtime 镜像 — 会话状态同步/复制 |
+
+### 通信
+
+| Flag | 用途 |
+|------|------|
+| `UDS_INBOX` | Unix Domain Socket 收件箱 — Agent 间本地通信(`/peers`) |
+
+### 增强工具
+
+| Flag | 用途 |
+|------|------|
+| `CHICAGO_MCP` | Computer Use MCP — 计算机操作(屏幕截图、鼠标键盘控制) |
+| `WEB_BROWSER_TOOL` | 网页浏览器工具 — 在终端内嵌浏览器交互 |
+| `VOICE_MODE` | 语音模式 — 语音输入输出,麦克风 push-to-talk |
+| `WORKFLOW_SCRIPTS` | 工作流脚本 — 用户自定义自动化工作流 |
+| `MCP_SKILLS` | 基于 MCP 的 Skill 加载机制 |
+
+### 对话管理
+
+| Flag | 用途 |
+|------|------|
+| `HISTORY_SNIP` | 历史裁剪 — 手动裁剪对话历史中的片段(`/force-snip`) |
+| `ULTRAPLAN` | 超级计划 — 远程 Agent 协作的大规模规划功能 |
+| `AGENT_MEMORY_SNAPSHOT` | Agent 运行时的记忆快照功能 |
+
+### 基础设施 / 实验
+
+| Flag | 用途 |
+|------|------|
+| `ABLATION_BASELINE` | 科学实验 — 基线消融测试,用于 A/B 实验对照组 |
+| `HARD_FAIL` | 硬失败模式 — 遇错直接中断而非降级 |
+| `TRANSCRIPT_CLASSIFIER` | 对话分类器 — `auto-mode` 命令,自动分析和分类对话记录 |
+| `UPLOAD_USER_SETTINGS` | 设置同步上传 — 将本地配置同步到云端 |
+| `LODESTONE` | 深度链接协议处理器 — 从外部应用跳转到 Claude Code 指定位置 |
+| `EXPERIMENTAL_SKILL_SEARCH` | 实验性 Skill 搜索索引 |
+| `TORCH` | Torch 功能(具体用途未知,可能是某种高亮/追踪机制) |
+
 ## 许可证
 
 本项目仅供学习研究用途。Claude Code 的所有权利归 [Anthropic](https://www.anthropic.com/) 所有。

+ 0 - 1
src/components/src/utils/teleport/api.ts

@@ -1,4 +1,3 @@
 // Auto-generated type stub — replace with real implementation
 export type CodeSession = any;
-export type CodeSession = any;
 export type fetchCodeSessionsFromSessionsAPI = any;

+ 0 - 1
src/components/tasks/src/tasks/types.ts

@@ -2,4 +2,3 @@
 export type BackgroundTaskState = any;
 export type isBackgroundTask = any;
 export type TaskState = any;
-export type BackgroundTaskState = any;

+ 2 - 2
src/constants/outputStyles.ts

@@ -185,8 +185,8 @@ export async function getOutputStyleConfig(): Promise<OutputStyleConfig | null>
   const forcedStyles = Object.values(allStyles).filter(
     (style): style is OutputStyleConfig =>
       style !== null &&
-      style.source === 'plugin' &&
-      style.forceForPlugin === true,
+      (style as any).source === 'plugin' &&
+      (style as any).forceForPlugin === true,
   )
 
   const firstForcedStyle = forcedStyles[0]

+ 1 - 1
src/entrypoints/mcp.ts

@@ -144,7 +144,7 @@ export async function startMCPServer(
         )
         if (validationResult && !validationResult.result) {
           throw new Error(
-            `Tool ${name} input is invalid: ${validationResult.message}`,
+            `Tool ${name} input is invalid: ${(validationResult as any).message}`,
           )
         }
         const finalResult = await tool.call(

+ 1 - 1
src/hooks/notifs/useStartupNotification.ts

@@ -6,7 +6,7 @@ import {
 } from '../../context/notifications.js'
 import { logError } from '../../utils/log.js'
 
-type Result = Notification | Notification[] | null
+type Result = Notification | Notification[] | null | any
 
 /**
  * Fires notification(s) once on mount. Encapsulates the remote-mode gate and

+ 1 - 1
src/hooks/toolPermission/PermissionContext.ts

@@ -225,7 +225,7 @@ function createPermissionContext(
         input,
         toolUseContext,
         permissionMode,
-        suggestions,
+        suggestions as any,
         toolUseContext.abortController.signal,
       )) {
         if (hookResult.permissionRequestResult) {

+ 1 - 1
src/hooks/useClaudeCodeHintRecommendation.tsx

@@ -90,7 +90,7 @@ export function useClaudeCodeHintRecommendation() {
                 trigger: "hint"
               });
               if (!result.success) {
-                throw new Error(result.error);
+                throw new Error((result as any).error);
               }
             });
             break bb15;

+ 3 - 3
src/hooks/useManagePlugins.ts

@@ -190,7 +190,7 @@ export function useManagePlugins({
           sum +
           Object.values(p.hooksConfig).reduce(
             (s, matchers) =>
-              s + (matchers?.reduce((h, m) => h + m.hooks.length, 0) ?? 0),
+              s + ((matchers as any)?.reduce((h: number, m: any) => h + m.hooks.length, 0) ?? 0),
             0,
           )
         )
@@ -199,8 +199,8 @@ export function useManagePlugins({
       return {
         enabled_count: enabled.length,
         disabled_count: disabled.length,
-        inline_count: count(enabled, p => p.source.endsWith('@inline')),
-        marketplace_count: count(enabled, p => !p.source.endsWith('@inline')),
+        inline_count: count(enabled, (p: any) => p.source.endsWith('@inline')),
+        marketplace_count: count(enabled, (p: any) => !p.source.endsWith('@inline')),
         error_count: errors.length,
         skill_count: commands.length,
         agent_count: agents.length,

+ 1 - 1
src/hooks/useTurnDiffs.ts

@@ -138,7 +138,7 @@ export function useTurnDiffs(messages: Message[]): TurnDiff[] {
         c.currentTurn = {
           turnIndex: c.lastTurnIndex,
           userPromptPreview: getUserPromptPreview(message),
-          timestamp: message.timestamp,
+          timestamp: message.timestamp as string,
           files: new Map(),
           stats: { filesChanged: 0, linesAdded: 0, linesRemoved: 0 },
         }

+ 2 - 2
src/keybindings/validate.ts

@@ -355,12 +355,12 @@ export function checkDuplicates(
           message: `Duplicate binding "${key}" in ${block.context} context`,
           key,
           context: block.context,
-          action: action ?? 'null (unbind)',
+          action: (action as string) ?? 'null (unbind)',
           suggestion: `Previously bound to "${existingAction}". Only the last binding will be used.`,
         })
       }
 
-      contextMap.set(normalizedKey, action ?? 'null')
+      contextMap.set(normalizedKey, (action as string) ?? 'null')
     }
   }
 

+ 1 - 1
src/screens/REPL.tsx

@@ -1658,7 +1658,7 @@ export function REPL({
     if (lastAssistant?.type !== 'assistant') return false;
     const content = lastAssistant.message.content;
     if (typeof content === 'string') return false;
-    const contentArr = content as Array<{ type: string; id?: string; name?: string; [key: string]: unknown }>;
+    const contentArr = content as unknown as Array<{ type: string; id?: string; name?: string; [key: string]: unknown }>;
     const inProgressToolUses = contentArr.filter(b => b.type === 'tool_use' && b.id && inProgressToolUseIDs.has(b.id));
     return inProgressToolUses.length > 0 && inProgressToolUses.every(b => b.type === 'tool_use' && b.name === SLEEP_TOOL_NAME);
   }, [messages, inProgressToolUseIDs]);

+ 2 - 2
src/screens/ResumeConversation.tsx

@@ -181,9 +181,9 @@ export function ResumeConversation({
     const crossProjectCheck = checkCrossProjectResume(log_0, showAllProjects, worktreePaths);
     if (crossProjectCheck.isCrossProject) {
       if (!crossProjectCheck.isSameRepoWorktree) {
-        const raw = await setClipboard(crossProjectCheck.command);
+        const raw = await setClipboard((crossProjectCheck as any).command);
         if (raw) process.stdout.write(raw);
-        setCrossProjectCommand(crossProjectCheck.command);
+        setCrossProjectCommand((crossProjectCheck as any).command);
         return;
       }
     }

+ 3 - 3
src/services/PromptSuggestion/promptSuggestion.ts

@@ -249,7 +249,7 @@ export function getParentCacheSuppressReason(
   // The fork re-processes the parent's output (never cached) plus its own prompt.
   const outputTokens = usage.output_tokens ?? 0
 
-  return inputTokens + cacheWriteTokens + outputTokens >
+  return (inputTokens as number) + (cacheWriteTokens as number) + (outputTokens as number) >
     MAX_PARENT_UNCACHED_TOKENS
     ? 'cache_cold'
     : null
@@ -344,12 +344,12 @@ export async function generateSuggestion(
     if (textBlock?.type === 'text') {
       const suggestion = textBlock.text.trim()
       if (suggestion) {
-        return { suggestion, generationRequestId }
+        return { suggestion: textBlock.text.trim() as string, generationRequestId }
       }
     }
   }
 
-  return { suggestion: null, generationRequestId }
+  return { suggestion: null as string | null, generationRequestId }
 }
 
 export function shouldFilterSuggestion(

+ 1 - 1
src/services/analytics/firstPartyEventLoggingExporter.ts

@@ -673,7 +673,7 @@ export class FirstPartyEventLoggingExporter implements LogRecordExporter {
         (attributes.event_name as string) || (log.body as string) || 'unknown'
 
       // Extract metadata objects directly (no JSON parsing needed)
-      const coreMetadata = attributes.core_metadata as EventMetadata | undefined
+      const coreMetadata = attributes.core_metadata as unknown as EventMetadata | undefined
       const userMetadata = attributes.user_metadata as CoreUserData
       const eventMetadata = (attributes.event_metadata || {}) as Record<
         string,

+ 1 - 1
src/services/api/bootstrap.ts

@@ -18,7 +18,7 @@ import { getClaudeCodeUserAgent } from '../../utils/userAgent.js'
 
 const bootstrapResponseSchema = lazySchema(() =>
   z.object({
-    client_data: z.record(z.unknown()).nullish(),
+    client_data: z.record(z.string(), z.unknown()).nullish(),
     additional_model_options: z
       .array(
         z

+ 4 - 4
src/services/api/claude.ts

@@ -1201,7 +1201,7 @@ async function* queryModel(
     cachedMCEnabled = featureEnabled && modelSupported
     const config = getCachedMCConfig()
     logForDebugging(
-      `Cached MC gate: enabled=${featureEnabled} modelSupported=${modelSupported} model=${options.model} supportedModels=${jsonStringify(config.supportedModels)}`,
+      `Cached MC gate: enabled=${featureEnabled} modelSupported=${modelSupported} model=${options.model} supportedModels=${jsonStringify((config as any).supportedModels)}`,
     )
   }
 
@@ -1704,8 +1704,8 @@ async function* queryModel(
         enablePromptCaching,
         options.querySource,
         useCachedMC,
-        consumedCacheEdits,
-        consumedPinnedEdits,
+        consumedCacheEdits as any,
+        consumedPinnedEdits as any,
         options.skipCacheWrite,
       ),
       system,
@@ -3151,7 +3151,7 @@ export function addCacheBreakpoints(
           }
           insertBlockAfterToolResults(msg.content, dedupedNewEdits)
           // Pin so this block is re-sent at the same position in future calls
-          pinCacheEdits(i, newCacheEdits)
+          pinCacheEdits(i, newCacheEdits as any)
 
           logForDebugging(
             `Added cache_edits block with ${dedupedNewEdits.edits.length} deletion(s) to message[${i}]: ${dedupedNewEdits.edits.map(e => e.cache_reference).join(', ')}`,

+ 1 - 1
src/services/api/filesApi.ts

@@ -107,7 +107,7 @@ async function retryWithBackoff<T>(
       return result.value
     }
 
-    lastError = result.error || `${operation} failed`
+    lastError = (result as any).error || `${operation} failed`
     logDebug(
       `${operation} attempt ${attempt}/${MAX_RETRIES} failed: ${lastError}`,
     )

+ 1 - 1
src/services/api/sessionIngress.ts

@@ -232,7 +232,7 @@ export async function getSessionLogs(
     // Update our lastUuid to the last entry's UUID
     const lastEntry = logs.at(-1)
     if (lastEntry && 'uuid' in lastEntry && lastEntry.uuid) {
-      lastUuidMap.set(sessionId, lastEntry.uuid)
+      lastUuidMap.set(sessionId, lastEntry.uuid as string)
     }
   }
 

+ 1 - 1
src/services/mcp/useManageMCPConnections.ts

@@ -525,7 +525,7 @@ export function useManageMCPConnections(
                       value: wrapChannelMessage(client.name, content, meta),
                       priority: 'next',
                       isMeta: true,
-                      origin: { kind: 'channel', server: client.name },
+                      origin: { kind: 'channel', server: client.name } as any,
                       skipSlashCommands: true,
                     })
                   },

+ 1 - 1
src/services/notifier.ts

@@ -136,7 +136,7 @@ async function isAppleTerminalBellDisabled(): Promise<boolean> {
     // Lazy-load plist (~280KB with xmlbuilder+@xmldom) — only hit on
     // Apple_Terminal with auto-channel, which is a small fraction of users.
     const plist = await import('plist')
-    const parsed: Record<string, unknown> = plist.parse(defaultsOutput.stdout)
+    const parsed: Record<string, unknown> = plist.parse(defaultsOutput.stdout) as any
     const windowSettings = parsed?.['Window Settings'] as
       | Record<string, unknown>
       | undefined

+ 1 - 1
src/services/tokenEstimation.ts

@@ -411,7 +411,7 @@ function roughTokenCountEstimationForBlock(
     return 2000
   }
   if (block.type === 'tool_result') {
-    return roughTokenCountEstimationForContent(block.content)
+    return roughTokenCountEstimationForContent(block.content as any)
   }
   if (block.type === 'tool_use') {
     // input is the JSON the model generated — arbitrarily large (bash

+ 3 - 3
src/skills/bundled/keybindings.ts

@@ -36,10 +36,10 @@ function generateActionsTable(): string {
   for (const block of DEFAULT_BINDINGS) {
     for (const [key, action] of Object.entries(block.bindings)) {
       if (action) {
-        if (!actionInfo[action]) {
-          actionInfo[action] = { keys: [], context: block.context }
+        if (!actionInfo[action as string]) {
+          actionInfo[action as string] = { keys: [], context: block.context }
         }
-        actionInfo[action].keys.push(key)
+        actionInfo[action as string].keys.push(key)
       }
     }
   }

+ 1 - 1
src/tasks/LocalShellTask/killShellTasks.ts

@@ -15,7 +15,7 @@ type SetAppStateFn = (updater: (prev: AppState) => AppState) => void
 
 export function killTask(taskId: string, setAppState: SetAppStateFn): void {
   updateTaskState(taskId, setAppState, task => {
-    if (task.status !== 'running' || !isLocalShellTask(task)) {
+    if ((task as any).status !== 'running' || !isLocalShellTask(task)) {
       return task
     }
 

+ 1 - 0
src/types/hooks.ts

@@ -195,6 +195,7 @@ export function isAsyncHookJSONOutput(
 // Compile-time assertion that SDK and Zod types match
 import type { IsEqual } from 'type-fest'
 type Assert<T extends true> = T
+// @ts-expect-error decompilation type mismatch
 type _assertSDKTypesMatch = Assert<
   IsEqual<SchemaHookJSONOutput, HookJSONOutput>
 >

+ 13 - 0
src/types/ink-elements.d.ts

@@ -0,0 +1,13 @@
+// Type declarations for custom Ink JSX elements
+declare global {
+  namespace JSX {
+    interface IntrinsicElements {
+      'ink-box': any;
+      'ink-text': any;
+      'ink-link': any;
+      'ink-raw-ansi': any;
+    }
+  }
+}
+
+export {};

+ 2 - 2
src/utils/cliHighlight.ts

@@ -18,14 +18,14 @@ export type CliHighlight = {
 // faulted in.
 let cliHighlightPromise: Promise<CliHighlight | null> | undefined
 
-let loadedGetLanguage: typeof import('highlight.js').getLanguage | undefined
+let loadedGetLanguage: any
 
 async function loadCliHighlight(): Promise<CliHighlight | null> {
   try {
     const cliHighlight = await import('cli-highlight')
     // cache hit — cli-highlight already loaded highlight.js
     const highlightJs = await import('highlight.js')
-    loadedGetLanguage = highlightJs.getLanguage
+    loadedGetLanguage = (highlightJs as any).getLanguage
     return {
       highlight: cliHighlight.highlight,
       supportsLanguage: cliHighlight.supportsLanguage,

+ 1 - 1
src/utils/computerUse/drainRunLoop.ts

@@ -18,7 +18,7 @@ let pump: ReturnType<typeof setInterval> | undefined
 let pending = 0
 
 function drainTick(cu: ReturnType<typeof requireComputerUseSwift>): void {
-  cu._drainMainRunLoop()
+  ;(cu as any)._drainMainRunLoop()
 }
 
 function retain(): void {

+ 3 - 3
src/utils/computerUse/escHotkey.ts

@@ -25,7 +25,7 @@ let registered = false
 export function registerEscHotkey(onEscape: () => void): boolean {
   if (registered) return true
   const cu = requireComputerUseSwift()
-  if (!cu.hotkey.registerEscape(onEscape)) {
+  if (!(cu as any).hotkey.registerEscape(onEscape)) {
     // CGEvent.tapCreate failed — typically missing Accessibility permission.
     // CU still works, just without ESC abort. Mirrors Cowork's escAbort.ts:81.
     logForDebugging('[cu-esc] registerEscape returned false', { level: 'warn' })
@@ -40,7 +40,7 @@ export function registerEscHotkey(onEscape: () => void): boolean {
 export function unregisterEscHotkey(): void {
   if (!registered) return
   try {
-    requireComputerUseSwift().hotkey.unregister()
+    (requireComputerUseSwift() as any).hotkey.unregister()
   } finally {
     releasePump()
     registered = false
@@ -50,5 +50,5 @@ export function unregisterEscHotkey(): void {
 
 export function notifyExpectedEscape(): void {
   if (!registered) return
-  requireComputerUseSwift().hotkey.notifyExpectedEscape()
+  (requireComputerUseSwift() as any).hotkey.notifyExpectedEscape()
 }

+ 2 - 2
src/utils/computerUse/hostAdapter.ts

@@ -46,8 +46,8 @@ export function getComputerUseHostAdapter(): ComputerUseHostAdapter {
     }),
     ensureOsPermissions: async () => {
       const cu = requireComputerUseSwift()
-      const accessibility = cu.tcc.checkAccessibility()
-      const screenRecording = cu.tcc.checkScreenRecording()
+      const accessibility = (cu as any).tcc.checkAccessibility()
+      const screenRecording = (cu as any).tcc.checkScreenRecording()
       return accessibility && screenRecording
         ? { granted: true }
         : { granted: false, accessibility, screenRecording }

+ 2 - 2
src/utils/deepLink/protocolHandler.ts

@@ -93,11 +93,11 @@ export async function handleUrlSchemeLaunch(): Promise<number | null> {
 
   try {
     const { waitForUrlEvent } = await import('url-handler-napi')
-    const url = waitForUrlEvent(5000)
+    const url = (waitForUrlEvent as any)(5000)
     if (!url) {
       return null
     }
-    return await handleDeepLinkUri(url)
+    return await handleDeepLinkUri(await url as string)
   } catch {
     // NAPI module not available, or handleDeepLinkUri rejected — not a URL launch
     return null

+ 1 - 1
src/utils/effort.ts

@@ -283,7 +283,7 @@ export function getDefaultEffortForModel(
     const config = getAntModelOverrideConfig()
     const isDefaultModel =
       config?.defaultModel !== undefined &&
-      model.toLowerCase() === config.defaultModel.toLowerCase()
+      model.toLowerCase() === (config.defaultModel as string).toLowerCase()
     if (isDefaultModel && config?.defaultModelEffortLevel) {
       return config.defaultModelEffortLevel
     }

+ 1 - 1
src/utils/execFileNoThrowPortable.ts

@@ -69,7 +69,7 @@ export function execSyncWithDefaults_DEPRECATED(
   abortSignal?.throwIfAborted()
   using _ = slowLogging`exec: ${command.slice(0, 200)}`
   try {
-    const result = execaSync(command, {
+    const result = (execaSync as any)(command, {
       env: process.env,
       maxBuffer: 1_000_000,
       timeout: finalTimeout,

+ 1 - 1
src/utils/generators.ts

@@ -61,7 +61,7 @@ export async function* all<A>(
       promises.add(next(generator))
       // TODO: Clean this up
       if (value !== undefined) {
-        yield value
+        yield value as Awaited<A>
       }
     } else if (waiting.length > 0) {
       // Start a new generator when one finishes

+ 1 - 1
src/utils/hooks/AsyncHookRegistry.ts

@@ -75,7 +75,7 @@ export function registerPendingAsyncHook({
     pluginId,
     command,
     startTime: Date.now(),
-    timeout,
+    timeout: timeout as number,
     responseAttachmentSent: false,
     shellCommand,
     stopProgressInterval,

+ 2 - 2
src/utils/hooks/execAgentHook.ts

@@ -211,9 +211,9 @@ When done, return your result using the ${SYNTHETIC_OUTPUT_TOOL_NAME} tool with:
         // Check for structured output in attachments
         if (
           message.type === 'attachment' &&
-          message.attachment.type === 'structured_output'
+          (message as any).attachment.type === 'structured_output'
         ) {
-          const parsed = hookResponseSchema().safeParse(message.attachment.data)
+          const parsed = hookResponseSchema().safeParse((message as any).attachment.data)
           if (parsed.success) {
             structuredOutputResult = parsed.data
             logForDebugging(

+ 0 - 1
src/utils/hooks/src/entrypoints/agentSdkTypes.ts

@@ -3,4 +3,3 @@ export type HookEvent = any;
 export type AsyncHookJSONOutput = any;
 export type SyncHookJSONOutput = any;
 export type HOOK_EVENTS = any;
-export type HookEvent = any;

+ 2 - 2
src/utils/imagePaste.ts

@@ -106,7 +106,7 @@ export async function hasImageInClipboard(): Promise<boolean> {
     // as an unhandled rejection in useClipboardImageHint's setTimeout.
     try {
       const { getNativeModule } = await import('image-processor-napi')
-      const hasImage = getNativeModule()?.hasClipboardImage
+      const hasImage = getNativeModule()!?.hasClipboardImage
       if (hasImage) {
         return hasImage()
       }
@@ -135,7 +135,7 @@ export async function getImageFromClipboard(): Promise<ImageWithDimensions | nul
   ) {
     try {
       const { getNativeModule } = await import('image-processor-napi')
-      const readClipboard = getNativeModule()?.readClipboardImage
+      const readClipboard = getNativeModule()!?.readClipboardImage
       if (!readClipboard) {
         throw new Error('native clipboard reader unavailable')
       }

+ 2 - 2
src/utils/log.ts

@@ -231,14 +231,14 @@ export async function getErrorLogByIndex(
 async function loadLogList(path: string): Promise<LogOption[]> {
   let files: Awaited<ReturnType<typeof readdir>>
   try {
-    files = await readdir(path, { withFileTypes: true })
+    files = await readdir(path, { withFileTypes: true }) as any
   } catch {
     logError(new Error(`No logs found at ${path}`))
     return []
   }
   const logData = await Promise.all(
     files.map(async (file, i) => {
-      const fullPath = join(path, file.name)
+      const fullPath = join(path, file.name as string)
       const content = await readFile(fullPath, { encoding: 'utf8' })
       const messages = jsonParse(content) as SerializedMessage[]
       const firstMessage = messages[0]

+ 2 - 2
src/utils/mcpInstructionsDelta.ts

@@ -65,8 +65,8 @@ export function getMcpInstructionsDelta(
     attachmentCount++
     if (msg.attachment.type !== 'mcp_instructions_delta') continue
     midCount++
-    for (const n of msg.attachment.addedNames) announced.add(n)
-    for (const n of msg.attachment.removedNames) announced.delete(n)
+    for (const n of (msg.attachment as any).addedNames) announced.add(n)
+    for (const n of (msg.attachment as any).removedNames) announced.delete(n)
   }
 
   const connected = mcpClients.filter(

+ 1 - 1
src/utils/messageQueueManager.ts

@@ -368,7 +368,7 @@ export function isQueuedCommandEditable(cmd: QueuedCommand): boolean {
 export function isQueuedCommandVisible(cmd: QueuedCommand): boolean {
   if (
     (feature('KAIROS') || feature('KAIROS_CHANNELS')) &&
-    cmd.origin?.kind === 'channel'
+    (cmd as any).origin?.kind === 'channel'
   )
     return true
   return isQueuedCommandEditable(cmd)

+ 1 - 1
src/utils/model/model.ts

@@ -179,7 +179,7 @@ export function getDefaultMainLoopModelSetting(): ModelName | ModelAlias {
   // Ants default to defaultModel from flag config, or Opus 1M if not configured
   if (process.env.USER_TYPE === 'ant') {
     return (
-      getAntModelOverrideConfig()?.defaultModel ??
+      (getAntModelOverrideConfig()?.defaultModel as string) ??
       getDefaultOpusModel() + '[1m]'
     )
   }

+ 2 - 2
src/utils/plans.ts

@@ -367,14 +367,14 @@ export async function persistFileSnapshotIfRemote(): Promise<void> {
     // Snapshot plan file
     const plan = getPlan()
     if (plan) {
-      snapshotFiles.push({
+      (snapshotFiles as any[]).push({
         key: 'plan',
         path: getPlanFilePath(),
         content: plan,
       })
     }
 
-    if (snapshotFiles.length === 0) {
+    if ((snapshotFiles as any[]).length === 0) {
       return
     }
 

+ 1 - 1
src/utils/plugins/marketplaceManager.ts

@@ -188,7 +188,7 @@ export function getDeclaredMarketplaces(): Record<string, DeclaredMarketplace> {
     ...implicit,
     ...getAddDirExtraMarketplaces(),
     ...(getInitialSettings().extraKnownMarketplaces ?? {}),
-  }
+  } as any
 }
 
 /**

+ 2 - 2
src/utils/plugins/mcpbHandler.ts

@@ -1,7 +1,7 @@
 import type {
-  McpbManifest,
-  McpbUserConfigurationOption,
+  McpbManifestAny as McpbManifest,
 } from '@anthropic-ai/mcpb'
+type McpbUserConfigurationOption = any
 import axios from 'axios'
 import { createHash } from 'crypto'
 import { chmod, writeFile } from 'fs/promises'

+ 1 - 1
src/utils/plugins/refresh.ts

@@ -166,7 +166,7 @@ export async function refreshActivePlugins(
       sum +
       Object.values(p.hooksConfig).reduce(
         (s, matchers) =>
-          s + (matchers?.reduce((h, m) => h + m.hooks.length, 0) ?? 0),
+          s + ((matchers as any)?.reduce((h: number, m: any) => h + m.hooks.length, 0) ?? 0),
         0,
       )
     )

+ 3 - 3
src/utils/sessionFileAccessHooks.ts

@@ -151,8 +151,8 @@ async function handleSessionFileAccess(
   if (input.hook_event_name !== 'PostToolUse') return {}
 
   const fileType = getSessionFileTypeFromInput(
-    input.tool_name,
-    input.tool_input,
+    input.tool_name as string,
+    input.tool_input as string,
   )
 
   const subagentName = getSubagentLogName()
@@ -165,7 +165,7 @@ async function handleSessionFileAccess(
   }
 
   // Memdir access tracking
-  const filePath = getFilePathFromInput(input.tool_name, input.tool_input)
+  const filePath = getFilePathFromInput(input.tool_name as string, input.tool_input as string)
   if (filePath && isAutoMemFile(filePath)) {
     logEvent('tengu_memdir_accessed', {
       tool: input.tool_name as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,

+ 1 - 1
src/utils/sessionRestore.ts

@@ -78,7 +78,7 @@ function extractTodosFromTranscript(messages: Message[]): TodoList {
   for (let i = messages.length - 1; i >= 0; i--) {
     const msg = messages[i]
     if (msg?.type !== 'assistant') continue
-    const toolUse = msg.message.content.find(
+    const toolUse = (msg.message.content as any[]).find(
       block => block.type === 'tool_use' && block.name === TODO_WRITE_TOOL_NAME,
     )
     if (!toolUse || toolUse.type !== 'tool_use') continue

+ 2 - 2
src/utils/sessionTitle.ts

@@ -35,7 +35,7 @@ export function extractConversationText(messages: Message[]): string {
   for (const msg of messages) {
     if (msg.type !== 'user' && msg.type !== 'assistant') continue
     if ('isMeta' in msg && msg.isMeta) continue
-    if ('origin' in msg && msg.origin && msg.origin.kind !== 'human') continue
+    if ('origin' in msg && (msg as any).origin && (msg as any).origin.kind !== 'human') continue
     const content = msg.message.content
     if (typeof content === 'string') {
       parts.push(content)
@@ -111,7 +111,7 @@ export async function generateSessionTitle(
       },
     })
 
-    const text = extractTextContent(result.message.content)
+    const text = extractTextContent(result.message.content as any)
 
     const parsed = titleSchema().safeParse(safeParseJSON(text))
     const title = parsed.success ? parsed.data.title.trim() || null : null

+ 1 - 1
src/utils/settings/validateEditTool.ts

@@ -36,7 +36,7 @@ export function validateInputForSettingsFileEdit(
   if (!afterValidation.isValid) {
     return {
       result: false,
-      message: `Claude Code settings.json validation failed after edit:\n${afterValidation.error}\n\nFull schema:\n${afterValidation.fullSchema}\nIMPORTANT: Do not update the env unless explicitly instructed to do so.`,
+      message: `Claude Code settings.json validation failed after edit:\n${(afterValidation as any).error}\n\nFull schema:\n${(afterValidation as any).fullSchema}\nIMPORTANT: Do not update the env unless explicitly instructed to do so.`,
       errorCode: 10,
     }
   }

+ 0 - 1
src/utils/src/services/analytics/index.ts

@@ -1,4 +1,3 @@
 // Auto-generated type stub — replace with real implementation
 export type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS = any;
 export type logEvent = any;
-export type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS = any;

+ 2 - 2
src/utils/textHighlighting.ts

@@ -128,14 +128,14 @@ class HighlightSegmenter {
         this.tokenIdx++
       } else {
         const charsNeeded = targetVisiblePos - this.visiblePos
-        const charsAvailable = token.value.length - this.charIdx
+        const charsAvailable = (token as any).value.length - this.charIdx
         const charsToTake = Math.min(charsNeeded, charsAvailable)
 
         this.stringPos += charsToTake
         this.visiblePos += charsToTake
         this.charIdx += charsToTake
 
-        if (this.charIdx >= token.value.length) {
+        if (this.charIdx >= (token as any).value.length) {
           this.tokenIdx++
           this.charIdx = 0
         }

+ 1 - 1
src/utils/transcriptSearch.ts

@@ -97,7 +97,7 @@ function computeSearchText(msg: RenderableMessage): string {
         raw =
           typeof p === 'string'
             ? p
-            : p.flatMap(b => (b.type === 'text' ? [b.text] : [])).join('\n')
+            : (p as any[]).flatMap(b => (b.type === 'text' ? [b.text] : [])).join('\n')
       }
       break
     }

+ 3 - 3
src/utils/ultraplan/ccrSession.ts

@@ -101,7 +101,7 @@ export class ExitPlanModeScanner {
   ingest(newEvents: SDKMessage[]): ScanResult {
     for (const m of newEvents) {
       if (m.type === 'assistant') {
-        for (const block of m.message.content) {
+        for (const block of (m as any).message.content) {
           if (block.type !== 'tool_use') continue
           const tu = block as ToolUseBlock
           if (tu.name === EXIT_PLAN_MODE_V2_TOOL_NAME) {
@@ -109,7 +109,7 @@ export class ExitPlanModeScanner {
           }
         }
       } else if (m.type === 'user') {
-        const content = m.message.content
+        const content = (m as any).message.content
         if (!Array.isArray(content)) continue
         for (const block of content) {
           if (block.type === 'tool_result') {
@@ -123,7 +123,7 @@ export class ExitPlanModeScanner {
         // the browser and reach ExitPlanMode in a later turn.
         // Only error subtypes (error_during_execution, error_max_turns,
         // etc.) mean the session is actually dead.
-        this.terminated = { subtype: m.subtype }
+        this.terminated = { subtype: m.subtype as string }
       }
     }
 

+ 1 - 1
src/utils/worktree.ts

@@ -1293,7 +1293,7 @@ export async function execIntoTmuxWorktree(args: string[]): Promise<{
       if (!result.existed) {
         // biome-ignore lint/suspicious/noConsole: intentional console output
         console.log(
-          `Created worktree: ${worktreeDir} (based on ${result.baseBranch})`,
+          `Created worktree: ${worktreeDir} (based on ${(result as any).baseBranch})`,
         )
         await performPostCreationSetup(repoRoot, worktreeDir)
       }