diff --git a/package.json b/package.json index fd9dd71..85b24f3 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test": "node scripts/test.mjs", "test:vitest": "node node_modules/vitest/vitest.mjs run", "test:watch": "node node_modules/vitest/vitest.mjs", - "lint": "ESLINT_USE_FLAT_CONFIG=false node node_modules/eslint/bin/eslint.js src --ext ts", + "lint": "node scripts/lint.mjs", "format": "node node_modules/prettier/bin/prettier.cjs --check .", "format:fix": "node node_modules/prettier/bin/prettier.cjs --write .", "rebuild-native": "cd node_modules/better-sqlite3 && npm run build-release", diff --git a/scripts/lint.mjs b/scripts/lint.mjs new file mode 100644 index 0000000..022a8d7 --- /dev/null +++ b/scripts/lint.mjs @@ -0,0 +1,18 @@ +import { spawnSync } from 'node:child_process'; +import { resolve } from 'node:path'; + +const eslintCli = resolve('node_modules/eslint/bin/eslint.js'); +const result = spawnSync(process.execPath, [eslintCli, 'src', '--ext', 'ts'], { + env: { + ...process.env, + ESLINT_USE_FLAT_CONFIG: 'false', + }, + stdio: 'inherit', +}); + +if (result.error) { + console.error(`Failed to start ESLint: ${result.error.message}`); + process.exitCode = 1; +} else { + process.exitCode = result.status ?? 1; +} diff --git a/src/advance/classic/cognitive-engine.ts b/src/advance/classic/cognitive-engine.ts index f487154..8dcf12c 100755 --- a/src/advance/classic/cognitive-engine.ts +++ b/src/advance/classic/cognitive-engine.ts @@ -95,6 +95,15 @@ const ALREADY_FIXED_CHECK_TOOL: ToolDefinition = { alreadyFixed: { type: 'boolean' }, reason: { type: 'string' }, evidence: { type: 'string' }, + evidenceSnippet: { + type: 'string', + description: + 'alreadyFixed=true 时,从当前目标文件或已提供的额外文件上下文中原样摘录的最小代码片段', + }, + evidenceLine: { + type: 'number', + description: 'evidenceSnippet 在对应文件中的起始行号;无法确定时可省略', + }, needsMoreContext: { type: 'boolean', description: @@ -106,6 +115,75 @@ const ALREADY_FIXED_CHECK_TOOL: ToolDefinition = { }, }; +function normalizeEvidenceFragment(text: string): string { + return text.replace(/\s+/g, ' ').trim().toLowerCase(); +} + +function extractPathReferences(text: string): string[] { + return Array.from( + text.matchAll(/[A-Za-z0-9_.@*~:-]+(?:[\\/][A-Za-z0-9_.@*~()-]+)+\.[A-Za-z0-9]+/g), + match => match[0].replace(/\\/g, '/').toLowerCase() + ); +} + +function extractDistinctiveCodeAnchors(text: string): string[] { + const withoutPaths = text.replace( + /[A-Za-z0-9_.@*~:-]+(?:[\\/][A-Za-z0-9_.@*~()-]+)+\.[A-Za-z0-9]+/g, + ' ' + ); + return Array.from( + withoutPaths.matchAll(/\b[A-Za-z_$][A-Za-z0-9_$]*\b/g), + match => match[0] + ).filter( + token => + token.includes('_') || /[a-z][A-Z]/.test(token) || (token.match(/[A-Z]/g)?.length ?? 0) >= 2 + ); +} + +/** already-fixed 证据必须能绑定到当前 finding 的文件或显式补充上下文。 */ +export function isAlreadyFixedEvidenceGrounded(params: { + findingFile: string; + fileContent: string; + extraFileContexts?: string[]; + evidence?: string; + evidenceSnippet?: string; +}): boolean { + const evidence = params.evidence?.trim() ?? ''; + const evidenceSnippet = params.evidenceSnippet?.trim() ?? ''; + if (!evidence && !evidenceSnippet) return false; + + const extraContexts = params.extraFileContexts ?? []; + const corpus = [params.fileContent, ...extraContexts].join('\n'); + const normalizedCorpus = normalizeEvidenceFragment(corpus); + const allowedPaths = new Set([ + params.findingFile.replace(/\\/g, '/').toLowerCase(), + ...extraContexts.flatMap(extractPathReferences), + ]); + + for (const path of extractPathReferences(`${evidence}\n${evidenceSnippet}`)) { + if ( + !Array.from(allowedPaths).some(allowed => allowed.endsWith(path) || path.endsWith(allowed)) + ) { + return false; + } + } + + if (evidenceSnippet && !normalizedCorpus.includes(normalizeEvidenceFragment(evidenceSnippet))) { + return false; + } + + const quotedAnchors = Array.from(evidence.matchAll(/`([^`\n]{2,160})`/g), match => match[1]) + .map(normalizeEvidenceFragment) + .filter(anchor => /[a-z_$]/i.test(anchor) && !extractPathReferences(anchor).length); + const distinctiveAnchors = extractDistinctiveCodeAnchors(evidence).map(normalizeEvidenceFragment); + const codeAnchors = [...new Set([...quotedAnchors, ...distinctiveAnchors])]; + if (codeAnchors.some(anchor => !normalizedCorpus.includes(anchor))) { + return false; + } + + return true; +} + const FAST_DECISION_TOOL: ToolDefinition = { name: 'fast_decision', description: @@ -398,7 +476,9 @@ export class CognitiveEngine { try { const matches = await manager.searchWorkspace(keyword); if (matches.length === 0) return null; - const lines = matches.map(match => `- ${match.file}:${match.line} ${match.content}`).join('\n'); + const lines = matches + .map(match => `- ${match.file}:${match.line} ${match.content}`) + .join('\n'); return `## 工作区中 ${keyword} 的匹配位置\n${lines}`; } catch (err) { const message = err instanceof Error ? err.message : String(err); @@ -478,8 +558,29 @@ export class CognitiveEngine { alreadyFixed?: boolean; reason?: string; evidence?: string; + evidenceSnippet?: string; + evidenceLine?: number; needsMoreContext?: boolean; }; + if ( + input.alreadyFixed === true && + !isAlreadyFixedEvidenceGrounded({ + findingFile: context.finding.file, + fileContent, + extraFileContexts: context.extraFileContexts, + evidence: input.evidence, + evidenceSnippet: input.evidenceSnippet, + }) + ) { + console.warn( + `[CognitiveEngine] already_fixed_check (${sourceLabel}) 证据与目标 finding 不匹配: ${context.finding.file}:${context.finding.line}` + ); + return { + alreadyFixed: false, + reason: 'already-fixed 证据无法绑定到当前 finding 的代码上下文,拒绝复用该结论', + needsMoreContext: sourceLabel === '聚焦窗口', + }; + } return { alreadyFixed: input.alreadyFixed === true, reason: input.reason ?? '未说明理由', diff --git a/src/advance/classic/fix/ask-gate.ts b/src/advance/classic/fix/ask-gate.ts new file mode 100644 index 0000000..cb90653 --- /dev/null +++ b/src/advance/classic/fix/ask-gate.ts @@ -0,0 +1,50 @@ +/** + * ask 门禁(L2,见 docs/goals/maintainer-llm-centric-goal.md) + * + * 向 Reviewer 提问前,框架先校验「这个问题能否用 worktree 工具自答」。 + * 仓库内文件内容/代码片段属于可自查信息,禁止索问——这类问题一旦被提出, + * 暴露的是框架失职而非信息缺失(真实现场实证:"请提供 tracker.ts 文件的内容")。 + * + * 命中以下模式的提问应被门禁拦截并转为修复自查,而不是出现在 MR 上。 + */ + +const SELF_ANSWERABLE_PATTERNS: RegExp[] = [ + // 请提供/请贴出 xx 文件(的内容/代码/实现/片段)——间距放宽以容纳长文件路径 + /请(?:提供|贴出|贴下|发一下|发送)[\s\S]{0,120}(?:文件|内容|代码|实现|片段)/, + // 能否/可以/能不能 提供/贴/发 xx 文件/代码/内容/实现 + /(?:能否|可以|能不能|烦请|麻烦)[\s\S]{0,15}(?:提供|贴|发)[\s\S]{0,30}(?:文件|代码|内容|片段|实现)/, + // 把 xx 文件/代码 发/贴/提供 给我 + /把[\s\S]{0,15}(?:文件|代码|内容)[\s\S]{0,10}(?:发|贴|提供)/, + // xx 文件的(完整|当前)内容/代码 是什么 + /(?:文件|代码)的(?:完整|当前|全部)?(?:内容|实现|代码)是(?:什么|啥)/, + // 英文等价形态 + /please (?:provide|share|paste|show)[\s\S]{0,40}(?:file|code|content|snippet)/i, + /(?:could|can) you (?:provide|share|paste|show)[\s\S]{0,40}(?:file|code|content|snippet)/i, +]; + +/** + * 判断提问是否属于「仓库内可自查」的索问。 + * + * 只拦截明确的文件内容/代码片段索问;意图澄清、方案取舍、业务上下文 + * 等真正需要人来回答的问题不在此列(保守放行)。 + */ +export function isSelfAnswerableQuestion(question: string): boolean { + const normalized = question.trim(); + if (!normalized) return false; + return SELF_ANSWERABLE_PATTERNS.some(pattern => pattern.test(normalized)); +} + +/** + * 判断 Reviewer 的回复是否「本身就是仓库内可查信息」(代码块或文件路径引用)。 + * + * 用途(G7):交互提问收到人工回复后直接转修复,若回复内容其实躺在仓库里, + * 说明这次提问疑似本可被门禁拦截——作为漏判候选回流 EverOS 供模式库扩充。 + * 保守判定:只认代码围栏与带扩展名的文件路径,纯文字方案讨论不算。 + */ +export function isRepoContentReply(body: string): boolean { + if (!body) return false; + if (/```/.test(body)) return true; + return /[\w@~.-]+(?:\/[\w@~.()-]+)+\.(?:ts|tsx|js|jsx|mts|cts|py|go|java|rs|vue|json|ya?ml|toml|md)(?::\d+)?\b/.test( + body + ); +} diff --git a/src/advance/classic/fix/commit-pipeline.ts b/src/advance/classic/fix/commit-pipeline.ts new file mode 100644 index 0000000..0e4bac0 --- /dev/null +++ b/src/advance/classic/fix/commit-pipeline.ts @@ -0,0 +1,180 @@ +/** + * 提交管道:框架侧的确定性兜底 + * + * 目标(见 docs/goals/maintainer-llm-centric-goal.md 子目标 B): + * - F2:commit message 三级兜底(EverOS 记忆 → 仓库静态探测 → 合规通用默认), + * LLM 只需提供"改了什么",格式拼装是框架的事; + * - F3:任何 commit/push 失败先由框架机械预处理(去 ANSI、截尾、归类、蒸馏), + * 可模板化修复的直接重试,不能的蒸馏成 ≤10 行诊断再交给上层; + * - L3:lint/test 类 hook 失败的蒸馏结果可回流修复循环,而非直接判死。 + */ + +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { stripTerminalControlCodes } from '../runners/shared/reply-safety.js'; + +/** commit/push 失败的机械归类 */ +export type CommitFailureKind = + | 'commit-message' + | 'lint' + | 'test' + | 'typecheck' + | 'permission' + | 'push' + | 'unknown'; + +/** 去除 ANSI 转义码,避免 hook 输出中的颜色控制字符干扰规范提取 */ +export function stripAnsiCodes(text: string): string { + return stripTerminalControlCodes(text); +} + +/** 保留 hook 输出尾部诊断,避免前置 lint/test 日志淹没最终拒绝原因 */ +export function extractCommitRejectionSection(text: string): string { + const normalized = text.replace(/\r\n?/g, '\n').trimEnd(); + const tailLines = normalized.split('\n').slice(-120).join('\n'); + return tailLines.slice(-8000); +} + +const COMMIT_MESSAGE_PATTERN = + /commit\s?message|提交信息|提交标题|conventional\s?commits|commitlint|header|subject|首行|格式.*不合规|不符合.*(?:规范|模板|约束|规则)/i; +const TEST_PATTERN = /\bFAIL\b|✗|✘|failed\s+tests?|Tests\s+\d+\s+failed|测试失败/i; +const LINT_PATTERN = /eslint|lint\s*错误|✖\s+\d+\s+problem|\d+\s+errors?/i; +const TYPECHECK_PATTERN = /tsc|TS\d{4}|type ?check|类型检查/i; +const PERMISSION_PATTERN = /permission\s+denied|403|401|unauthorized|forbidden|没有权限|权限不足/i; +const PUSH_PATTERN = /non-fast-forward|rejected|failed to push|推送被拒|冲突/i; + +/** + * 对 commit/push 失败输出做机械归类。 + * + * 只看蒸馏后的尾部诊断(最终拒绝原因通常在末尾),优先级: + * commit-message > test > typecheck > lint > permission > push > unknown。 + * commit-message 最优先:pre-commit hook 往往先跑 lint/test(产生大量噪音), + * 最后才以提交信息规范为由拒绝,尾部模式才是真实死因。 + */ +export function classifyCommitFailure(diagnostic: string): CommitFailureKind { + const tail = extractCommitRejectionSection(stripAnsiCodes(diagnostic)); + const tailLines = tail.split('\n').slice(-30).join('\n'); + if (COMMIT_MESSAGE_PATTERN.test(tailLines)) return 'commit-message'; + if (TEST_PATTERN.test(tailLines)) return 'test'; + if (TYPECHECK_PATTERN.test(tailLines)) return 'typecheck'; + if (LINT_PATTERN.test(tailLines)) return 'lint'; + if (PERMISSION_PATTERN.test(tailLines)) return 'permission'; + if (PUSH_PATTERN.test(tailLines)) return 'push'; + return 'unknown'; +} + +/** 各归类的一句话处置建议,供蒸馏诊断与上层决策使用 */ +const KIND_GUIDANCE: Record = { + 'commit-message': '提交信息不符合项目规范,应理解规则后重写 message 重试', + lint: 'pre-commit hook 的 lint 检查未通过,应回流修复循环消除新增 error 后重试', + test: 'pre-commit hook 的测试未通过,应回流修复循环修复失败用例后重试', + typecheck: 'pre-commit hook 的类型检查未通过,应回流修复循环消除类型错误后重试', + permission: 'git 权限不足,属于环境/凭据问题,不应重试,需人工介入', + push: 'push 被拒绝(多为分支冲突/非快进),应先同步远端再试,必要时人工介入', + unknown: '无法机械归类,需 LLM 阅读蒸馏诊断后判断', +}; + +/** + * 把任意 commit/push 失败输出蒸馏为 ≤ maxLines 行的诊断。 + * 第一行为归类与建议,其后为尾部关键证据——发布到 MR 的只能是这个, + * 而不是几千行的 hook 原文。 + */ +export function distillCommitFailure(rawError: string, maxLines = 10): string { + const kind = classifyCommitFailure(rawError); + const tail = extractCommitRejectionSection(stripAnsiCodes(rawError)) + .split('\n') + .filter(line => line.trim().length > 0); + const evidenceBudget = Math.max(1, maxLines - 1); + const evidence = tail + .slice(-evidenceBudget) + .map(line => (line.length > 800 ? `${line.slice(0, 799)}…` : line)); + const distilled = [`【提交失败分类: ${kind}】${KIND_GUIDANCE[kind]}`, ...evidence].join('\n'); + return distilled.length > 6_000 ? `${distilled.slice(0, 5_999)}…` : distilled; +} + +/** commitlint/husky 等静态配置探测结果 */ +const CONVENTIONAL_COMMITS_HINT = + 'Conventional Commits:格式 (): ,' + + 'type 通常为 feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert'; + +/** + * 静态探测仓库的提交信息规范(第二级兜底)。 + * + * 依次检查 commitlint 配置文件、package.json 的 commitlint 键、husky commit-msg 钩子; + * 命中即返回 Conventional Commits 提示。探测不到返回 undefined, + * 由调用方回退到合规通用默认 message。 + */ +export function detectCommitConvention(repoRoot: string): string | undefined { + try { + const commitlintFiles = [ + 'commitlint.config.js', + 'commitlint.config.ts', + 'commitlint.config.mjs', + 'commitlint.config.cjs', + '.commitlintrc', + '.commitlintrc.json', + '.commitlintrc.js', + '.commitlintrc.yml', + '.commitlintrc.yaml', + ]; + if (commitlintFiles.some(file => existsSync(join(repoRoot, file)))) { + return CONVENTIONAL_COMMITS_HINT; + } + const pkgPath = join(repoRoot, 'package.json'); + if (existsSync(pkgPath)) { + const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as Record; + if (pkg.commitlint || pkg['commitlint-config']) { + return CONVENTIONAL_COMMITS_HINT; + } + } + if (existsSync(join(repoRoot, '.husky', 'commit-msg'))) { + return CONVENTIONAL_COMMITS_HINT; + } + } catch { + // 探测失败不阻断提交,回退默认 + } + return undefined; +} + +const CONVENTIONAL_SUBJECT = /^[a-z]+(?:\([^)]*\))?:\s/i; + +/** 为朴素主题行补一个 Conventional Commits 前缀(若尚未具备) */ +export function ensureConventionalSubject(subject: string, type: string, scope: string): string { + const trimmed = subject.trim(); + if (CONVENTIONAL_SUBJECT.test(trimmed)) return trimmed; + return `${type}(${scope}): ${trimmed}`; +} + +/** 合规的单 finding 默认提交信息 */ +export function buildDefaultFixMessage(finding: { + message: string; + ruleId?: string; + file: string; + line: number; +}): string { + const subject = ensureConventionalSubject(finding.message, 'fix', 'review'); + return [ + subject, + '', + `规则: ${finding.ruleId ?? 'N/A'}`, + `文件: ${finding.file}:${finding.line}`, + ].join('\n'); +} + +/** 合规的批量修复默认提交信息 */ +export function buildDefaultBatchMessage(appliedFiles: string[], deletedFiles: string[]): string { + const total = appliedFiles.length + deletedFiles.length; + const lines = [`fix(review): 批量修复 ${total} 个 Reviewer 问题`, '']; + if (appliedFiles.length > 0) { + lines.push('修改文件:', ...appliedFiles.map(f => `- ${f}`), ''); + } + if (deletedFiles.length > 0) { + lines.push('删除文件:', ...deletedFiles.map(f => `- ${f}`), ''); + } + return lines.join('\n'); +} + +/** 合规的删除文件默认提交信息 */ +export function buildDefaultDeleteMessage(fileName: string): string { + return `chore(review): 移除不应上传的文件 ${fileName}`; +} diff --git a/src/advance/classic/fix/fix-tool-loop.ts b/src/advance/classic/fix/fix-tool-loop.ts index 78edf70..caf1403 100755 --- a/src/advance/classic/fix/fix-tool-loop.ts +++ b/src/advance/classic/fix/fix-tool-loop.ts @@ -48,6 +48,12 @@ export interface FixToolLoopOptions { maxReadOnlySteps?: number; /** 触发只读探索提醒的步数阈值,默认 maxReadOnlySteps - 2 */ readOnlyReminderStep?: number; + /** + * 只读熔断前的「带诊断谢幕」行动机会步数,默认 3。 + * 熔断时先把 already-fixed 回查结论注入上下文,再给 LLM 最后一轮 + * 修改或明确 finish 的机会,避免无诊断机械暴毙。 + */ + finalActingSteps?: number; /** 验证策略,默认 WorkspaceValidationStrategy */ validationStrategy?: ValidationStrategy; /** 可选的 prompt 加载器,默认使用全局 loader */ @@ -65,6 +71,13 @@ function isTruncatedStopReason(stopReason: string): boolean { return stopReason === 'length' || stopReason === 'max_tokens'; } +/** 兼容旧模型:识别“无需改动/已经修复”的自然语言 finish 原因。 */ +export function looksLikeAlreadyFixedClaim(reason: string): boolean { + return /already\s+(?:been\s+)?(?:fixed|resolved)|no\s+(?:additional\s+)?(?:code\s+)?change|无需(?:额外|再次|重复)?修改|无需再改|已(?:经)?修复|问题(?:已)?不存在|当前代码.{0,20}(?:满足|已包含|已覆盖)/i.test( + reason + ); +} + export class FixToolLoop { private readonly llmClient: LlmClient; private readonly worktreeManager: WorktreeManager; @@ -80,6 +93,7 @@ export class FixToolLoop { private readonly extraSystemPrompt: string; private readonly maxReadOnlySteps: number; private readonly readOnlyReminderStep: number; + private readonly finalActingSteps: number; private readonly registry: ToolRegistry; private readonly executor: ToolExecutor; private readonly validationStrategy: ValidationStrategy; @@ -101,6 +115,10 @@ export class FixToolLoop { private noToolCallRetries = 0; private unchangedFinishRetries = 0; private alreadyFixedRecheckAttempted = false; + private finalActingRoundUsed = false; + /** 最近一次 already-fixed 回查的原始结论,用于谢幕消息与失败原因诊断 */ + private lastRecheckVerdict: { alreadyFixed: boolean; reason: string; evidence?: string } | null = + null; constructor(options: FixToolLoopOptions) { this.llmClient = options.llmClient; @@ -120,6 +138,7 @@ export class FixToolLoop { options.maxReadOnlySteps ?? Math.max(8, this.maxStepsWithoutProgress + 3); this.readOnlyReminderStep = options.readOnlyReminderStep ?? Math.max(1, this.maxReadOnlySteps - 2); + this.finalActingSteps = Math.max(1, options.finalActingSteps ?? 3); this.promptLoader = options.promptLoader ?? defaultPromptLoader; this.recheckAlreadyFixed = options.recheckAlreadyFixed; this.registry = new ToolRegistry(FIX_TOOLS); @@ -306,10 +325,27 @@ export class FixToolLoop { if (this.stepsWithoutFileChange >= this.maxReadOnlySteps) { const rechecked = await this.tryRecheckAlreadyFixed(); if (rechecked) return rechecked; + if (!this.finalActingRoundUsed) { + // 带诊断谢幕:把 already-fixed 回查结论回灌给 LLM, + // 给最后一轮「直接修改或明确 finish 并说明理由」的机会,避免无诊断机械暴毙。 + this.finalActingRoundUsed = true; + this.messages.push({ + role: 'user', + content: this.promptLoader.load('fix-tool-loop-final-acting-round', { + steps: String(this.finalActingSteps), + verdictReason: this.lastRecheckVerdict?.reason ?? '框架无法确认问题是否已消失', + verdictEvidence: this.lastRecheckVerdict?.evidence ?? '无', + }), + }); + this.stepsWithoutFileChange = Math.max(0, this.maxReadOnlySteps - this.finalActingSteps); + continue; + } return { success: false, reason: this.promptLoader.load('fix-tool-loop-read-only-failure-reason', { steps: String(this.stepsWithoutFileChange), + verdictReason: this.lastRecheckVerdict?.reason ?? '未执行回查', + verdictEvidence: this.lastRecheckVerdict?.evidence ?? '无', }), }; } @@ -350,6 +386,7 @@ export class FixToolLoop { this.alreadyFixedRecheckAttempted = true; try { const result = await this.recheckAlreadyFixed(); + this.lastRecheckVerdict = result; if (!result.alreadyFixed) return null; return { success: true, @@ -368,6 +405,14 @@ export class FixToolLoop { return Array.from(this.appliedFiles); } + /** + * 本轮 run() 是否动用了「最后一轮行动机会」(只读熔断前的 final acting round)。 + * 供外部过程指标(readOnlyFinalActingRounds)使用。 + */ + wasFinalActingRoundUsed(): boolean { + return this.finalActingRoundUsed; + } + /** * 估算消息历史的总字符数,用于诊断上下文膨胀。 * 需覆盖所有部分类型:text、tool_result.content、tool_use.input。 @@ -590,8 +635,28 @@ export class FixToolLoop { private async handleFinish(finishCall: ToolCall): Promise { const success = finishCall.input.success === true; const reason = String(finishCall.input.reason ?? ''); + const hasNoFileChanges = this.appliedFiles.size === 0 && this.deletedFiles.size === 0; + const claimsAlreadyFixed = + finishCall.input.alreadyFixed === true || (!success && looksLikeAlreadyFixedClaim(reason)); + + if (hasNoFileChanges && claimsAlreadyFixed) { + const rechecked = await this.tryRecheckAlreadyFixed(); + if (rechecked) return rechecked; + return { + success: false, + reason: [ + '模型判断问题已经修复,但框架回查未确认该结论。', + this.lastRecheckVerdict?.reason ?? (reason || '未提供可验证证据'), + ].join(' '), + }; + } if (success) { + if (hasNoFileChanges) { + const rechecked = await this.tryRecheckAlreadyFixed(); + if (rechecked) return rechecked; + } + // LLM 可能直接调用 finish 却忘记调用 validate;自动补一次验证,避免"未调用 validate"的误判。 if (!this.lastValidationResult?.passed) { const raw = await this.worktreeManager.validate(); @@ -613,7 +678,7 @@ export class FixToolLoop { }; } - if (this.appliedFiles.size === 0 && this.deletedFiles.size === 0) { + if (hasNoFileChanges) { return { success: false, reason: this.promptLoader.load('fix-tool-loop-no-change-failure-reason'), diff --git a/src/advance/classic/fix/maintainer-actor.ts b/src/advance/classic/fix/maintainer-actor.ts index a3ebcd3..1abf103 100755 --- a/src/advance/classic/fix/maintainer-actor.ts +++ b/src/advance/classic/fix/maintainer-actor.ts @@ -1,13 +1,21 @@ import type { GitLabProvider } from '../provider/gitlab-provider.js'; -import type { MergeRequest, ReviewFinding, Discussion } from '../provider/types.js'; +import type { + MergeRequest, + ReviewFinding, + Discussion, + CiFailureReport, +} from '../provider/types.js'; import type { LlmClient } from '../../llm/client.js'; -import type { WorktreeManager } from '../worktree/worktree-manager.js'; +import type { WorktreeChangedFile, WorktreeManager } from '../worktree/worktree-manager.js'; import type { MaintainerBrain, MaintainerDecision } from './maintainer-brain.js'; +import type { IssueScope } from './issue-scope.js'; import type { CognitiveDecision } from './cognitive-types.js'; import type { MrAgentState } from '../runners/shared/state-utils.js'; import type { IMemoryClient } from '../memory/types.js'; import type { RecallPlanner } from '../memory/recall-planner.js'; import type { DiscussionDeliveryResult } from '../runners/shared/discussion-delivery.js'; +import { extractFileCandidatesFromTrace } from '../runners/shared/mr-lifecycle.js'; +import type { MrLifecycleMetrics } from '../runners/shared/mr-lifecycle.js'; import { deliverDiscussionReply, isDiscussionDeliveryPending, @@ -16,6 +24,21 @@ import { FixToolLoop } from './fix-tool-loop.js'; import { formatAgentFooter, MAINTAINER_ROLE_LABEL } from '../runners/shared/review-utils.js'; import { basename } from 'node:path'; import { defaultPromptLoader } from '../../llm/prompts/loader.js'; +import { + classifyCommitFailure, + detectCommitConvention, + distillCommitFailure, + extractCommitRejectionSection, + stripAnsiCodes, + buildDefaultFixMessage as pipelineBuildDefaultFixMessage, + buildDefaultBatchMessage as pipelineBuildDefaultBatchMessage, + buildDefaultDeleteMessage, +} from './commit-pipeline.js'; +import { isSelfAnswerableQuestion } from './ask-gate.js'; +import { compactDiscussionReason } from '../runners/shared/reply-safety.js'; + +// 兼容既有引用(含测试):从本模块再导出,实现统一收敛到 commit-pipeline +export { stripAnsiCodes, extractCommitRejectionSection }; export interface MaintainerActorOptions { /** GitLab API 提供者 */ @@ -34,6 +57,8 @@ export interface MaintainerActorOptions { recallPlanner?: RecallPlanner; /** 远端副作用状态变化后的即时 checkpoint */ checkpoint?: () => void; + /** 可选的 M 系列过程指标计数器(M1/M2/M3/M5/M6 由本类自增) */ + metrics?: MrLifecycleMetrics; } export interface MaintainerActionResult { @@ -45,6 +70,29 @@ export interface MaintainerActionResult { error?: string; } +export type BatchFixItemStatus = 'fixed' | 'already-fixed' | 'failed' | 'deferred'; + +export interface BatchFixItemResult { + file: string; + line: number; + status: BatchFixItemStatus; + reason?: string; +} + +export interface BatchFixResult { + success: boolean; + reason: string; + appliedFiles: string[]; + deletedFiles: string[]; + alreadyFixedItems: Array<{ file: string; line: number; reason: string }>; + itemResults: BatchFixItemResult[]; +} + +export interface ApplyDecisionOptions { + /** 单次修复失败后是否立即向 Reviewer 求助;Runner 默认自行管理重试次数。 */ + askOnFixFailure?: boolean; +} + /** * MaintainerActor * @@ -62,6 +110,114 @@ export class MaintainerActor { constructor(private readonly options: MaintainerActorOptions) {} + /** 自增一个 M 系列过程指标(metrics 未注入时静默跳过) */ + private incrMetric( + key: + | 'readOnlyFinalActingRounds' + | 'commitFirstTryPasses' + | 'commitFirstTryRejections' + | 'askGateInterceptions' + | 'hookFailureReflows' + ): void { + const m = this.options.metrics; + if (m) { + m[key] = (m[key] ?? 0) + 1; + } + } + + /** loop.run() 之后检查是否动用了最后一轮行动机会,计入 M1 */ + private trackFinalActingRound(loop: FixToolLoop): void { + if (loop.wasFinalActingRoundUsed()) { + this.incrMetric('readOnlyFinalActingRounds'); + } + } + + /** 修复任务允许坏基线进入工具循环,但依赖安装失败仍然直接中断。 */ + private async prepareRepairEnvironment(): Promise { + const result = await this.options.worktreeManager.prepareEnvironment({ + allowCompileFailure: true, + }); + return result?.compilePackagesFailure; + } + + /** 把修复前已存在的编译失败明确标记为基线,避免错误归因到当前 finding。 */ + private buildBaselineFailurePrompt(failure?: string): string | undefined { + if (!failure) return undefined; + return [ + '环境准备阶段检测到 source branch 在本轮修改前已经无法通过 compile:packages。', + '以下内容属于修复前基线:不要把它归因到当前 finding;如果诊断明确指向当前 finding 的目标文件,可一并消除,否则只确保本轮不新增错误。', + compactDiscussionReason(failure, 4_000), + ].join('\n\n'); + } + + private normalizeRepoPath(filePath: string): string { + return filePath.replace(/\\/g, '/').replace(/^\.\//, ''); + } + + /** 优先读取 git status;测试替身未实现时才退回工具循环记录。 */ + private async listChangedFiles( + fallbackApplied: string[] = [], + fallbackDeleted: string[] = [] + ): Promise { + const manager = this.options.worktreeManager as WorktreeManager & { + listChangedFiles?: () => Promise; + }; + if (typeof manager.listChangedFiles === 'function') { + return (await manager.listChangedFiles()).map(file => ({ + path: this.normalizeRepoPath(file.path), + deleted: file.deleted, + })); + } + + const changed = new Map(); + for (const filePath of fallbackApplied) { + const path = this.normalizeRepoPath(filePath); + changed.set(path, { path, deleted: false }); + } + for (const filePath of fallbackDeleted) { + const path = this.normalizeRepoPath(filePath); + changed.set(path, { path, deleted: true }); + } + return Array.from(changed.values()); + } + + private async resolveTargetPaths(filePath: string): Promise> { + const targets = new Set([this.normalizeRepoPath(filePath)]); + try { + const resolved = await this.options.worktreeManager.resolveFilePath(filePath); + if (resolved) targets.add(this.normalizeRepoPath(resolved)); + } catch { + // 路径解析失败时保留 Reviewer 给出的原始路径做保守校验 + } + return targets; + } + + private assertWriteScope( + changes: WorktreeChangedFile[], + allowedPaths: Set, + context: string + ): void { + const unexpected = changes + .map(file => file.path) + .filter(filePath => !allowedPaths.has(this.normalizeRepoPath(filePath))); + if (unexpected.length > 0) { + throw new Error(`${context} 越界修改了非目标文件: ${unexpected.join(', ')}`); + } + } + + private syncChangedFileSets( + changes: WorktreeChangedFile[], + appliedFiles: Set, + deletedFiles: Set + ): void { + appliedFiles.clear(); + deletedFiles.clear(); + for (const change of changes) { + if (change.deleted) deletedFiles.add(change.path); + else appliedFiles.add(change.path); + } + } + /** * 对单条 finding/discussion 应用决策 */ @@ -70,13 +226,15 @@ export class MaintainerActor { discussion: Discussion, finding: ReviewFinding, decision: MaintainerDecision, - state: MrAgentState + state: MrAgentState, + options: ApplyDecisionOptions = {} ): Promise { + const askOnFixFailure = options.askOnFixFailure ?? true; switch (decision.action) { case 'fix': { if (decision.deleteFile) { const result = await this.executeDeleteFileFix(mr, discussion, finding, decision, state); - if (!result.codeApplied) { + if (!result.codeApplied && askOnFixFailure) { const question = defaultPromptLoader.load('maintainer-delete-failed-ask', { file: finding.file, }); @@ -87,7 +245,7 @@ export class MaintainerActor { return result; } const result = await this.executeFix(mr, discussion, finding, decision, state); - if (!result.codeApplied) { + if (!result.codeApplied && askOnFixFailure) { const question = defaultPromptLoader.load('maintainer-fix-failed-ask', { fileLine: `${finding.file}:${finding.line}`, }); @@ -99,6 +257,31 @@ export class MaintainerActor { } case 'ask': { const question = decision.question ?? defaultPromptLoader.load('maintainer-ask-clarify'); + // L2 ask 门禁:仓库内可自查的索问不出现在 MR 上,转为修复自查; + // 自查失败才退回提问,且使用修复失败模板而非原索问。 + if (decision.question && isSelfAnswerableQuestion(decision.question)) { + this.incrMetric('askGateInterceptions'); + console.log( + `[MaintainerActor] ask 门禁拦截仓库内可自查的索问,转为修复自查: ${decision.question}` + ); + decision.action = 'fix'; + decision.fixDescription = [ + decision.fixDescription, + `原提问被框架门禁拦截(所索信息在仓库内可自行查阅,禁止向 Reviewer 索要文件内容/代码片段):${decision.question}`, + ] + .filter(Boolean) + .join('\n'); + const result = await this.executeFix(mr, discussion, finding, decision, state); + if (!result.codeApplied && askOnFixFailure) { + const fallbackQuestion = defaultPromptLoader.load('maintainer-fix-failed-ask', { + fileLine: `${finding.file}:${finding.line}`, + }); + decision.question = fallbackQuestion; + const askResult = await this.ask(mr, discussion, fallbackQuestion, finding.file, state); + return this.mergeActionResults(result, askResult, false); + } + return result; + } return this.ask(mr, discussion, question, finding.file, state); } case 'ignore': { @@ -118,29 +301,42 @@ export class MaintainerActor { askedItems: Array<{ fileLine: string; text: string }>, ignoredItems: Array<{ fileLine: string; reason: string }>, alreadyFixedItems: Array<{ fileLine: string; reason: string }>, - state: MrAgentState + state: MrAgentState, + deferredItems: string[] = [] ): Promise { const sections: string[] = []; + const existingAwaiting = state.interactiveThreads?.[discussion.id]; if (fixedItems.length > 0) { sections.push(`✅ 已自动修复并推送:\n${fixedItems.map(item => `- ${item}`).join('\n')}`); } if (alreadyFixedItems.length > 0) { sections.push( - `✅ 已修复(无需重复修改):\n${alreadyFixedItems.map(item => `- ${item.fileLine}: ${item.reason}`).join('\n')}` + `✅ 已修复(无需重复修改):\n${alreadyFixedItems.map(item => `- ${item.fileLine}: ${compactDiscussionReason(item.reason)}`).join('\n')}` ); } if (failedItems.length > 0) { - sections.push(`⏸️ 尝试修复未成功:\n${failedItems.map(item => `- ${item}`).join('\n')}`); + sections.push( + `⏸️ 尝试修复未成功:\n${failedItems.map(item => `- ${compactDiscussionReason(item)}`).join('\n')}` + ); + } + if (deferredItems.length > 0) { + sections.push( + `⏭️ 本轮暂缓,将继续处理:\n${deferredItems.map(item => `- ${item}`).join('\n')}` + ); } if (askedItems.length > 0) { sections.push( `❓ 需要 Reviewer 澄清:\n${askedItems.map(item => `- ${item.fileLine}: ${item.text}`).join('\n')}` ); + } else if (existingAwaiting) { + sections.push( + `❓ 仍待 Reviewer 澄清:\n- ${existingAwaiting.filePath || '当前 finding'}: ${existingAwaiting.question}` + ); } if (ignoredItems.length > 0) { sections.push( - `📝 已忽略:\n${ignoredItems.map(item => `- ${item.fileLine}: ${item.reason}`).join('\n')}` + `📝 已忽略:\n${ignoredItems.map(item => `- ${item.fileLine}: ${compactDiscussionReason(item.reason)}`).join('\n')}` ); } @@ -151,13 +347,32 @@ export class MaintainerActor { const body = `${sections.join('\n\n')}\n\n${formatAgentFooter(MAINTAINER_ROLE_LABEL, this.options.maintainerName)}`; console.log( - `[MaintainerActor] discussion ${discussion.id} 汇总回复 counts=fixed:${fixedItems.length},alreadyFixed:${alreadyFixedItems.length},failed:${failedItems.length},asked:${askedItems.length},ignored:${ignoredItems.length}` + `[MaintainerActor] discussion ${discussion.id} 汇总回复 counts=fixed:${fixedItems.length},alreadyFixed:${alreadyFixedItems.length},failed:${failedItems.length},deferred:${deferredItems.length},asked:${askedItems.length},ignored:${ignoredItems.length}` ); // 已修复、已确认无需重复修改、已忽略都属于终态;无失败/待澄清项时 resolve。 const completedItems = fixedItems.length + alreadyFixedItems.length + ignoredItems.length; - const shouldResolve = completedItems > 0 && failedItems.length === 0 && askedItems.length === 0; - const pendingQuestion = askedItems[0]; + const existingAskedAt = + existingAwaiting?.askedAt ?? + state.maintainerThreadState?.[discussion.id]?.delivery?.awaitingReplyAt; + const pendingQuestion = askedItems[0] + ? { + question: askedItems[0].text, + filePath: askedItems[0].fileLine.split(':')[0], + askedAt: existingAskedAt, + } + : existingAwaiting + ? { + question: existingAwaiting.question, + filePath: existingAwaiting.filePath ?? '', + askedAt: existingAwaiting.askedAt, + } + : undefined; + const shouldResolve = + completedItems > 0 && + failedItems.length === 0 && + deferredItems.length === 0 && + !pendingQuestion; const result = await this.deliverReply( mr, discussion, @@ -165,17 +380,16 @@ export class MaintainerActor { shouldResolve, state, pendingQuestion - ? { question: pendingQuestion.text, filePath: pendingQuestion.fileLine.split(':')[0] } - : undefined ); - if (result.replyPosted && askedItems.length > 0) { + if (result.replyPosted && pendingQuestion) { this.setAwaitingReply( state, discussion.id, - askedItems[0].text, - askedItems[0].fileLine, - state.maintainerThreadState?.[discussion.id]?.delivery?.awaitingReplyAt + pendingQuestion.question, + pendingQuestion.filePath, + pendingQuestion.askedAt ?? + state.maintainerThreadState?.[discussion.id]?.delivery?.awaitingReplyAt ); this.options.checkpoint?.(); console.log(`[MaintainerActor] 汇总 discussion ${discussion.id} 有待澄清项,等待回复`); @@ -207,13 +421,7 @@ export class MaintainerActor { if (!isDiscussionDeliveryPending(threadState?.delivery)) return null; const delivery = threadState?.delivery; if (!delivery) return null; - return this.deliverReply( - mr, - discussion, - delivery.replyBody, - delivery.resolveRequired, - state - ); + return this.deliverReply(mr, discussion, delivery.replyBody, delivery.resolveRequired, state); } /** 对账任意已记录投递,包括远端可能已被删除的完成态回复。 */ @@ -224,13 +432,7 @@ export class MaintainerActor { ): Promise { const delivery = state.maintainerThreadState?.[discussion.id]?.delivery; if (!delivery) return null; - return this.deliverReply( - mr, - discussion, - delivery.replyBody, - delivery.resolveRequired, - state - ); + return this.deliverReply(mr, discussion, delivery.replyBody, delivery.resolveRequired, state); } /** @@ -241,39 +443,112 @@ export class MaintainerActor { fixableItems: Array<{ finding: ReviewFinding; fileContent: string; + scope?: IssueScope; deleteFile?: boolean; }>, - originalComment: string - ): Promise<{ - success: boolean; - reason: string; - appliedFiles: string[]; - deletedFiles: string[]; - alreadyFixedItems: Array<{ file: string; line: number; reason: string }>; - }> { + _originalComment: string + ): Promise { console.log(`[MaintainerActor] 开始批量修复,${fixableItems.length} 个 finding`); + type PendingBatchFixItemResult = Omit & { + status: BatchFixItemStatus | 'pending-commit'; + }; + const appliedFiles = new Set(); + const deletedFiles = new Set(); + const approvedChangedPaths = new Set(); + const alreadyFixedItems: Array<{ file: string; line: number; reason: string }> = []; + const itemResults: PendingBatchFixItemResult[] = []; + let currentIndex = 0; + let commitStarted = false; + + const addDeferredItems = (startIndex: number, reason: string): void => { + for (const item of fixableItems.slice(startIndex)) { + if ( + itemResults.some( + result => result.file === item.finding.file && result.line === item.finding.line + ) + ) { + continue; + } + itemResults.push({ + file: item.finding.file, + line: item.finding.line, + status: 'deferred', + reason, + }); + } + }; + + const buildResult = (success: boolean, reason: string): BatchFixResult => ({ + success, + reason: compactDiscussionReason(reason), + appliedFiles: Array.from(appliedFiles), + deletedFiles: Array.from(deletedFiles), + alreadyFixedItems, + itemResults: itemResults.map(result => ({ + ...result, + status: + result.status === 'pending-commit' + ? success + ? 'fixed' + : commitStarted + ? 'failed' + : 'deferred' + : result.status, + reason: + result.status === 'pending-commit' && !success + ? commitStarted + ? compactDiscussionReason(reason) + : '批量事务尚未提交,将在下一轮重新处理' + : result.reason, + })), + }); + try { console.log(`[MaintainerActor] 阶段=worktree 准备/更新 worktree`); await this.options.worktreeManager.ensureWorktree(); console.log(`[MaintainerActor] 阶段=checkout 切换到 source branch: ${mr.sourceBranch}`); await this.options.worktreeManager.checkoutBranch(mr.sourceBranch); console.log(`[MaintainerActor] 阶段=prepare 准备运行环境`); - await this.options.worktreeManager.prepareEnvironment(); + const baselineFailure = await this.prepareRepairEnvironment(); + const baselineFailurePrompt = this.buildBaselineFailurePrompt(baselineFailure); - const appliedFiles = new Set(); - const deletedFiles = new Set(); - const alreadyFixedItems: Array<{ file: string; line: number; reason: string }> = []; - - for (const item of fixableItems) { + for (currentIndex = 0; currentIndex < fixableItems.length; currentIndex++) { + const item = fixableItems[currentIndex]; const { finding } = item; if (item.deleteFile) { console.log(`[MaintainerActor] 批量修复中删除文件: ${finding.file}`); const resolved = await this.options.worktreeManager.resolveFilePath(finding.file); - if (resolved) { - await this.options.worktreeManager.removeFile(resolved); - deletedFiles.add(finding.file); + if (!resolved) { + const reason = `无法定位待删除文件 ${finding.file}`; + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'failed', + reason, + }); + addDeferredItems(currentIndex + 1, '前序 finding 未完成,本轮尚未执行'); + await this.recordFixOutcome(mr.iid, finding, false, reason); + return buildResult(false, reason); } + await this.options.worktreeManager.removeFile(resolved); + const targetPaths = new Set([ + this.normalizeRepoPath(finding.file), + this.normalizeRepoPath(resolved), + ]); + const changes = await this.listChangedFiles(Array.from(appliedFiles), [ + ...Array.from(deletedFiles), + finding.file, + ]); + const allowedPaths = new Set([...approvedChangedPaths, ...targetPaths]); + this.assertWriteScope(changes, allowedPaths, `finding ${finding.file}:${finding.line}`); + this.syncChangedFileSets(changes, appliedFiles, deletedFiles); + for (const change of changes) approvedChangedPaths.add(change.path); + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'pending-commit', + }); continue; } @@ -284,53 +559,108 @@ export class MaintainerActor { mr, memoryClient: this.options.memoryClient, recallPlanner: this.options.recallPlanner, - extraSystemPrompt: `这是同一条 discussion 中的批量修复任务之一。原始评论:\n${originalComment}`, + extraSystemPrompt: [ + `这是同一条 discussion 中的批量修复任务之一。当前只处理 ${finding.file}:${finding.line};严禁引用、判断或复用同一 discussion 中其他 finding 的文件、函数和证据。`, + item.scope === 'cross-file' + ? '该 finding 被识别为跨文件问题;仅在 Reviewer 问题确实要求时修改必要调用点。' + : '该 finding 是局部问题,只允许修改目标文件。', + baselineFailurePrompt, + ] + .filter(Boolean) + .join('\n\n'), recheckAlreadyFixed: () => this.options.brain.recheckAlreadyFixed(finding), }); const result = await loop.run(); + this.trackFinalActingRound(loop); console.log( `[MaintainerActor] finding ${finding.file}:${finding.line} 修复结果: success=${result.success}, reason=${result.reason}` ); if (result.alreadyFixed) { + const reason = compactDiscussionReason(result.evidence || result.reason); alreadyFixedItems.push({ file: finding.file, line: finding.line, - reason: result.evidence || result.reason, + reason, + }); + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'already-fixed', + reason, }); + await this.recordFixOutcome(mr.iid, finding, true, `already-fixed: ${reason}`); continue; } if (!result.success) { - return { - success: false, - reason: result.reason, - appliedFiles: Array.from(appliedFiles), - deletedFiles: Array.from(deletedFiles), - alreadyFixedItems, - }; + const reason = compactDiscussionReason(result.reason); + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'failed', + reason, + }); + addDeferredItems(currentIndex + 1, '前序 finding 未完成,本轮尚未执行'); + await this.recordFixOutcome(mr.iid, finding, false, reason); + return buildResult(false, reason); } - for (const f of loop.getAppliedFiles()) { - appliedFiles.add(f); + const loopAppliedFiles = loop.getAppliedFiles(); + const loopDeletedFiles = loop.getDeletedFiles(); + const changes = await this.listChangedFiles( + [...Array.from(appliedFiles), ...loopAppliedFiles], + [...Array.from(deletedFiles), ...loopDeletedFiles] + ); + const targetPaths = await this.resolveTargetPaths(finding.file); + const changedPaths = new Set(changes.map(change => change.path)); + const targetChanged = Array.from(targetPaths).some(target => changedPaths.has(target)); + const introducedChange = changes.some(change => !approvedChangedPaths.has(change.path)); + if (item.scope !== 'cross-file') { + const allowedPaths = new Set([...approvedChangedPaths, ...targetPaths]); + this.assertWriteScope(changes, allowedPaths, `finding ${finding.file}:${finding.line}`); } - for (const f of loop.getDeletedFiles()) { - deletedFiles.add(f); + if ( + (item.scope === 'cross-file' && !introducedChange) || + (!targetChanged && item.scope !== 'cross-file') + ) { + const reason = '修复循环未修改 finding 指向的目标文件'; + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'failed', + reason, + }); + addDeferredItems(currentIndex + 1, '前序 finding 未完成,本轮尚未执行'); + await this.recordFixOutcome(mr.iid, finding, false, reason); + return buildResult(false, reason); } + this.syncChangedFileSets(changes, appliedFiles, deletedFiles); + for (const change of changes) approvedChangedPaths.add(change.path); + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'pending-commit', + }); } if (appliedFiles.size === 0 && deletedFiles.size === 0 && alreadyFixedItems.length === 0) { - return { - success: false, - reason: '没有文件被修改或删除', - appliedFiles: [], - deletedFiles: [], - alreadyFixedItems: [], - }; + return buildResult(false, '没有文件被修改、删除,也没有确认 already-fixed'); } const changeDescription = [ + `修复项:\n${fixableItems + .filter(item => + itemResults.some( + result => + result.status === 'pending-commit' && + result.file === item.finding.file && + result.line === item.finding.line + ) + ) + .map(item => `- ${item.finding.file}:${item.finding.line} — ${item.finding.message}`) + .join('\n')}`, appliedFiles.size > 0 ? `修改文件:\n${Array.from(appliedFiles) .map(f => `- ${f}`) @@ -346,25 +676,63 @@ export class MaintainerActor { .join('\n'); if (appliedFiles.size > 0 || deletedFiles.size > 0) { console.log(`[MaintainerActor] 阶段=commit-push 批量提交到分支: ${mr.sourceBranch}`); - await this.commitWithConventionRetry(mr.sourceBranch, changeDescription, () => - buildDefaultBatchMessage(Array.from(appliedFiles), Array.from(deletedFiles)) + const baseFinding = fixableItems[0].finding; + commitStarted = true; + await this.commitWithConventionRetry( + mr.sourceBranch, + changeDescription, + () => buildDefaultBatchMessage(Array.from(appliedFiles), Array.from(deletedFiles)), + distilledFailure => this.reflowAfterHookFailure(mr, baseFinding, distilledFailure), + async () => { + const changes = await this.listChangedFiles( + Array.from(appliedFiles), + Array.from(deletedFiles) + ); + this.assertWriteScope(changes, approvedChangedPaths, '批量修复提交前校验'); + } ); } - return { - success: true, - reason: - appliedFiles.size > 0 || deletedFiles.size > 0 - ? '批量修复已推送至 source branch' - : '所有 finding 在当前代码中均已修复,无需提交', - appliedFiles: Array.from(appliedFiles), - deletedFiles: Array.from(deletedFiles), - alreadyFixedItems, - }; + const reason = + appliedFiles.size > 0 || deletedFiles.size > 0 + ? '批量修复已推送至 source branch' + : '所有 finding 在当前代码中均已修复,无需提交'; + for (const result of itemResults) { + if (result.status === 'pending-commit') { + const finding = fixableItems.find( + item => item.finding.file === result.file && item.finding.line === result.line + )?.finding; + if (finding) await this.recordFixOutcome(mr.iid, finding, true, reason); + } + } + return buildResult(true, reason); } catch (err) { - const reason = err instanceof Error ? err.message : String(err); + const reason = compactDiscussionReason(err instanceof Error ? err.message : String(err)); console.error(`[MaintainerActor] 批量修复异常: ${reason}`); - return { success: false, reason, appliedFiles: [], deletedFiles: [], alreadyFixedItems: [] }; + if (commitStarted) { + for (const result of itemResults) { + if (result.status !== 'pending-commit') continue; + const finding = fixableItems.find( + item => item.finding.file === result.file && item.finding.line === result.line + )?.finding; + if (finding) await this.recordFixOutcome(mr.iid, finding, false, reason); + } + } else if (currentIndex < fixableItems.length) { + const finding = fixableItems[currentIndex].finding; + if ( + !itemResults.some(result => result.file === finding.file && result.line === finding.line) + ) { + itemResults.push({ + file: finding.file, + line: finding.line, + status: 'failed', + reason, + }); + await this.recordFixOutcome(mr.iid, finding, false, reason); + } + addDeferredItems(currentIndex + 1, '前序 finding 异常中断,本轮尚未执行'); + } + return buildResult(false, reason); } } @@ -398,7 +766,8 @@ export class MaintainerActor { await this.options.worktreeManager.checkoutBranch(mr.sourceBranch); console.log(`[MaintainerActor] 阶段=prepare 准备运行环境`); - await this.options.worktreeManager.prepareEnvironment(); + const baselineFailure = await this.prepareRepairEnvironment(); + const baselineFailurePrompt = this.buildBaselineFailurePrompt(baselineFailure); const loop = new FixToolLoop({ llmClient: this.options.llmClient, @@ -407,16 +776,26 @@ export class MaintainerActor { mr, memoryClient: this.options.memoryClient, recallPlanner: this.options.recallPlanner, - extraSystemPrompt, + extraSystemPrompt: [ + extraSystemPrompt, + decision.scope === 'cross-file' + ? '该 finding 被识别为跨文件问题;仅修改解决 Reviewer 问题所必需的文件。' + : '该 finding 是局部问题,只允许修改目标文件。', + baselineFailurePrompt, + ] + .filter(Boolean) + .join('\n\n'), recheckAlreadyFixed: () => this.options.brain.recheckAlreadyFixed(finding), }); const fixResult = await loop.run(); + this.trackFinalActingRound(loop); console.log( `[MaintainerActor] 修复结果: success=${fixResult.success}, reason=${fixResult.reason}` ); if (fixResult.alreadyFixed) { + await this.recordFixOutcome(mr.iid, finding, true, `already-fixed: ${fixResult.reason}`); decision.action = 'ignore'; decision.alreadyFixed = true; decision.reason = fixResult.reason; @@ -426,14 +805,38 @@ export class MaintainerActor { } if (!fixResult.success) { + await this.recordFixOutcome(mr.iid, finding, false, fixResult.reason); return this.emptyActionResult(false, fixResult.reason); } + const changes = await this.listChangedFiles(loop.getAppliedFiles(), loop.getDeletedFiles()); + if (changes.length === 0) { + return this.emptyActionResult(false, '修复循环结束后 git 工作区没有实际变更'); + } + const targetPaths = await this.resolveTargetPaths(finding.file); + if (decision.scope !== 'cross-file') { + this.assertWriteScope(changes, targetPaths, `finding ${finding.file}:${finding.line}`); + const targetChanged = changes.some(change => targetPaths.has(change.path)); + if (!targetChanged) { + return this.emptyActionResult(false, '修复循环未修改 finding 指向的目标文件'); + } + } + const approvedChangedPaths = new Set(changes.map(change => change.path)); + console.log(`[MaintainerActor] 阶段=commit-push 提交并推送修复到分支: ${mr.sourceBranch}`); await this.commitWithConventionRetry( mr.sourceBranch, `问题: ${finding.message}\n规则: ${finding.ruleId ?? 'N/A'}\n文件: ${finding.file}:${finding.line}`, - () => buildDefaultFixMessage(finding) + () => buildDefaultFixMessage(finding), + distilledFailure => + this.reflowAfterHookFailure(mr, syntheticFinding, distilledFailure, extraSystemPrompt), + async () => { + const currentChanges = await this.listChangedFiles( + loop.getAppliedFiles(), + loop.getDeletedFiles() + ); + this.assertWriteScope(currentChanges, approvedChangedPaths, '单条修复提交前校验'); + } ); const cognitive = decision as CognitiveDecision; @@ -450,10 +853,12 @@ export class MaintainerActor { if (delivery.resolved) { console.log(`[MaintainerActor] 已修复并 resolve discussion ${discussion.id}`); } + await this.recordFixOutcome(mr.iid, finding, true, '修复已推送并回复'); return this.withDeliveryResult(true, delivery); } catch (err) { const reason = err instanceof Error ? err.message : String(err); console.error(`[MaintainerActor] 修复异常: ${reason}`); + await this.recordFixOutcome(mr.iid, finding, false, reason); return this.emptyActionResult(false, reason); } } @@ -479,7 +884,7 @@ export class MaintainerActor { await this.options.worktreeManager.checkoutBranch(mr.sourceBranch); console.log(`[MaintainerActor] 阶段=prepare 准备运行环境`); - await this.options.worktreeManager.prepareEnvironment(); + await this.prepareRepairEnvironment(); const resolvedPath = await this.options.worktreeManager.resolveFilePath(finding.file); if (!resolvedPath) { @@ -489,13 +894,25 @@ export class MaintainerActor { console.log(`[MaintainerActor] 阶段=delete 删除文件: ${resolvedPath}`); await this.options.worktreeManager.removeFile(resolvedPath); + const changes = await this.listChangedFiles([], [finding.file]); + const targetPaths = new Set([ + this.normalizeRepoPath(finding.file), + this.normalizeRepoPath(resolvedPath), + ]); + this.assertWriteScope(changes, targetPaths, `删除 finding ${finding.file}:${finding.line}`); + const approvedChangedPaths = new Set(changes.map(change => change.path)); const changeDescription = `Reviewer 指出文件 ${finding.file} 不应上传,已从 MR 中删除。`; console.log(`[MaintainerActor] 阶段=commit-push 提交删除到分支: ${mr.sourceBranch}`); await this.commitWithConventionRetry( mr.sourceBranch, changeDescription, - () => `移除不应上传的文件 ${basename(finding.file)}` + () => buildDefaultDeleteMessage(basename(finding.file)), + distilledFailure => this.reflowAfterHookFailure(mr, finding, distilledFailure), + async () => { + const currentChanges = await this.listChangedFiles([], [finding.file]); + this.assertWriteScope(currentChanges, approvedChangedPaths, '删除修复提交前校验'); + } ); const cognitive = decision as CognitiveDecision; @@ -576,6 +993,131 @@ export class MaintainerActor { return this.withDeliveryResult(true, result); } + /** + * 对 CI 失败执行最小修复。 + * + * 把失败 job 的日志尾部作为问题上下文交给 FixToolLoop,在 isolated worktree + * 中完成变更与本地验证,成功后提交推送至 MR source branch。 + * 修复动作与 CI discussion 的关联、回复由调用方(MaintainerRunner)负责。 + */ + async executeCiFix( + mr: MergeRequest, + report: CiFailureReport + ): Promise<{ codeApplied: boolean; reason: string; appliedFiles: string[] }> { + const failureDigest = report.failedJobs + .map( + job => + `### job: ${job.name} (stage: ${job.stage}${job.failureReason ? `, reason: ${job.failureReason}` : ''})\n${job.traceTail}` + ) + .join('\n\n'); + + // 从日志中猜测最可能出问题的仓库文件,供修复循环聚焦;失败则退化为通用描述 + let targetFile = '(见 CI 日志)'; + for (const job of report.failedJobs) { + for (const candidate of extractFileCandidatesFromTrace(job.traceTail)) { + try { + const resolved = await this.options.worktreeManager.resolveFilePath(candidate); + if (resolved) { + targetFile = this.normalizeRepoPath(resolved); + break; + } + } catch { + // 路径解析失败时继续尝试下一个候选 + } + } + if (targetFile !== '(见 CI 日志)') break; + } + + const syntheticFinding: ReviewFinding = { + severity: 'HIGH', + file: targetFile, + line: 1, + ruleId: 'ci-failure', + message: `CI pipeline 失败,失败 job: ${report.failedJobs.map(job => job.name).join(', ')}`, + suggestion: '根据 CI 日志定位失败根因,做最小化修复使 pipeline 恢复通过', + autoFixable: true, + }; + + const extraSystemPrompt = [ + '这是 CI pipeline 失败的自动修复任务。以下是失败 job 的日志尾部:', + '', + failureDigest, + '', + '要求:', + '1. 只做让 CI 恢复通过所必需的最小修改,不要顺手重构或修复无关问题。', + '2. 先在 worktree 中定位并复现失败原因(如运行对应脚本),修复后再次本地验证。', + '3. 如果日志显示失败与代码无关(如 runner 故障、网络问题),不要修改任何文件,直接结束。', + ].join('\n'); + + console.log( + `[MaintainerActor] 执行 CI 修复: pipeline=${report.pipelineId ?? 'unknown'}, failedJobs=[${report.failedJobs.map(job => job.name).join(',')}]` + ); + + try { + console.log(`[MaintainerActor] 阶段=worktree 准备/更新 worktree`); + await this.options.worktreeManager.ensureWorktree(); + console.log(`[MaintainerActor] 阶段=checkout 切换到 source branch: ${mr.sourceBranch}`); + await this.options.worktreeManager.checkoutBranch(mr.sourceBranch); + console.log(`[MaintainerActor] 阶段=prepare 准备运行环境`); + const baselineFailure = await this.prepareRepairEnvironment(); + const baselineFailurePrompt = this.buildBaselineFailurePrompt(baselineFailure); + + const loop = new FixToolLoop({ + llmClient: this.options.llmClient, + worktreeManager: this.options.worktreeManager, + finding: syntheticFinding, + mr, + memoryClient: this.options.memoryClient, + recallPlanner: this.options.recallPlanner, + extraSystemPrompt: [extraSystemPrompt, baselineFailurePrompt].filter(Boolean).join('\n\n'), + }); + + const fixResult = await loop.run(); + this.trackFinalActingRound(loop); + console.log( + `[MaintainerActor] CI 修复结果: success=${fixResult.success}, reason=${fixResult.reason}` + ); + + if (!fixResult.success) { + return { codeApplied: false, reason: fixResult.reason, appliedFiles: [] }; + } + + const changes = await this.listChangedFiles(loop.getAppliedFiles(), loop.getDeletedFiles()); + const appliedFiles = changes.map(change => change.path); + if (changes.length === 0) { + return { codeApplied: false, reason: 'CI 修复未产生任何文件变更', appliedFiles: [] }; + } + const approvedChangedPaths = new Set(appliedFiles); + + console.log(`[MaintainerActor] 阶段=commit-push 提交 CI 修复到分支: ${mr.sourceBranch}`); + await this.commitWithConventionRetry( + mr.sourceBranch, + `CI pipeline 失败修复。\n失败 job: ${report.failedJobs.map(job => `${job.stage}/${job.name}`).join(', ')}\n修改文件:\n${appliedFiles.map(f => `- ${f}`).join('\n')}`, + () => + [ + `fix(ci): 修复 CI 失败(${report.failedJobs.map(job => job.name).join(', ')})`, + '', + '修改文件:', + ...appliedFiles.map(f => `- ${f}`), + ].join('\n'), + distilledFailure => this.reflowAfterHookFailure(mr, syntheticFinding, distilledFailure), + async () => { + const currentChanges = await this.listChangedFiles( + loop.getAppliedFiles(), + loop.getDeletedFiles() + ); + this.assertWriteScope(currentChanges, approvedChangedPaths, 'CI 修复提交前校验'); + } + ); + + return { codeApplied: true, reason: 'CI 修复已推送至 source branch', appliedFiles }; + } catch (err) { + const reason = err instanceof Error ? err.message : String(err); + console.error(`[MaintainerActor] CI 修复异常: ${reason}`); + return { codeApplied: false, reason, appliedFiles: [] }; + } + } + private getMaintainerThreadState(state: MrAgentState, discussionId: string) { state.maintainerThreadState ??= {}; state.maintainerThreadState[discussionId] ??= { @@ -592,7 +1134,7 @@ export class MaintainerActor { body: string, resolve: boolean, state: MrAgentState, - awaitingReply?: { question: string; filePath: string } + awaitingReply?: { question: string; filePath: string; askedAt?: number } ): Promise { const threadState = this.getMaintainerThreadState(state, discussion.id); return deliverDiscussionReply({ @@ -669,41 +1211,149 @@ export class MaintainerActor { } /** - * 提交并推送;若被项目 hook 以提交信息规范为由拒绝, - * 让 LLM 根据尾部诊断理解该项目的实际规则,生成替代 message 并重试一次。 + * 提交并推送(提交管道)。 + * + * 失败时先由框架机械预处理:归类(commit-message/lint/test/typecheck/permission/push)+ + * 蒸馏(≤10 行诊断)。commit-message 类按项目规则重写 message 重试一次; + * lint/test/typecheck 类通过 reflow 回流修复循环、修复后重试一次; + * 其余情况只把蒸馏诊断抛给上层——发布到 MR 的永远不是 hook 原文。 */ private async commitWithConventionRetry( branch: string, changeDescription: string, - buildDefaultMessage: () => string + buildDefaultMessage: () => string, + reflow?: (distilledFailure: string) => Promise, + verifyChanges?: () => Promise ): Promise { const wm = this.options.worktreeManager; - const message = await this.buildCommitMessage(changeDescription, buildDefaultMessage); - try { - await wm.commitAndPush(branch, message, { setUpstream: false }); - return; - } catch (err) { - const errorText = err instanceof Error ? err.message : String(err); - const diagnostic = extractCommitRejectionSection(stripAnsiCodes(errorText)); - const diagnosticPreview = diagnostic.length > 1000 ? `…${diagnostic.slice(-1000)}` : diagnostic; - console.warn( - `[MaintainerActor] commit 被拒绝,尝试从 hook 尾部诊断恢复提交信息: ${diagnosticPreview}` - ); - const recovery = await this.recoverCommitMessage( - diagnostic, - message, - changeDescription, - branch - ); - if (!recovery) { - // 拒绝原因与提交信息格式无关(如 lint/测试失败),不重试 - throw err; + let message = await this.buildCommitMessage(changeDescription, buildDefaultMessage); + let recoveredConvention: string | undefined; + let commitMessageRecoveryAttempted = false; + let hookReflowAttempted = false; + + for (let attempt = 0; attempt < 3; attempt++) { + await verifyChanges?.(); + try { + await wm.commitAndPush(branch, message, { setUpstream: false }); + if (attempt === 0) this.incrMetric('commitFirstTryPasses'); + if (recoveredConvention) { + this.commitConvention = recoveredConvention; + this.commitConventionLoaded = true; + await this.rememberCommitConvention(recoveredConvention); + } + return; + } catch (err) { + if (attempt === 0) this.incrMetric('commitFirstTryRejections'); + const rawText = err instanceof Error ? err.message : String(err); + const kind = classifyCommitFailure(rawText); + const distilled = distillCommitFailure(rawText); + console.warn(`[MaintainerActor] commit 失败(分类=${kind}),蒸馏诊断:\n${distilled}`); + + if (kind === 'commit-message' && !commitMessageRecoveryAttempted) { + commitMessageRecoveryAttempted = true; + const diagnostic = extractCommitRejectionSection(stripAnsiCodes(rawText)); + const recovery = await this.recoverCommitMessage( + diagnostic, + message, + changeDescription, + branch + ); + if (recovery) { + message = recovery.message; + recoveredConvention = recovery.convention; + continue; + } + } + + // L3:lint/test/typecheck 类拒绝回流修复循环一次,有新变更则重试提交 + if ( + (kind === 'lint' || kind === 'test' || kind === 'typecheck') && + reflow && + !hookReflowAttempted + ) { + hookReflowAttempted = true; + console.log(`[MaintainerActor] ${kind} 类 hook 失败回流修复循环`); + const changed = await reflow(distilled); + if (changed) continue; + console.warn(`[MaintainerActor] 回流未产生新文件变更,不再重试提交`); + } + + throw new Error(distilled); } - await wm.commitAndPush(branch, recovery.message, { setUpstream: false }); - this.commitConvention = recovery.convention; - this.commitConventionLoaded = true; - await this.rememberCommitConvention(recovery.convention); } + + throw new Error('提交重试次数已耗尽'); + } + + /** + * M7:修复循环终局写入 EverOS(成功/失败都记录,失败原因含模式线索)。 + * 与 brain.decide 的决策级记录互补:这里记录的是修复循环的真实结果。 + */ + private async recordFixOutcome( + mrIid: number, + finding: ReviewFinding, + success: boolean, + reason: string + ): Promise { + const memory = this.options.memoryClient; + if (!memory) { + return; + } + try { + await memory.recordFixAttempt({ + mrIid, + file: finding.file, + line: finding.line, + success, + reason: `outcome:${success ? 'success' : 'failure'} | ${reason}`.slice(0, 1500), + }); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerActor] 修复终局记忆写入失败: ${message}`); + } + } + + /** + * L3:hook lint/test 类拒绝后的修复回流。 + * 用蒸馏诊断构造合成 finding,驱动一轮标准 FixToolLoop 消除校验错误; + * 返回是否产生了新的文件变更(有变更才值得重试提交)。 + */ + private async reflowAfterHookFailure( + mr: MergeRequest, + baseFinding: ReviewFinding, + distilledFailure: string, + extraSystemPrompt?: string + ): Promise { + this.incrMetric('hookFailureReflows'); + const reflowFinding: ReviewFinding = { + ...baseFinding, + line: 1, + message: `pre-commit hook 校验未通过:${distilledFailure}`, + suggestion: '根据蒸馏诊断修复 lint/test/typecheck 错误,使本地校验通过', + autoFixable: true, + }; + const loop = new FixToolLoop({ + llmClient: this.options.llmClient, + worktreeManager: this.options.worktreeManager, + finding: reflowFinding, + mr, + memoryClient: this.options.memoryClient, + recallPlanner: this.options.recallPlanner, + extraSystemPrompt: [ + '此前修复已完成,但提交被 pre-commit hook 拒绝。以下是框架蒸馏后的失败诊断,请据此消除校验错误后 finish:', + distilledFailure, + extraSystemPrompt ?? '', + ] + .filter(Boolean) + .join('\n\n'), + recheckAlreadyFixed: () => this.options.brain.recheckAlreadyFixed(reflowFinding), + }); + const result = await loop.run(); + this.trackFinalActingRound(loop); + console.log( + `[MaintainerActor] hook 失败回流结果: success=${result.success}, reason=${result.reason}` + ); + return loop.getAppliedFiles().length > 0 || loop.getDeletedFiles().length > 0; } /** 按已记忆的项目规范生成提交信息;无规范时使用朴素默认 */ @@ -752,27 +1402,44 @@ export class MaintainerActor { return buildDefaultMessage(); } - /** 从项目记忆召回提交信息规范(实例级缓存) */ + /** + * 提交规范三级兜底:EverOS 记忆 → 仓库静态探测(commitlint/husky)→ 调用方的合规默认。 + * 实例级缓存,避免每次提交都召回记忆/扫描磁盘。 + */ private async getCommitConvention(): Promise { if (this.commitConventionLoaded) { return this.commitConvention; } this.commitConventionLoaded = true; const memory = this.options.memoryClient; - if (!memory) { - return undefined; + if (memory) { + try { + const recalled = await memory.recallProjectKnowledge( + 'commit message 提交信息规范 convention git 提交格式' + ); + this.commitConvention = recalled.find( + item => typeof item === 'string' && /commit|提交/i.test(item) + ); + } catch (err) { + console.warn( + `[MaintainerActor] 召回提交规范记忆失败: ${err instanceof Error ? err.message : String(err)}` + ); + } } - try { - const recalled = await memory.recallProjectKnowledge( - 'commit message 提交信息规范 convention git 提交格式' - ); - this.commitConvention = recalled.find( - item => typeof item === 'string' && /commit|提交/i.test(item) - ); - } catch (err) { - console.warn( - `[MaintainerActor] 召回提交规范记忆失败: ${err instanceof Error ? err.message : String(err)}` - ); + if (!this.commitConvention) { + // 第二级:静态探测仓库 hook/lint 配置,命中即视为 Conventional Commits 项目 + try { + this.commitConvention = detectCommitConvention( + this.options.worktreeManager.getWorktreePath() + ); + if (this.commitConvention) { + console.log(`[MaintainerActor] 静态探测到项目提交规范: ${this.commitConvention}`); + } + } catch (err) { + console.warn( + `[MaintainerActor] 静态探测提交规范失败: ${err instanceof Error ? err.message : String(err)}` + ); + } } return this.commitConvention; } @@ -868,19 +1535,6 @@ export class MaintainerActor { } } -/** 去除 ANSI 转义码,避免 hook 输出中的颜色控制字符干扰规范提取 */ -export function stripAnsiCodes(text: string): string { - // eslint-disable-next-line no-control-regex - return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, ''); -} - -/** 保留 hook 输出尾部诊断,避免前置 lint/test 日志淹没最终拒绝原因 */ -export function extractCommitRejectionSection(text: string): string { - const normalized = text.replace(/\r\n?/g, '\n').trimEnd(); - const tailLines = normalized.split('\n').slice(-120).join('\n'); - return tailLines.slice(-8000); -} - /** 清理模型生成的提交信息,保留项目自定义格式但移除不可见空字符 */ function normalizeGeneratedCommitMessage(message: string | undefined): string | undefined { const normalized = message?.replace(/\0/g, '').replace(/\r\n?/g, '\n').trim(); @@ -897,27 +1551,19 @@ function sanitizeCommitSubject(message: string): string { } /** - * 朴素默认提交信息:不预设任何项目格式。 - * 若目标项目 hook 拒绝,会触发提交规范学习并重试。 + * 合规默认提交信息:Conventional Commits 形态(第三级兜底)。 + * 若项目实际规范不同,hook 拒绝后会触发规范学习并按项目规则重写。 */ function buildDefaultFixMessage(finding: ReviewFinding): string { - return [ - sanitizeCommitSubject(finding.message), - '', - `规则: ${finding.ruleId ?? 'N/A'}`, - `文件: ${finding.file}:${finding.line}`, - ].join('\n'); + return pipelineBuildDefaultFixMessage({ + message: sanitizeCommitSubject(finding.message), + ruleId: finding.ruleId, + file: finding.file, + line: finding.line, + }); } -/** 朴素默认批量提交信息 */ +/** 合规默认批量提交信息 */ function buildDefaultBatchMessage(appliedFiles: string[], deletedFiles: string[]): string { - const total = appliedFiles.length + deletedFiles.length; - const lines = [`批量修复 ${total} 个 Reviewer 问题`, '']; - if (appliedFiles.length > 0) { - lines.push('修改文件:', ...appliedFiles.map(f => `- ${f}`), ''); - } - if (deletedFiles.length > 0) { - lines.push('删除文件:', ...deletedFiles.map(f => `- ${f}`), ''); - } - return lines.join('\n'); + return pipelineBuildDefaultBatchMessage(appliedFiles, deletedFiles); } diff --git a/src/advance/classic/fix/tools/tool-definitions.ts b/src/advance/classic/fix/tools/tool-definitions.ts index b8ec5d1..a435459 100755 --- a/src/advance/classic/fix/tools/tool-definitions.ts +++ b/src/advance/classic/fix/tools/tool-definitions.ts @@ -34,11 +34,15 @@ export const WRITE_FILE_TOOL: ToolDefinition = { type: 'object', properties: { relPath: { type: 'string', description: '文件相对路径' }, - content: { type: 'string', description: '本段要写入的内容(overwrite 为完整内容,append 为追加片段)' }, + content: { + type: 'string', + description: '本段要写入的内容(overwrite 为完整内容,append 为追加片段)', + }, mode: { type: 'string', enum: ['overwrite', 'append'], - description: '写入模式:overwrite 覆盖整文件(默认);append 追加到文件末尾,用于分段写大文件', + description: + '写入模式:overwrite 覆盖整文件(默认);append 追加到文件末尾,用于分段写大文件', }, }, required: ['relPath', 'content'], @@ -61,8 +65,7 @@ export const DELETE_FILE_TOOL: ToolDefinition = { export const APPLY_PATCH_TOOL: ToolDefinition = { name: 'apply_patch', - description: - '将标准 unified diff 应用到 worktree。若 git apply 失败会尝试自研 patch 应用器。', + description: '将标准 unified diff 应用到 worktree。若 git apply 失败会尝试自研 patch 应用器。', input_schema: { type: 'object', properties: { @@ -87,7 +90,8 @@ export const RUN_SCRIPT_TOOL: ToolDefinition = { args: { type: 'array', items: { type: 'string' }, - description: '可选的额外参数,会附加在 npm script 之后,例如 ["packages/foo/src/bar.test.ts"]', + description: + '可选的额外参数,会附加在 npm script 之后,例如 ["packages/foo/src/bar.test.ts"]', }, }, required: ['script'], @@ -153,7 +157,8 @@ export const SEARCH_IN_FILE_TOOL: ToolDefinition = { export const SEARCH_WORKSPACE_TOOL: ToolDefinition = { name: 'search_workspace', - description: '在 Git 跟踪文件中搜索关键字,返回跨文件匹配位置。用于查找调用点、dispose、生命周期或共享类型引用。', + description: + '在 Git 跟踪文件中搜索关键字,返回跨文件匹配位置。用于查找调用点、dispose、生命周期或共享类型引用。', input_schema: { type: 'object', properties: { @@ -210,7 +215,7 @@ export const READ_OUTPUT_FILE_TOOL: ToolDefinition = { export const FINISH_TOOL: ToolDefinition = { name: 'finish', description: - '当你认为修复已完成、无法继续或需要 Reviewer 澄清时调用,结束工具循环。', + '当你认为修复已完成、问题在当前代码中已不存在、无法继续或需要 Reviewer 澄清时调用,结束工具循环。', input_schema: { type: 'object', properties: { @@ -222,6 +227,15 @@ export const FINISH_TOOL: ToolDefinition = { type: 'string', description: '说明当前状态,失败时解释原因', }, + alreadyFixed: { + type: 'boolean', + description: + '如果读取当前代码后确认 finding 已被其他提交修复、无需再改,设为 true;框架会再次独立回查,不会直接采信', + }, + evidence: { + type: 'string', + description: 'alreadyFixed=true 时给出仅来自当前目标 finding 的具体代码证据', + }, }, required: ['success', 'reason'], additionalProperties: false, diff --git a/src/advance/classic/provider/gitlab-provider.ts b/src/advance/classic/provider/gitlab-provider.ts index 6a32efa..1a2bfcd 100755 --- a/src/advance/classic/provider/gitlab-provider.ts +++ b/src/advance/classic/provider/gitlab-provider.ts @@ -15,6 +15,9 @@ import { type ReviewerCommentSnapshot, type MergeOptions, type GitLabDiffPosition, + type MrOverview, + type CiFailureReport, + type CiFailedJob, } from './types.js'; import { selectRecentActiveComments, @@ -413,4 +416,74 @@ export class GitLabProvider implements IGitProvider { `[GitLabProvider] mergeMR 尚未实现 (iid=${iid}, options=${JSON.stringify(options)})` ); } + + /** + * 获取指定 MR 的概览信息(生命周期终态感知) + */ + async getMROverview(iid: number): Promise { + const mr = await this.client.getMergeRequest(iid); + const refs = (mr as unknown as { diff_refs?: { head_sha?: string } }).diff_refs; + const labels = (mr as unknown as { labels?: string[] }).labels; + return { + state: mr.state ?? 'unknown', + headSha: refs?.head_sha, + labels: labels ?? [], + }; + } + + /** + * 获取指定 MR 的 CI 失败报告 + * + * 以 MR 最新 pipeline 为准;仅当状态为 failed 时收集失败 job 的日志尾部, + * 供 Maintainer 做最小化 CI 修复。单个 job 日志只保留尾部片段,避免超大 trace + * 占用内存;收集 job 数量上限同样受控。 + */ + async getCiFailureReport(iid: number): Promise { + const status = await this.getCIStatus(iid); + if (status !== 'failed') { + return { status, failedJobs: [] }; + } + + const pipelines = await this.client.getMergeRequestPipelines(iid, 1); + const pipeline = pipelines[0]; + if (!pipeline) { + return { status, failedJobs: [] }; + } + + const jobs = await this.client.listPipelineJobs(pipeline.id); + const failed = jobs.filter(job => job.status === 'failed').slice(0, MAX_CI_FAILURE_JOBS); + + const failedJobs: CiFailedJob[] = []; + for (const job of failed) { + let traceTail = ''; + try { + const trace = await this.client.getJobTrace(job.id); + traceTail = trace.slice(-CI_TRACE_TAIL_CHARS); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + traceTail = `(获取 job 日志失败: ${message})`; + } + failedJobs.push({ + id: job.id, + name: job.name, + stage: job.stage, + failureReason: job.failure_reason, + traceTail, + webUrl: job.web_url, + }); + } + + return { + status, + pipelineId: pipeline.id, + pipelineSha: pipeline.sha, + pipelineWebUrl: pipeline.web_url, + failedJobs, + }; + } } + +/** CI 失败诊断最多收集的 job 数 */ +const MAX_CI_FAILURE_JOBS = 3; +/** 单个失败 job 保留的日志尾部字符数 */ +const CI_TRACE_TAIL_CHARS = 4000; diff --git a/src/advance/classic/provider/types.ts b/src/advance/classic/provider/types.ts index b36b097..14d3dd9 100755 --- a/src/advance/classic/provider/types.ts +++ b/src/advance/classic/provider/types.ts @@ -177,6 +177,37 @@ export interface MrShaInfo { startSha: string; } +/** MR 生命周期终态感知所需的概览信息。 */ +export interface MrOverview { + /** GitLab MR 状态:opened / merged / closed / locked */ + state: string; + /** 当前 head SHA(可能缺失) */ + headSha?: string; + /** 标签列表 */ + labels: string[]; +} + +/** CI 失败 job 的诊断信息。 */ +export interface CiFailedJob { + id: number; + name: string; + stage: string; + /** GitLab 失败原因枚举(如 script_failure / runner_system_failure) */ + failureReason?: string; + /** 日志尾部片段,用于定位失败根因 */ + traceTail: string; + webUrl?: string; +} + +/** 指定 MR 的 CI 失败报告;status 非 failed 时 failedJobs 为空。 */ +export interface CiFailureReport { + status: 'pending' | 'running' | 'success' | 'failed' | 'skipped' | 'unknown'; + pipelineId?: number; + pipelineSha?: string; + pipelineWebUrl?: string; + failedJobs: CiFailedJob[]; +} + import type { MrReviewFilter } from '../../types.js'; /** @@ -236,6 +267,12 @@ export interface IGitProvider { /** 获取指定 MR 的 CI 状态 */ getCIStatus(iid: number): Promise<'pending' | 'running' | 'success' | 'failed' | 'skipped' | 'unknown'>; + /** 获取指定 MR 的概览(生命周期终态感知) */ + getMROverview(iid: number): Promise; + + /** 获取指定 MR 的 CI 失败报告(含失败 job 日志尾部) */ + getCiFailureReport(iid: number): Promise; + /** 合并指定 MR */ mergeMR(iid: number, options?: MergeOptions): Promise; } diff --git a/src/advance/classic/review/reviewer-actor.ts b/src/advance/classic/review/reviewer-actor.ts index 9c492a4..552b16b 100755 --- a/src/advance/classic/review/reviewer-actor.ts +++ b/src/advance/classic/review/reviewer-actor.ts @@ -158,8 +158,10 @@ export class ReviewerActor { return this.options.provider.postReviewComment(mr.iid, body); } - options.state.reviewCommentDelivery ??= {}; - const deliveryState = (options.state.reviewCommentDelivery[options.stateKey] ??= {}); + const state = options.state; + const stateKey = options.stateKey; + state.reviewCommentDelivery ??= {}; + const deliveryState = (state.reviewCommentDelivery[stateKey] ??= {}); const result = await deliverReviewComment({ provider: this.options.provider, mr, @@ -170,7 +172,7 @@ export class ReviewerActor { deliveryState[kind] = delivery; }, checkpoint: () => { - if (this.options.project) saveState(this.options.project, options.state!, 'reviewer'); + if (this.options.project) saveState(this.options.project, state, 'reviewer'); }, }); if (!result.posted || result.noteId === undefined) { diff --git a/src/advance/classic/runners/maintainer-runner.ts b/src/advance/classic/runners/maintainer-runner.ts index 513e922..c5baba4 100755 --- a/src/advance/classic/runners/maintainer-runner.ts +++ b/src/advance/classic/runners/maintainer-runner.ts @@ -10,16 +10,45 @@ import { LlmClient } from '../../llm/client.js'; import { GitLabProvider } from '../provider/gitlab-provider.js'; import { WorktreeManager } from '../worktree/worktree-manager.js'; import { MaintainerBrain } from '../fix/maintainer-brain.js'; -import { MaintainerActor, type MaintainerActionResult } from '../fix/maintainer-actor.js'; +import { + MaintainerActor, + type BatchFixResult, + type MaintainerActionResult, +} from '../fix/maintainer-actor.js'; import { CognitiveEngine } from '../cognitive-engine.js'; import { MemoryClient } from '../memory/memory-client.js'; import { RecallPlanner } from '../memory/recall-planner.js'; import type { Project, RoleConfig, MaintainerConfig } from '../../types.js'; -import type { MergeRequest, ReviewFinding, Discussion } from '../provider/types.js'; +import { getArchiveRoot } from '../../types.js'; +import type { + MergeRequest, + ReviewFinding, + Discussion, + ReviewerComment, +} from '../provider/types.js'; import type { MrContext } from '../fix/cognitive-types.js'; import { buildAuthenticatedRemoteUrl } from './shared/config-utils.js'; import { logger } from '../../../core/logger.js'; -import { loadState, saveState, type MrAgentState } from './shared/state-utils.js'; +import { + loadState, + saveState, + type MaintainerThreadState, + type MrAgentState, +} from './shared/state-utils.js'; +import { + archiveLifecycleRecord, + buildMrLifecycleKey, + classifyCiFailure, + collectInterruptCandidates, + computeClosureStats, + createLifecycleState, + detectInterruptCommand, + hashFailedJobs, + isMrConverged, + MAX_CI_FIX_ATTEMPTS_PER_HEAD, + type MrLifecycleInterrupt, + type MrLifecycleState, +} from './shared/mr-lifecycle.js'; import { formatAgentFooter, isAgentAuthoredNote, @@ -30,7 +59,15 @@ import { } from './shared/review-utils.js'; import { readDiscussionFileContent } from './shared/discussion-file-reader.js'; import { focusedContextToString } from '../fix/focused-context-streamer.js'; -import { isDiscussionPending, INTERACTIVE_REPLY_TIMEOUT_MS } from './shared/maintainer-filter.js'; +import { + hasVisibleMaintainerQuestion, + isDiscussionPending, + isNoFixBackfillCapped, + isJudgmentFlipped, + INTERACTIVE_REPLY_TIMEOUT_MS, +} from './shared/maintainer-filter.js'; +import { isSelfAnswerableQuestion, isRepoContentReply } from '../fix/ask-gate.js'; +import { sanitizeEverOSId } from '../memory/types.js'; import { isCiReviewBody, parseStructuredCiReview } from './shared/ci-review-parser.js'; import { getFindingKey, @@ -43,6 +80,13 @@ import { type DiscussionDeliveryResult, } from './shared/discussion-delivery.js'; import { getCommentActivityAt, getCommentUpdatedAt } from '../provider/activity-window.js'; +import { + compactDiscussionReplyBody, + compactDiscussionReason, + hashDiscussionReplyBody, + MAX_DISCUSSION_REPLY_CHARS, +} from './shared/reply-safety.js'; +import { defaultPromptLoader } from '../../llm/prompts/loader.js'; function logMemoryUsage(label: string): void { const usage = process.memoryUsage(); @@ -68,6 +112,180 @@ export function buildMaintainerMrSessionId(projectId: string, mrIid: number): st /** 单条 finding 最大自动修复重试次数 */ const MAX_FIX_RETRY_ATTEMPTS = 3; +const MAINTAINER_STATE_REPAIR_VERSION = 2; +export const STALE_DISCUSSION_DELIVERY_MS = 2 * 60 * 60 * 1000; + +function buildFixFailureQuestion(fileLine: string): string { + return defaultPromptLoader.load('maintainer-fix-failed-ask', { fileLine }); +} + +function isPrematureFixFailureQuestion(question: string): boolean { + return /尝试自动修复.+未成功.+补充期望的修改方式或范围|automatic fix.+failed.+clarif/i.test( + question + ); +} + +/** 对旧版本留下的 ask、批量同因失败和超长正文做一次性自愈迁移。 */ +export function repairLegacyMaintainerThreadState( + threadState: MaintainerThreadState, + now = Date.now() +): { + changed: boolean; + repairedSelfAnswerableAsk: boolean; + repairedPrematureFixAsk: boolean; +} { + let changed = false; + let repairedSelfAnswerableAsk = false; + let repairedPrematureFixAsk = false; + + for (const decision of Object.values(threadState.decisions)) { + if (decision.lastFailureReason) { + const compacted = compactDiscussionReason(decision.lastFailureReason); + if (compacted !== decision.lastFailureReason) { + decision.lastFailureReason = compacted; + changed = true; + } + } + if (decision.replyBody) { + const compacted = compactDiscussionReason(decision.replyBody); + if (compacted !== decision.replyBody) { + decision.replyBody = compacted; + changed = true; + } + } + } + + const delivery = threadState.delivery; + if (delivery) { + const compactedBody = compactDiscussionReplyBody(delivery.replyBody); + if (compactedBody !== delivery.replyBody) { + delivery.replyBody = compactedBody; + delivery.replyHash = hashDiscussionReplyBody(compactedBody); + changed = true; + } + delivery.createdAt ??= + threadState.lastSummaryAt ?? delivery.awaitingReplyAt ?? delivery.updatedAt; + } + + const previousRepairVersion = threadState.repairVersion ?? 0; + if (previousRepairVersion < 1) { + const duplicateFailureGroups = new Map(); + for (const [key, decision] of Object.entries(threadState.decisions)) { + if (decision.action !== 'fix' || !decision.lastFailureReason) continue; + const reason = compactDiscussionReason(decision.lastFailureReason); + const keys = duplicateFailureGroups.get(reason) ?? []; + keys.push(key); + duplicateFailureGroups.set(reason, keys); + } + + for (const keys of duplicateFailureGroups.values()) { + if (keys.length < 2) continue; + for (const key of keys) { + const decision = threadState.decisions[key]; + decision.failedAttempts = 0; + decision.fixSucceeded = undefined; + decision.lastFailureReason = undefined; + decision.decidedAt = now; + changed = true; + } + } + + for (const decision of Object.values(threadState.decisions)) { + const question = decision.question ?? decision.replyBody ?? decision.reason; + if (decision.action !== 'ask' || !isSelfAnswerableQuestion(question)) continue; + decision.action = 'fix'; + decision.question = undefined; + decision.failedAttempts = 0; + decision.fixSucceeded = undefined; + decision.lastFailureReason = undefined; + decision.decidedAt = now; + repairedSelfAnswerableAsk = true; + changed = true; + } + } + + if (previousRepairVersion < 2) { + const prematureDecisions = Object.values(threadState.decisions).filter(decision => { + const question = decision.question ?? threadState.delivery?.question ?? ''; + return ( + decision.action === 'fix' && + !decision.fixSucceeded && + decision.failedAttempts < MAX_FIX_RETRY_ATTEMPTS && + isPrematureFixFailureQuestion(question) + ); + }); + if (prematureDecisions.length > 0) { + for (const decision of prematureDecisions) { + decision.question = undefined; + decision.decidedAt = now; + } + if (threadState.delivery?.awaitingReply) { + threadState.delivery.awaitingReply = false; + threadState.delivery.awaitingReplyAt = undefined; + threadState.delivery.question = undefined; + threadState.delivery.filePath = undefined; + threadState.delivery.updatedAt = now; + } + repairedPrematureFixAsk = true; + changed = true; + } + } + + threadState.repairVersion = MAINTAINER_STATE_REPAIR_VERSION; + if (changed) { + threadState.lastSummaryHash = undefined; + threadState.noFixExplanationBackfilledAt = undefined; + } + return { changed, repairedSelfAnswerableAsk, repairedPrematureFixAsk }; +} + +/** 陈旧的未完成投递必须重新计算,不能跨多天照搬旧回复。 */ +export function getDiscussionDeliveryInvalidationReason(params: { + discussion: Discussion; + threadState: MaintainerThreadState; + currentHeadSha?: string; + now?: number; +}): string | undefined { + const delivery = params.threadState.delivery; + if (!delivery) return undefined; + const replyExists = params.discussion.notes.some( + note => + note.id === delivery.replyNoteId || + note.body === delivery.replyBody || + compactDiscussionReplyBody(note.body) === delivery.replyBody + ); + const postedReplyExists = delivery.replyStatus === 'posted' && replyExists; + if (postedReplyExists && !isDiscussionDeliveryPending(delivery)) return undefined; + + if (delivery.awaitingReply && isSelfAnswerableQuestion(delivery.question ?? '')) { + return '历史投递包含仓库内可自查的提问'; + } + if (delivery.replyBody.length > MAX_DISCUSSION_REPLY_CHARS) { + return '历史投递正文超过远端安全上限'; + } + + const createdAt = + delivery.createdAt ?? + params.threadState.lastSummaryAt ?? + delivery.awaitingReplyAt ?? + delivery.updatedAt; + const sourceUpdatedAt = params.discussion.notes[0] + ? getCommentUpdatedAt(params.discussion.notes[0]) + : 0; + if (sourceUpdatedAt > createdAt) return 'Reviewer 源评论在投递生成后发生更新'; + if ( + params.currentHeadSha && + params.threadState.lastProcessedHeadSha && + isReviewCommitStale(params.threadState.lastProcessedHeadSha, params.currentHeadSha) + ) { + return 'MR HEAD 已变化'; + } + if (postedReplyExists) return undefined; + if ((params.now ?? Date.now()) - createdAt > STALE_DISCUSSION_DELIVERY_MS) { + return '未完成投递已超过两小时,需要重新计算'; + } + return undefined; +} function normalizeMaintainerActionResult( result: MaintainerActionResult | boolean | undefined @@ -121,7 +339,8 @@ export function buildSummaryStateHash( failedItems: string[], askedItems: Array<{ fileLine: string }>, ignoredItems: Array<{ fileLine: string }>, - alreadyFixedItems: Array<{ fileLine: string }> + alreadyFixedItems: Array<{ fileLine: string }>, + deferredItems: string[] = [] ): string { const stateKeys = [ ...new Set([ @@ -130,6 +349,7 @@ export function buildSummaryStateHash( ...askedItems.map(item => `ask:${item.fileLine}`), ...ignoredItems.map(item => `ignored:${item.fileLine}`), ...alreadyFixedItems.map(item => `already-fixed:${item.fileLine}`), + ...deferredItems.map(item => `deferred:${item.split(' — ')[0]}`), ]), ].sort(); return simpleHash(JSON.stringify(stateKeys)); @@ -217,10 +437,32 @@ export async function runDiscussionTasks( */ export function classifyBatchFixItems( items: Array<{ file: string; line: number; deleteFile?: boolean }>, - batchResult: { success: boolean; reason: string; appliedFiles: string[]; deletedFiles: string[] } -): { fixedItems: string[]; failedItems: string[] } { + batchResult: { + success: boolean; + reason: string; + appliedFiles: string[]; + deletedFiles: string[]; + itemResults?: BatchFixResult['itemResults']; + } +): { fixedItems: string[]; failedItems: string[]; deferredItems: string[] } { const fixedItems: string[] = []; const failedItems: string[] = []; + const deferredItems: string[] = []; + + if (batchResult.itemResults) { + for (const item of batchResult.itemResults) { + const key = `${item.file}:${item.line}`; + if (item.status === 'fixed') fixedItems.push(key); + if (item.status === 'failed') { + failedItems.push(`${key} — ${item.reason || batchResult.reason || '修复失败'}`); + } + if (item.status === 'deferred') { + deferredItems.push(`${key} — ${item.reason || '本轮尚未执行'}`); + } + } + return { fixedItems, failedItems, deferredItems }; + } + for (const item of items) { const key = `${item.file}:${item.line}`; const fixed = item.deleteFile @@ -232,7 +474,7 @@ export function classifyBatchFixItems( failedItems.push(`${key} — ${batchResult.reason || '修复失败'}`); } } - return { fixedItems, failedItems }; + return { fixedItems, failedItems, deferredItems }; } /** @@ -243,6 +485,21 @@ export interface MaintainerRunnerOptions { llmClient: LlmClient; } +export interface CiHandlingResult { + /** 本轮是否实际调用了 CI 修复循环。 */ + fixAttempted: boolean; + /** 本轮是否已经推送 CI 修复。 */ + fixPushed: boolean; + /** 是否应等待下一轮 CI/HEAD 刷新后再处理普通 discussion。 */ + deferDiscussionProcessing: boolean; +} + +const CONTINUE_AFTER_CI: CiHandlingResult = { + fixAttempted: false, + fixPushed: false, + deferDiscussionProcessing: false, +}; + export class MaintainerRunner extends BaseRoleRunner { constructor(options: MaintainerRunnerOptions) { super({ llmClient: options.llmClient }); @@ -304,6 +561,7 @@ export class MaintainerRunner extends BaseRoleRunner { const state = loadState(project); state.interactiveThreads ??= {}; + state.mrLifecycle ??= {}; console.log(`[MaintainerRunner] 扫描项目 ${project.name} 的 open MRs...`); console.log( @@ -325,6 +583,10 @@ export class MaintainerRunner extends BaseRoleRunner { console.log(`[MaintainerRunner] 项目 ${project.name} 发现 ${mrs.length} 个 open MR`); logMemoryUsage('开始处理项目前'); + // 生命周期终态清扫:已跟踪但不再 open 的 MR,识别 merged/closed 并归档 + await this.finalizeTerminalLifecycles(provider, mrs, state, project); + saveState(project, state, 'maintainer'); + // 默认跳过 draft;如果 filter 里显式配置了 Draft=true,则保留 draft MR const draftCondition = maintainerConfig.filter?.conditions.find(c => c.field === 'draft'); const includeDraft = draftCondition?.values.includes('true') ?? false; @@ -337,6 +599,15 @@ export class MaintainerRunner extends BaseRoleRunner { console.log(`[MaintainerRunner] 维护 MR !${mr.iid}: ${mr.title}`); + // 单 MR 全生命周期状态:首次见到时建档,每轮更新轮询水位 + const lifecycle = this.ensureMrLifecycle(state, mr); + if (lifecycle.status === 'archived') { + console.log( + `[MaintainerRunner] MR !${mr.iid} 已归档(${lifecycle.endReason ?? 'unknown'}),跳过自治维护` + ); + continue; + } + let allDiscussions: Discussion[]; let discussions: Discussion[]; let activeDiscussionIds: Set; @@ -358,6 +629,16 @@ export class MaintainerRunner extends BaseRoleRunner { continue; } + // 用户中断指令检测:命中后优雅退出并归档,后续轮询不再自治处理本 MR + const interrupt = await this.detectMrInterrupt(provider, mr, allDiscussions, lifecycle); + if (interrupt) { + lifecycle.interrupted = interrupt; + await this.acknowledgeInterrupt(provider, mr, lifecycle, maintainerName); + this.finalizeLifecycle(project, lifecycle, 'interrupted', allDiscussions); + saveState(project, state, 'maintainer'); + continue; + } + const memoryClient = mcpUrl ? new MemoryClient({ mcpUrl, @@ -381,14 +662,53 @@ export class MaintainerRunner extends BaseRoleRunner { memoryClient, recallPlanner, checkpoint: () => saveState(project, state, 'maintainer'), + metrics: lifecycle.metrics, }); + let currentHeadSha: string | undefined; + try { + currentHeadSha = (await provider.getMRShaInfo(mr.iid)).headSha; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn( + `[MaintainerRunner] MR !${mr.iid} current HEAD unavailable; stale recheck skipped: ${message}` + ); + } + + for (const discussion of allDiscussions) { + const threadState = state.maintainerThreadState?.[discussion.id]; + if (!threadState) continue; + const repair = repairLegacyMaintainerThreadState(threadState); + if (repair.repairedSelfAnswerableAsk || repair.repairedPrematureFixAsk) { + delete state.interactiveThreads[discussion.id]; + const delivery = threadState.delivery; + if ( + delivery?.awaitingReply && + (isSelfAnswerableQuestion(delivery.question ?? '') || + isPrematureFixFailureQuestion(delivery.question ?? '')) + ) { + const replyExists = discussion.notes.some(note => note.id === delivery.replyNoteId); + delivery.awaitingReply = false; + delivery.awaitingReplyAt = undefined; + delivery.question = undefined; + delivery.filePath = undefined; + if (delivery.replyStatus !== 'posted' || !replyExists) { + threadState.delivery = undefined; + } + } + } + if (repair.changed) { + console.log(`[MaintainerRunner] discussion ${discussion.id} 已完成历史状态自愈`); + } + } + const reconciliationResults = await this.reconcileTrackedDiscussionDeliveries( actor, provider, mr, allDiscussions, - state + state, + currentHeadSha ); saveState(project, state, 'maintainer'); @@ -399,16 +719,6 @@ export class MaintainerRunner extends BaseRoleRunner { ); }); - let currentHeadSha: string | undefined; - try { - currentHeadSha = (await provider.getMRShaInfo(mr.iid)).headSha; - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - console.warn( - `[MaintainerRunner] MR !${mr.iid} current HEAD unavailable; stale recheck skipped: ${message}` - ); - } - const pendingDiscussions = discussions.filter(d => { const reconciliation = reconciliationResults.get(d.id); if (reconciliation?.pending) return false; @@ -439,69 +749,522 @@ export class MaintainerRunner extends BaseRoleRunner { `[MaintainerRunner] MR !${mr.iid} pending discussions: ${pendingDiscussions.length}` ); - if (pendingDiscussions.length === 0) { - console.log(`[MaintainerRunner] MR !${mr.iid} has no pending discussions`); + // 先处理 CI 阻塞,避免坏基线让每条普通 finding 都被同一个编译错误连坐。 + const ciHandling = await this.handleCiStatus( + provider, + actor, + mr, + lifecycle, + maintainerConfig, + maintainerName, + currentHeadSha + ); + if (ciHandling.deferDiscussionProcessing) { + console.log( + ciHandling.fixPushed + ? `[MaintainerRunner] MR !${mr.iid} 本轮已推送 CI 修复,等待新 pipeline 与新 HEAD 后再处理普通 discussion` + : `[MaintainerRunner] MR !${mr.iid} 本轮已优先尝试 CI 修复,避免在坏基线上处理旧 discussion,等待下一轮再评估` + ); + this.refreshLifecycleMetrics(lifecycle, allDiscussions, state, pendingDiscussions.length); + saveState(project, state, 'maintainer'); await memoryClient?.disconnect().catch(() => undefined); continue; } - console.log( - `[MaintainerRunner] MR !${mr.iid} processing ${pendingDiscussions.length} discussions` - ); - await runDiscussionTasks( - pendingDiscussions, - async discussion => { - console.log( - `[MaintainerRunner] 开始处理 discussion ${discussion.id}, position=${JSON.stringify(discussion.position)}` - ); - logMemoryUsage(`处理 discussion ${discussion.id} 前`); - await this.processDiscussion( - mr, - discussion, - provider, - brain, - actor, - worktreeManager, - maintainerName, - state, - project.rootPath, - memoryClient, - cognitiveDepth, - currentHeadSha - ); - try { - const latestHeadSha = await refreshDiscussionProcessedHeadSha( + if (pendingDiscussions.length === 0) { + console.log(`[MaintainerRunner] MR !${mr.iid} has no pending discussions`); + } else { + console.log( + `[MaintainerRunner] MR !${mr.iid} processing ${pendingDiscussions.length} discussions` + ); + await runDiscussionTasks( + pendingDiscussions, + async discussion => { + console.log( + `[MaintainerRunner] 开始处理 discussion ${discussion.id}, position=${JSON.stringify(discussion.position)}` + ); + logMemoryUsage(`处理 discussion ${discussion.id} 前`); + await this.processDiscussion( + mr, + discussion, provider, - mr.iid, - discussion.id, - state + brain, + actor, + worktreeManager, + maintainerName, + state, + project.rootPath, + memoryClient, + cognitiveDepth, + currentHeadSha ); - if (latestHeadSha) { - currentHeadSha = latestHeadSha; + try { + const latestHeadSha = await refreshDiscussionProcessedHeadSha( + provider, + mr.iid, + discussion.id, + state + ); + if (latestHeadSha) { + currentHeadSha = latestHeadSha; + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn( + `[MaintainerRunner] discussion ${discussion.id} 完成后刷新 MR HEAD 失败: ${message}` + ); } - } catch (error) { + saveState(project, state, 'maintainer'); + }, + (discussion, error) => { + // 记忆写入可能已经在异常前完成,因此不能据此推断回复也已成功发布。 const message = error instanceof Error ? error.message : String(error); - console.warn( - `[MaintainerRunner] discussion ${discussion.id} 完成后刷新 MR HEAD 失败: ${message}` + console.error( + `[MaintainerRunner] discussion ${discussion.id} 处理异常,继续处理后续 discussion: ${message}` ); + saveState(project, state, 'maintainer'); } - saveState(project, state, 'maintainer'); - }, - (discussion, error) => { - // 记忆写入可能已经在异常前完成,因此不能据此推断回复也已成功发布。 - const message = error instanceof Error ? error.message : String(error); - console.error( - `[MaintainerRunner] discussion ${discussion.id} 处理异常,继续处理后续 discussion: ${message}` - ); - saveState(project, state, 'maintainer'); - } - ); + ); + } + + // 生命周期指标与收敛判定(讨论闭环率、修/辩/挂起统计、误修信号) + this.refreshLifecycleMetrics(lifecycle, allDiscussions, state, pendingDiscussions.length); + saveState(project, state, 'maintainer'); await memoryClient?.disconnect().catch(() => undefined); } saveState(project, state, 'maintainer'); } + /** + * 获取/创建 MR 生命周期记录,并更新本轮轮询水位 + */ + private ensureMrLifecycle(state: MrAgentState, mr: MergeRequest): MrLifecycleState { + state.mrLifecycle ??= {}; + const key = buildMrLifecycleKey(mr.iid); + state.mrLifecycle[key] ??= createLifecycleState(mr); + const lifecycle = state.mrLifecycle[key]; + lifecycle.title = mr.title; + lifecycle.webUrl = mr.webUrl; + lifecycle.lastPolledAt = Date.now(); + lifecycle.pollCount += 1; + return lifecycle; + } + + /** 自增一个 M 系列过程指标(M4/M5 由 runner 侧写入) */ + private incrLifecycleMetric( + state: MrAgentState, + mr: MergeRequest, + key: 'duplicateSummarySkips' | 'askGateInterceptions' + ): void { + const metrics = this.ensureMrLifecycle(state, mr).metrics; + metrics[key] = (metrics[key] ?? 0) + 1; + } + + /** + * 生命周期终态清扫 + * + * 已跟踪但本轮不再出现在 open 列表中的 MR:核实其真实状态, + * merged/closed 则优雅退出并归档;仍 open(例如被 filter 排除)则保留等待。 + */ + private async finalizeTerminalLifecycles( + provider: GitLabProvider, + openMrs: MergeRequest[], + state: MrAgentState, + project: Project + ): Promise { + const openIids = new Set(openMrs.map(mr => mr.iid)); + for (const lifecycle of Object.values(state.mrLifecycle ?? {})) { + if (lifecycle.status === 'archived') continue; + if (openIids.has(lifecycle.mrIid)) continue; + + let remoteState: string; + try { + remoteState = (await provider.getMROverview(lifecycle.mrIid)).state; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] 核实 MR !${lifecycle.mrIid} 终态失败: ${message}`); + continue; + } + + if (remoteState !== 'merged' && remoteState !== 'closed') continue; + + // merged/closed 的 MR 通常仍可读取 discussion,尽力补齐终态闭环快照 + let discussions: Discussion[] = []; + try { + discussions = (await provider.getDiscussionSnapshot(lifecycle.mrIid)).all; + } catch { + // 读取失败时以空快照归档,不阻断退出 + } + console.log(`[MaintainerRunner] MR !${lifecycle.mrIid} 已 ${remoteState},执行归档退出`); + this.finalizeLifecycle(project, lifecycle, remoteState, discussions); + } + } + + /** + * 检测 MR 上的用户中断指令(MR 级评论 + discussion note 中的人工停止指令) + */ + private async detectMrInterrupt( + provider: GitLabProvider, + mr: MergeRequest, + allDiscussions: Discussion[], + lifecycle: MrLifecycleState + ): Promise { + let mrNotes: ReviewerComment[] = []; + try { + mrNotes = (await provider.getReviewerCommentSnapshot(mr.iid)).all; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] 获取 MR !${mr.iid} 评论失败,跳过中断指令检测: ${message}`); + return undefined; + } + const candidates = collectInterruptCandidates(mrNotes, allDiscussions); + const interrupt = detectInterruptCommand( + candidates, + (author, body) => !isAgentAuthoredNote(body) && !isBotAuthor(author) + ); + if (!interrupt) return undefined; + // 已触发过的旧指令不重复处理 + if (interrupt.at <= (lifecycle.interrupted?.at ?? 0)) return undefined; + return interrupt; + } + + /** + * 发布中断确认评论,告知用户 Maintainer 已停止自治维护 + */ + private async acknowledgeInterrupt( + provider: GitLabProvider, + mr: MergeRequest, + lifecycle: MrLifecycleState, + maintainerName: string + ): Promise { + const interrupt = lifecycle.interrupted; + if (!interrupt) return; + const body = [ + `🛑 已收到 @${interrupt.by} 的停止指令,${maintainerName} 已停止对本 MR 的自动修复与讨论处理,并归档当前维护记录。`, + '', + `> ${interrupt.command.replace(/\n/g, ' ')}`, + '', + '如需恢复自治维护,请在本 MR 中重新 @ 我说明。', + '', + formatAgentFooter(MAINTAINER_ROLE_LABEL, maintainerName), + ].join('\n'); + try { + await provider.postReviewComment(mr.iid, body); + console.log(`[MaintainerRunner] MR !${mr.iid} 收到用户中断指令,已发布停止确认`); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] MR !${mr.iid} 中断确认评论发布失败: ${message}`); + } + } + + /** + * CI 状态感知与自治修复 + * + * - failed:区分基础设施失败(挂起)与代码问题失败(最小修复并推送); + * - 同一 head 上修复次数受 MAX_CI_FIX_ATTEMPTS_PER_HEAD 约束,超限挂起; + * - 修复进展都写入 Maintainer 创建的 CI 跟踪 discussion,保持过程透明。 + */ + private async handleCiStatus( + provider: GitLabProvider, + actor: MaintainerActor, + mr: MergeRequest, + lifecycle: MrLifecycleState, + config: MaintainerConfig, + maintainerName: string, + currentHeadSha?: string + ): Promise { + let status: string; + try { + status = await provider.getCIStatus(mr.iid); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] 获取 MR !${mr.iid} CI 状态失败: ${message}`); + return CONTINUE_AFTER_CI; + } + + lifecycle.ci ??= { fixAttempts: 0, totalFixPushes: 0, updatedAt: Date.now() }; + const ci = lifecycle.ci; + const prevStatus = ci.lastStatus; + ci.lastStatus = status; + ci.updatedAt = Date.now(); + + if (status === 'success') { + if (prevStatus === 'failed' && ci.discussionId && ci.totalFixPushes > 0) { + await this.postCiNote( + provider, + mr, + ci, + `✅ CI 已恢复通过(累计推送 ${ci.totalFixPushes} 次自动修复)。`, + maintainerName + ); + } + ci.fixAttempts = 0; + ci.suspended = false; + ci.suspendReason = undefined; + return CONTINUE_AFTER_CI; + } + + if (status !== 'failed') return CONTINUE_AFTER_CI; + + // head 变化(自动推送或人工推送)意味着新一轮失败,重置修复计数 + if (currentHeadSha && ci.lastHeadSha !== currentHeadSha) { + ci.lastHeadSha = currentHeadSha; + ci.lastFailedJobsHash = undefined; + ci.fixAttempts = 0; + ci.suspended = false; + ci.suspendReason = undefined; + } + + let report; + try { + report = await provider.getCiFailureReport(mr.iid); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] 获取 MR !${mr.iid} CI 失败详情失败: ${message}`); + return CONTINUE_AFTER_CI; + } + if (report.failedJobs.length === 0) { + console.log(`[MaintainerRunner] MR !${mr.iid} CI 失败但未收集到失败 job,跳过`); + return CONTINUE_AFTER_CI; + } + + const jobsHash = hashFailedJobs(report.failedJobs); + const jobNames = report.failedJobs.map(job => `${job.stage}/${job.name}`).join(', '); + + // 基础设施/环境失败:修改代码无意义,直接挂起 + const infraOnly = report.failedJobs.every(job => classifyCiFailure(job) === 'infra'); + if (infraOnly) { + if (!ci.suspended || ci.lastFailedJobsHash !== jobsHash) { + await this.ensureCiDiscussion(provider, mr, ci, maintainerName, report.failedJobs); + await this.postCiNote( + provider, + mr, + ci, + `⏸️ CI 失败属于基础设施/环境问题(${jobNames}),非代码问题,已挂起自动修复,等待重跑或人工处理。`, + maintainerName + ); + } + ci.suspended = true; + ci.suspendReason = 'infra-failure'; + ci.lastFailedJobsHash = jobsHash; + return CONTINUE_AFTER_CI; + } + + if (config.ciFixEnabled === false) { + console.log(`[MaintainerRunner] MR !${mr.iid} CI 失败,但项目未启用 CI 自动修复,跳过`); + return CONTINUE_AFTER_CI; + } + + // 同一轮失败已挂起,等待人工 + if (ci.suspended && ci.lastFailedJobsHash === jobsHash) { + console.log(`[MaintainerRunner] MR !${mr.iid} CI 修复已挂起,等待人工介入`); + return CONTINUE_AFTER_CI; + } + + if (ci.fixAttempts >= MAX_CI_FIX_ATTEMPTS_PER_HEAD) { + await this.ensureCiDiscussion(provider, mr, ci, maintainerName, report.failedJobs); + if (!ci.suspended) { + await this.postCiNote( + provider, + mr, + ci, + `⏸️ 已尝试 ${ci.fixAttempts} 次自动修复仍未通过(${jobNames}),挂起等待人工介入。`, + maintainerName + ); + } + ci.suspended = true; + ci.suspendReason = 'attempts-exhausted'; + ci.lastFailedJobsHash = jobsHash; + return CONTINUE_AFTER_CI; + } + + // 修:在 isolated worktree 中执行最小修复并推送 + await this.ensureCiDiscussion(provider, mr, ci, maintainerName, report.failedJobs); + const result = await actor.executeCiFix(mr, report); + ci.fixAttempts += 1; + ci.lastFailedJobsHash = jobsHash; + if (result.codeApplied) { + ci.totalFixPushes += 1; + lifecycle.metrics.fixPushes += 1; + await this.postCiNote( + provider, + mr, + ci, + `🔧 已针对 CI 失败(${jobNames})推送第 ${ci.totalFixPushes} 次自动修复:\n${result.appliedFiles.map(f => `- ${f}`).join('\n')}\n\n等待 pipeline 复跑。`, + maintainerName + ); + } else { + await this.postCiNote( + provider, + mr, + ci, + `⚠️ CI 自动修复未成功(第 ${ci.fixAttempts}/${MAX_CI_FIX_ATTEMPTS_PER_HEAD} 次):${result.reason}`, + maintainerName + ); + } + return { + fixAttempted: true, + fixPushed: result.codeApplied, + deferDiscussionProcessing: true, + }; + } + + /** + * 确保 CI 修复跟踪 discussion 存在;不存在时创建并记录 ID + */ + private async ensureCiDiscussion( + provider: GitLabProvider, + mr: MergeRequest, + ci: NonNullable, + maintainerName: string, + failedJobs: Array<{ name: string; stage: string; webUrl?: string }> + ): Promise { + if (ci.discussionId) return; + const body = [ + `🤖 ${maintainerName} CI 修复跟踪(本线程由 Maintainer 创建,记录 pipeline 失败的自治修复进展)`, + '', + '当前失败 job:', + ...failedJobs.map( + job => `- ${job.stage}/${job.name}${job.webUrl ? `(${job.webUrl})` : ''}` + ), + '', + formatAgentFooter(MAINTAINER_ROLE_LABEL, maintainerName), + ].join('\n'); + try { + ci.discussionId = await provider.createDiscussion(mr.iid, body); + console.log( + `[MaintainerRunner] MR !${mr.iid} 已创建 CI 修复跟踪 discussion ${ci.discussionId}` + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] MR !${mr.iid} 创建 CI 跟踪 discussion 失败: ${message}`); + } + } + + /** + * 向 CI 修复跟踪 discussion 追加进展说明 + */ + private async postCiNote( + provider: GitLabProvider, + mr: MergeRequest, + ci: NonNullable, + text: string, + maintainerName: string + ): Promise { + if (!ci.discussionId) return; + try { + await provider.addDiscussionNote( + mr.iid, + ci.discussionId, + `${text}\n\n${formatAgentFooter(MAINTAINER_ROLE_LABEL, maintainerName)}` + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] MR !${mr.iid} CI 进展说明发布失败: ${message}`); + } + } + + /** + * 刷新生命周期指标并做收敛判定 + * + * 指标取当前快照而非增量:修/辩/挂起计数直接反映跨轮次记忆 + * (maintainerThreadState.decisions)中的最新结论,天然幂等。 + */ + private refreshLifecycleMetrics( + lifecycle: MrLifecycleState, + allDiscussions: Discussion[], + state: MrAgentState, + pendingDiscussionCount: number + ): void { + // Maintainer 自己创建的 CI 跟踪线程不计入 reviewer 意见闭环 + const scoped = allDiscussions.filter(d => d.id !== lifecycle.ci?.discussionId); + const closure = computeClosureStats(scoped); + const metrics = lifecycle.metrics; + metrics.discussionsTotal = closure.total; + metrics.discussionsResolved = closure.resolved; + + let fixed = 0; + let rejected = 0; + let suspended = 0; + let humanFollowups = 0; + for (const discussion of scoped) { + const threadState = state.maintainerThreadState?.[discussion.id]; + if (threadState) { + for (const decision of Object.values(threadState.decisions)) { + if (decision.action === 'fix' && decision.fixSucceeded) fixed += 1; + else if (decision.action === 'ignore' && !decision.alreadyFixed) rejected += 1; + else if (decision.action === 'ask') suspended += 1; + } + } + // 误修信号:Maintainer 宣称修复后仍有「人工」追评 + const lastFixClaimAt = discussion.notes + .filter(note => isMaintainerAuthoredNote(note.body) && /✅[\s\S]*修复/.test(note.body)) + .reduce((max, note) => Math.max(max, getCommentActivityAt(note)), 0); + if (lastFixClaimAt > 0 && getLastHumanNoteAt(discussion) > lastFixClaimAt) { + humanFollowups += 1; + } + } + metrics.findingsFixed = fixed; + metrics.findingsRejected = rejected; + metrics.findingsSuspended = suspended; + metrics.humanFollowupsAfterFix = humanFollowups; + + const converged = isMrConverged({ + pendingDiscussionCount, + closure, + ciStatus: lifecycle.ci?.lastStatus, + ciSuspended: lifecycle.ci?.suspended, + }); + if (converged && lifecycle.status === 'active') { + lifecycle.status = 'converged'; + console.log( + `[MaintainerRunner] MR !${lifecycle.mrIid} 意见已收敛(闭环 ${closure.resolved}/${closure.total}),进入待合并状态` + ); + } else if (!converged && lifecycle.status === 'converged') { + lifecycle.status = 'active'; + console.log(`[MaintainerRunner] MR !${lifecycle.mrIid} 出现新待处理事项,恢复自治维护`); + } + } + + /** + * 生命周期归档:写入归档文件并记录终态指标,支撑收敛效率验收 + */ + private finalizeLifecycle( + project: Project, + lifecycle: MrLifecycleState, + endReason: 'merged' | 'closed' | 'interrupted', + discussions: Discussion[] + ): void { + lifecycle.status = 'archived'; + lifecycle.endReason = endReason; + lifecycle.archivedAt = Date.now(); + + const scoped = discussions.filter(d => d.id !== lifecycle.ci?.discussionId); + const closure = computeClosureStats(scoped); + + try { + lifecycle.archivePath = archiveLifecycleRecord( + getArchiveRoot(project), + project.id, + lifecycle, + closure + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] MR !${lifecycle.mrIid} 生命周期归档失败: ${message}`); + } + + const metrics = lifecycle.metrics; + console.log( + `[MaintainerRunner] MR !${lifecycle.mrIid} 生命周期归档(${endReason}):` + + `轮询 ${lifecycle.pollCount} 次,闭环 ${metrics.discussionsResolved}/${metrics.discussionsTotal},` + + `修 ${metrics.findingsFixed} / 辩 ${metrics.findingsRejected} / 挂起 ${metrics.findingsSuspended},` + + `推送 ${metrics.fixPushes} 次,误修信号 ${metrics.humanFollowupsAfterFix} 次` + + (lifecycle.archivePath ? `,归档:${lifecycle.archivePath}` : '') + ); + } + /** * 处理单个 discussion(来自 Reviewer 或人工)。 * @@ -594,18 +1357,21 @@ export class MaintainerRunner extends BaseRoleRunner { this.restoreInteractiveThread(state, discussion.id); } - // 如果本 discussion 正在交互式等待 Reviewer 回复,先处理新回复 + // 如果本 discussion 正在交互式等待 Reviewer 回复,先处理新回复。 + // 等待态不能阻塞同一 discussion 内其他仍可自动重试的 finding。 + let suppressRepeatedAsk = false; const existingThread = state.interactiveThreads?.[discussion.id]; if (existingThread?.status === 'awaiting-reply') { const askedAt = existingThread.askedAt; // 只要 discussion 里在提问时间之后还有 Maintainer 发布的 note,就说明状态有效 - const maintainerNotesAfterAsk = discussion.notes.filter(note => { - if (!isMaintainerAuthoredNote(note.body)) return false; - return getCommentActivityAt(note) >= askedAt - 1000; - }); + const askNoteStillExists = hasVisibleMaintainerQuestion( + discussion, + askedAt, + existingThread.question + ); // 如果 discussion 里已经找不到提问后的 Maintainer note,说明状态已脏,清除后继续处理 - if (maintainerNotesAfterAsk.length === 0) { + if (!askNoteStillExists) { console.warn( `[MaintainerRunner] discussion ${discussion.id} 的交互状态已过期,清除后重新处理` ); @@ -617,6 +1383,16 @@ export class MaintainerRunner extends BaseRoleRunner { }); if (newReviewerNotes.length === 0) { + const activeFindingKeys = new Set( + threadState.activeFindingKeys ?? Object.keys(threadState.decisions) + ); + const hasRetryableFix = Object.entries(threadState.decisions).some( + ([key, decision]) => + activeFindingKeys.has(key) && + decision.action === 'fix' && + !decision.fixSucceeded && + decision.failedAttempts < MAX_FIX_RETRY_ATTEMPTS + ); if (Date.now() - askedAt > INTERACTIVE_REPLY_TIMEOUT_MS) { // 超时未收到回复:清理交互状态,避免无限等待; // 讨论中有人工参与者时留一条收尾说明,纯 Agent 讨论静默清理 @@ -654,47 +1430,65 @@ export class MaintainerRunner extends BaseRoleRunner { console.log( `[MaintainerRunner] discussion ${discussion.id} 交互式提问超时未回复,已清理等待状态` ); + if (hasRetryableFix) { + suppressRepeatedAsk = true; + console.log( + `[MaintainerRunner] discussion ${discussion.id} 仍有可重试 finding,继续本轮处理` + ); + } else { + recordProcessed(); + return; + } + } else if (hasRetryableFix) { + suppressRepeatedAsk = true; + console.log( + `[MaintainerRunner] discussion ${discussion.id} 等待 Reviewer 回复,同时继续处理其他可重试 finding` + ); } else { console.log(`[MaintainerRunner] discussion ${discussion.id} 等待 Reviewer 回复中`); + recordProcessed(); + return; } - recordProcessed(); - return; } - const interactiveFilePath = existingThread.filePath; - const interactiveQuestion = existingThread.question; - this.clearAwaitingReplyState(state, discussion.id); - try { - await this.handleInteractiveReply( - mr, - discussion, - brain, - actor, - worktreeManager, - maintainerName, - state, - projectRootPath, - interactiveFilePath - ); - } catch (error) { - state.interactiveThreads[discussion.id] = { - status: 'awaiting-reply', - askedAt, - question: interactiveQuestion, - filePath: interactiveFilePath, - }; - const currentDelivery = state.maintainerThreadState?.[discussion.id]?.delivery; - if (currentDelivery) { - currentDelivery.awaitingReply = true; - currentDelivery.awaitingReplyAt = askedAt; - currentDelivery.question = interactiveQuestion; - currentDelivery.filePath = interactiveFilePath; - currentDelivery.updatedAt = Date.now(); + if (newReviewerNotes.length > 0) { + const interactiveFilePath = existingThread.filePath; + const interactiveQuestion = existingThread.question; + this.clearAwaitingReplyState(state, discussion.id); + try { + await this.handleInteractiveReply( + mr, + discussion, + brain, + actor, + worktreeManager, + maintainerName, + state, + projectRootPath, + interactiveFilePath, + interactiveQuestion, + memoryClient + ); + } catch (error) { + state.interactiveThreads[discussion.id] = { + status: 'awaiting-reply', + askedAt, + question: interactiveQuestion, + filePath: interactiveFilePath, + }; + const currentDelivery = state.maintainerThreadState?.[discussion.id]?.delivery; + if (currentDelivery) { + currentDelivery.awaitingReply = true; + currentDelivery.awaitingReplyAt = askedAt; + currentDelivery.question = interactiveQuestion; + currentDelivery.filePath = interactiveFilePath; + currentDelivery.updatedAt = Date.now(); + } + throw error; } - throw error; + recordProcessed(); + return; } - recordProcessed(); - return; } } @@ -1076,7 +1870,8 @@ export class MaintainerRunner extends BaseRoleRunner { existing.failedAttempts < MAX_FIX_RETRY_ATTEMPTS; const noFixExplanationMissing = existing?.action === 'ignore' && - !this.hasNoFixExplanationForItems(discussion, [`${finding.file}:${finding.line}`]); + !this.hasNoFixExplanationForItems(discussion, [`${finding.file}:${finding.line}`]) && + !isNoFixBackfillCapped(threadState, lastHumanNoteAt); if ( existing && !staleFinding && @@ -1112,6 +1907,7 @@ export class MaintainerRunner extends BaseRoleRunner { state ); console.log(`[MaintainerRunner] finding ${key} 的远端无需修复说明缺失,已补发并 resolve`); + threadState.noFixExplanationBackfilledAt = Date.now(); threadState.lastHumanNoteAt = lastHumanNoteAt; recordProcessed(); return; @@ -1146,11 +1942,30 @@ export class MaintainerRunner extends BaseRoleRunner { `[MaintainerRunner] finding ${finding.file}:${finding.line} 决策: action=${decision.action}, reason=${decision.reason}` ); + // M7:Reviewer 推翻了此前的「无需修复/已修复」判断,写入反思供 already-fixed 回查参考 + if (isJudgmentFlipped(existing, hasNewHumanNote, decision.action) && memoryClient) { + try { + await memoryClient.recordReflection({ + caseKey: sanitizeEverOSId(`case-mr-${mr.iid}-${finding.file}-${finding.line}`), + reflection: + `此前判断为无需修复/已修复(${existing.reason}),` + + `Reviewer 新回复后重新判断为需要修复(${decision.reason})。` + + `后续 already-fixed 回查应参考本次推翻,避免重复误判。`, + outcome: 'failure', + }); + console.log(`[MaintainerRunner] finding ${key} 判断被推翻,已写入反思记忆`); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] 判断推翻反思写入失败,继续处理: ${message}`); + } + } + // 人工新回复触发的重评估:若结论与历史一致,不重复回复,仅刷新状态 if ( existing && !staleFinding && !needsRetry && + decision.action !== 'fix' && decision.action === existing.action && (decision.alreadyFixed ?? false) === (existing.alreadyFixed ?? false) ) { @@ -1163,9 +1978,16 @@ export class MaintainerRunner extends BaseRoleRunner { return; } - const actionResult = normalizeMaintainerActionResult( - await actor.applyDecision(mr, discussion, finding, decision, state) - ); + const runnerOwnsFixRetry = + decision.action === 'fix' || + (decision.action === 'ask' && + Boolean(decision.question && isSelfAnswerableQuestion(decision.question))); + const rawActionResult = runnerOwnsFixRetry + ? await actor.applyDecision(mr, discussion, finding, decision, state, { + askOnFixFailure: false, + }) + : await actor.applyDecision(mr, discussion, finding, decision, state); + const actionResult = normalizeMaintainerActionResult(rawActionResult); const codeApplied = actionResult.codeApplied; // 记录本次决策,用于下次轮询去重 @@ -1176,6 +1998,7 @@ export class MaintainerRunner extends BaseRoleRunner { replyBody: decision.replyBody, question: decision.question, deleteFile: decision.deleteFile, + scope: decision.scope, failedAttempts: decision.action === 'fix' && !codeApplied ? (staleFinding ? 0 : (existing?.failedAttempts ?? 0)) + 1 @@ -1191,6 +2014,37 @@ export class MaintainerRunner extends BaseRoleRunner { }; threadState.lastHumanNoteAt = lastHumanNoteAt; + if (decision.action === 'fix' && !codeApplied) { + const storedDecision = threadState.decisions[key]; + const failureReason = storedDecision.lastFailureReason ?? '修复未成功'; + const exhausted = storedDecision.failedAttempts >= MAX_FIX_RETRY_ATTEMPTS; + const question = exhausted ? buildFixFailureQuestion(key) : undefined; + storedDecision.question = question; + const postSummary = ( + actor as MaintainerActor & { + postSummary?: MaintainerActor['postSummary']; + } + ).postSummary; + if (typeof postSummary === 'function') { + await postSummary.call( + actor, + mr, + discussion, + [], + [`${key} — ${failureReason}`], + question ? [{ fileLine: key, text: question }] : [], + [], + [], + state + ); + } + console.log( + exhausted + ? `[MaintainerRunner] finding ${key} 已连续失败 ${storedDecision.failedAttempts} 次,转入 Reviewer 澄清` + : `[MaintainerRunner] finding ${key} 第 ${storedDecision.failedAttempts}/${MAX_FIX_RETRY_ATTEMPTS} 次修复未成功,保留自动重试` + ); + } + if ( cognitiveDepth === 'deep' && codeApplied && @@ -1230,6 +2084,7 @@ export class MaintainerRunner extends BaseRoleRunner { const askedItems: Array<{ fileLine: string; text: string }> = []; const ignoredItems: Array<{ fileLine: string; reason: string }> = []; const alreadyFixedItems: Array<{ fileLine: string; reason: string }> = []; + const deferredItems: string[] = []; const fixableItems: Array<{ finding: ReviewFinding; @@ -1286,14 +2141,19 @@ export class MaintainerRunner extends BaseRoleRunner { if (shouldReuse) { console.log(`[MaintainerRunner] finding ${key} 复用历史决策: action=${existing.action}`); - this.applyStoredDecision(existing, finding, { - fixedItems, - failedItems, - askedItems, - ignoredItems, - alreadyFixedItems, - fixableItems, - }); + this.applyStoredDecision( + existing, + finding, + { + fixedItems, + failedItems, + askedItems, + ignoredItems, + alreadyFixedItems, + fixableItems, + }, + suppressRepeatedAsk + ); continue; } @@ -1332,6 +2192,7 @@ export class MaintainerRunner extends BaseRoleRunner { replyBody: decision.replyBody, question: decision.question, deleteFile: decision.deleteFile, + scope: decision.scope, failedAttempts: staleFinding || existing?.action !== 'fix' ? 0 : (existing.failedAttempts ?? 0), fixSucceeded: staleFinding ? undefined : existing?.fixSucceeded, @@ -1354,9 +2215,39 @@ export class MaintainerRunner extends BaseRoleRunner { } if (decision.action === 'ask') { + const question = decision.question ?? decision.reason; + // L2 ask 门禁:仓库内可自查的索问不进入提问汇总,转为修复自查项 + if (decision.question && isSelfAnswerableQuestion(decision.question)) { + this.incrLifecycleMetric(state, mr, 'askGateInterceptions'); + console.log( + `[MaintainerRunner] ask 门禁拦截 ${key} 的仓库内可自查索问,转为修复自查: ${decision.question}` + ); + threadState.decisions[key].action = 'fix'; + fixableItems.push({ + finding: { + ...finding, + suggestion: [ + finding.suggestion ?? '', + `(框架门禁:原提问被判定为仓库内可自行查阅,禁止向 Reviewer 索要文件内容/代码片段;请自行读取相关代码后完成修复:${decision.question})`, + ] + .filter(Boolean) + .join('\n'), + }, + fileContent: focusedContextToString(focusedContent), + scope: decision.scope, + deleteFile: decision.deleteFile, + }); + continue; + } + if (suppressRepeatedAsk) { + console.log( + `[MaintainerRunner] discussion ${discussion.id} 已有待澄清问题,暂不重复发布 ${key} 的提问` + ); + continue; + } askedItems.push({ fileLine: `${finding.file}:${finding.line}`, - text: decision.question ?? decision.reason, + text: question, }); continue; } @@ -1379,6 +2270,7 @@ export class MaintainerRunner extends BaseRoleRunner { fixableItems.map(item => ({ finding: item.finding, fileContent: item.fileContent, + scope: item.scope, deleteFile: item.deleteFile, })), firstNote.body @@ -1389,21 +2281,45 @@ export class MaintainerRunner extends BaseRoleRunner { // 按 batch 结果更新每条 finding 的决策状态 const batchAlreadyFixed = batchResult.alreadyFixedItems ?? []; + const itemResultsByKey = new Map( + (batchResult.itemResults ?? []).map(result => [`${result.file}:${result.line}`, result]) + ); for (const item of fixableItems) { const key = getFindingKey(item.finding); const decision = threadState.decisions[key]; if (!decision || decision.action !== 'fix') continue; + const itemResult = itemResultsByKey.get(key); const alreadyFixed = batchAlreadyFixed.find( entry => entry.file === item.finding.file && entry.line === item.finding.line ); - if (alreadyFixed) { + if (itemResult?.status === 'already-fixed' || alreadyFixed) { + const reason = itemResult?.reason || alreadyFixed?.reason || '当前代码中已不存在该问题'; decision.action = 'ignore'; decision.alreadyFixed = true; - decision.reason = alreadyFixed.reason; - decision.replyBody = alreadyFixed.reason; + decision.reason = reason; + decision.replyBody = reason; decision.fixSucceeded = undefined; decision.lastFailureReason = undefined; - alreadyFixedItems.push({ fileLine: key, reason: alreadyFixed.reason }); + alreadyFixedItems.push({ fileLine: key, reason }); + decision.decidedAt = Date.now(); + continue; + } + if (itemResult?.status === 'fixed') { + decision.fixSucceeded = true; + decision.lastFailureReason = undefined; + decision.decidedAt = Date.now(); + continue; + } + if (itemResult?.status === 'failed') { + decision.failedAttempts = (decision.failedAttempts ?? 0) + 1; + decision.fixSucceeded = false; + decision.lastFailureReason = itemResult.reason || batchResult.reason || '修复失败'; + decision.decidedAt = Date.now(); + continue; + } + if (itemResult?.status === 'deferred') { + decision.fixSucceeded = false; + decision.decidedAt = Date.now(); continue; } const isFixed = item.deleteFile @@ -1420,6 +2336,26 @@ export class MaintainerRunner extends BaseRoleRunner { } } + if (!suppressRepeatedAsk) { + for (const item of fixableItems) { + const key = getFindingKey(item.finding); + const decision = threadState.decisions[key]; + if ( + !decision || + decision.action !== 'fix' || + decision.fixSucceeded || + decision.failedAttempts < MAX_FIX_RETRY_ATTEMPTS + ) { + continue; + } + const question = decision.question ?? buildFixFailureQuestion(key); + decision.question = question; + if (!askedItems.some(asked => asked.fileLine === key)) { + askedItems.push({ fileLine: key, text: question }); + } + } + } + if (cognitiveDepth === 'deep' && batchResult.success && memoryClient) { const engine = new CognitiveEngine({ llmClient: this.llmClient, memoryClient }); for (const item of fixableItems) { @@ -1464,6 +2400,7 @@ export class MaintainerRunner extends BaseRoleRunner { ); fixedItems.push(...classified.fixedItems); failedItems.push(...classified.failedItems); + deferredItems.push(...classified.deferredItems); } const summaryHash = buildSummaryStateHash( @@ -1471,14 +2408,16 @@ export class MaintainerRunner extends BaseRoleRunner { failedItems, askedItems, ignoredItems, - alreadyFixedItems + alreadyFixedItems, + deferredItems ); const hasResults = fixedItems.length > 0 || failedItems.length > 0 || askedItems.length > 0 || ignoredItems.length > 0 || - alreadyFixedItems.length > 0; + alreadyFixedItems.length > 0 || + deferredItems.length > 0; const summaryChanged = summaryHash !== threadState.lastSummaryHash; const noFixItems = [...ignoredItems, ...alreadyFixedItems]; const noFixExplanationComplete = this.hasNoFixExplanationForItems( @@ -1495,17 +2434,27 @@ export class MaintainerRunner extends BaseRoleRunner { askedItems, ignoredItems, alreadyFixedItems, - state + state, + deferredItems ); if (!summaryResult || summaryResult.replyPosted) { threadState.lastSummaryHash = summaryHash; threadState.lastSummaryAt = Date.now(); + // 含无需修复/已修复说明的 summary 发布成功即视为补发完成, + // 后续不再仅因远端说明识别失败(如行号漂移)而重复补发。 + if (noFixItems.length > 0) { + threadState.noFixExplanationBackfilledAt = Date.now(); + } } else { console.warn( `[MaintainerRunner] discussion ${discussion.id} summary 投递未完成,保留 hash 以便下轮重试: ${summaryResult.error ?? '未知错误'}` ); } } else { + // M4:有汇总结果但内容无变化 → 去重生效,命中「已发过、跳过」 + if (hasResults) { + this.incrLifecycleMetric(state, mr, 'duplicateSummarySkips'); + } console.log( `[MaintainerRunner] discussion ${discussion.id} summary 无变化或无需发布,跳过(hasResults=${hasResults}, changed=${summaryChanged})` ); @@ -1525,7 +2474,9 @@ export class MaintainerRunner extends BaseRoleRunner { maintainerName: string, state: MrAgentState, projectRootPath: string, - filePath: string | undefined + filePath: string | undefined, + interactiveQuestion?: string, + memoryClient?: MemoryClient ): Promise { if (!filePath) { console.warn( @@ -1568,6 +2519,37 @@ export class MaintainerRunner extends BaseRoleRunner { }); console.log(`[MaintainerRunner] LLM 决策: action=${decision.action}`); + // G7:交互提问获人工回复后直接转修复,若回复内容本是仓库内可查信息, + // 说明这次提问疑似漏过了 ask 门禁——作为模式库漏判候选回流 EverOS。 + if ( + decision.action === 'fix' && + interactiveQuestion && + !isSelfAnswerableQuestion(interactiveQuestion) && + memoryClient + ) { + const lastHumanReply = discussion.notes + .filter(note => !isAgentAuthoredNote(note.body) && !isBotAuthor(note.author)) + .sort((a, b) => getCommentActivityAt(b) - getCommentActivityAt(a))[0]; + if (lastHumanReply && isRepoContentReply(lastHumanReply.body)) { + try { + await memoryClient.recordReflection({ + caseKey: sanitizeEverOSId(`ask-gate-miss-mr-${mr.iid}-${discussion.id}`), + reflection: + `此前向 Reviewer 提问「${interactiveQuestion.slice(0, 200)}」,` + + `Reviewer 回复中包含仓库内可查信息(代码/文件路径),随后直接修复(${decision.reason})。` + + `该提问疑似可被 ask 门禁拦截,SELF_ANSWERABLE_PATTERNS 模式库可参考补充。`, + outcome: 'failure', + }); + console.log( + `[MaintainerRunner] discussion ${discussion.id} 疑似 ask 门禁漏判,已写入反思记忆` + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + console.warn(`[MaintainerRunner] ask 门禁漏判反思写入失败: ${message}`); + } + } + } + const syntheticFindingForApply: ReviewFinding = { severity: 'MEDIUM', file: filePath, @@ -1720,14 +2702,34 @@ export class MaintainerRunner extends BaseRoleRunner { provider: GitLabProvider, mr: MergeRequest, discussions: Discussion[], - state: MrAgentState + state: MrAgentState, + currentHeadSha?: string ): Promise> { const results = new Map(); for (const discussion of discussions) { - const delivery = state.maintainerThreadState?.[discussion.id]?.delivery; + const threadState = state.maintainerThreadState?.[discussion.id]; + const delivery = threadState?.delivery; if (!delivery) continue; + const invalidationReason = getDiscussionDeliveryInvalidationReason({ + discussion, + threadState, + currentHeadSha, + }); + if (invalidationReason) { + console.warn( + `[MaintainerRunner] discussion ${discussion.id} 丢弃陈旧投递并重新计算: ${invalidationReason}` + ); + threadState.delivery = undefined; + threadState.lastSummaryHash = undefined; + threadState.noFixExplanationBackfilledAt = undefined; + delete state.interactiveThreads[discussion.id]; + continue; + } const replyExists = discussion.notes.some( - note => note.id === delivery.replyNoteId || note.body === delivery.replyBody + note => + note.id === delivery.replyNoteId || + note.body === delivery.replyBody || + compactDiscussionReplyBody(note.body) === delivery.replyBody ); if (!isDiscussionDeliveryPending(delivery) && replyExists) { if (delivery.awaitingReply) this.restoreInteractiveThread(state, discussion.id); @@ -1982,7 +2984,8 @@ export class MaintainerRunner extends BaseRoleRunner { scope?: import('../fix/maintainer-brain.js').MaintainerDecision['scope']; deleteFile?: boolean; }>; - } + }, + suppressAsk = false ): void { const fileLine = `${finding.file}:${finding.line}`; switch (decision.action) { @@ -1998,6 +3001,7 @@ export class MaintainerRunner extends BaseRoleRunner { break; } case 'ask': { + if (suppressAsk) break; buckets.askedItems.push({ fileLine, text: decision.question || decision.replyBody || decision.reason, @@ -2013,11 +3017,17 @@ export class MaintainerRunner extends BaseRoleRunner { buckets.failedItems.push( `${fileLine} — ${decision.lastFailureReason ?? '多次尝试修复未成功'}` ); + if (!suppressAsk) { + const question = decision.question ?? buildFixFailureQuestion(fileLine); + decision.question = question; + buckets.askedItems.push({ fileLine, text: question }); + } } else { // 理论上 needsRetry 才会走到这里,保留为可修复项 buckets.fixableItems.push({ finding, fileContent: '', + scope: decision.scope, deleteFile: decision.deleteFile, }); } diff --git a/src/advance/classic/runners/shared/discussion-delivery.ts b/src/advance/classic/runners/shared/discussion-delivery.ts index 340c7f9..69a5f9c 100755 --- a/src/advance/classic/runners/shared/discussion-delivery.ts +++ b/src/advance/classic/runners/shared/discussion-delivery.ts @@ -1,5 +1,6 @@ import type { Discussion, IGitProvider, MergeRequest } from '../../provider/types.js'; import type { DiscussionDeliveryState } from './state-utils.js'; +import { compactDiscussionReplyBody, hashDiscussionReplyBody } from './reply-safety.js'; export interface DiscussionDeliveryResult { replyPosted: boolean; @@ -9,15 +10,6 @@ export interface DiscussionDeliveryResult { error?: string; } -function stableHash(text: string): string { - let hash = 0; - for (let index = 0; index < text.length; index++) { - hash = (hash << 5) - hash + text.charCodeAt(index); - hash |= 0; - } - return String(hash); -} - export function isDiscussionDeliveryPending( delivery: DiscussionDeliveryState | undefined ): boolean { @@ -38,31 +30,42 @@ export async function deliverDiscussionReply(params: { discussion: Discussion; body: string; resolve: boolean; - awaitingReply?: { question: string; filePath: string }; + awaitingReply?: { question: string; filePath: string; askedAt?: number }; delivery: DiscussionDeliveryState | undefined; setDelivery: (delivery: DiscussionDeliveryState) => void; checkpoint: () => void; }): Promise { const { provider, mr, discussion, resolve, setDelivery, checkpoint } = params; - const requestedHash = stableHash(params.body); - const reusable = params.delivery?.replyHash === requestedHash ? params.delivery : undefined; + const safeBody = compactDiscussionReplyBody(params.body); + const requestedHash = hashDiscussionReplyBody(safeBody); + const existingSafeBody = params.delivery + ? compactDiscussionReplyBody(params.delivery.replyBody) + : undefined; + const reusable = + params.delivery && + (params.delivery.replyHash === requestedHash || existingSafeBody === safeBody) + ? params.delivery + : undefined; const delivery: DiscussionDeliveryState = reusable ?? { - replyBody: params.body, + replyBody: safeBody, replyHash: requestedHash, replyStatus: 'pending', resolveRequired: resolve, resolveStatus: resolve ? 'pending' : 'not-required', attempts: 0, + createdAt: Date.now(), updatedAt: Date.now(), }; - delivery.replyBody = reusable?.replyBody ?? params.body; + delivery.replyBody = safeBody; + delivery.replyHash = requestedHash; + delivery.createdAt ??= Date.now(); delivery.resolveRequired = resolve; if (params.awaitingReply) { delivery.awaitingReply = true; delivery.question = params.awaitingReply.question; delivery.filePath = params.awaitingReply.filePath; - delivery.awaitingReplyAt ??= Date.now(); + delivery.awaitingReplyAt ??= params.awaitingReply.askedAt ?? Date.now(); } if (!resolve) delivery.resolveStatus = 'not-required'; delivery.updatedAt = Date.now(); @@ -70,7 +73,10 @@ export async function deliverDiscussionReply(params: { checkpoint(); const existingNote = discussion.notes.find( - note => note.id === delivery.replyNoteId || note.body === delivery.replyBody + note => + note.id === delivery.replyNoteId || + note.body === delivery.replyBody || + compactDiscussionReplyBody(note.body) === delivery.replyBody ); if (existingNote) { delivery.replyStatus = 'posted'; diff --git a/src/advance/classic/runners/shared/maintainer-filter.ts b/src/advance/classic/runners/shared/maintainer-filter.ts index 5a2f335..ad8a63a 100755 --- a/src/advance/classic/runners/shared/maintainer-filter.ts +++ b/src/advance/classic/runners/shared/maintainer-filter.ts @@ -65,6 +65,26 @@ function getLatestNoteTime( return latest; } +function normalizeQuestionForMatch(text: string): string { + return text.toLowerCase().replace(/[\s\p{P}\p{S}]+/gu, ''); +} + +/** 判断等待中的提问是否仍在远端 discussion 中可见。 */ +export function hasVisibleMaintainerQuestion( + discussion: Discussion, + askedAt: number, + question: string +): boolean { + const normalizedQuestion = normalizeQuestionForMatch(question); + if (!normalizedQuestion) return false; + const marker = normalizedQuestion.slice(0, 120); + return discussion.notes.some(note => { + if (!isMaintainerAuthoredNote(note.body)) return false; + if (getCommentActivityAt(note) < askedAt - 1000) return false; + return normalizeQuestionForMatch(note.body).includes(marker); + }); +} + /** * 判断一条 note 是否来自真正的人类(非任何 Agent、非自动化 bot) */ @@ -118,6 +138,40 @@ function hasCompleteNoFixExplanation( return entries.every(([fileLine]) => explanationNotes.some(note => note.body.includes(fileLine))); } +/** + * 判断「无需修复说明补发」是否已熔断。 + * + * 补发过一次后,若远端说明识别仍失败(常见于行号漂移导致逐条 file:line 匹配不上), + * 不再仅因此反复补发;出现新人工回复或决策更新时熔断自动解除。 + */ +export function isNoFixBackfillCapped( + threadState: MaintainerThreadState, + lastHumanNoteAt: number +): boolean { + const backfilledAt = threadState.noFixExplanationBackfilledAt; + if (!backfilledAt) return false; + if (lastHumanNoteAt > backfilledAt) return false; + const latestDecisionAt = Object.values(threadState.decisions).reduce( + (latest, decision) => Math.max(latest, decision.decidedAt), + 0 + ); + return latestDecisionAt <= backfilledAt; +} + +/** + * 判断「Reviewer 推翻了此前的无需修复/已修复判断」。 + * + * 此前结论为 ignore(含 alreadyFixed),出现新人工回复后重新决策为 fix—— + * 说明此前的无需修复判断被人类推翻,应写入反思记忆供 already-fixed 回查参考(M7)。 + */ +export function isJudgmentFlipped( + existing: MaintainerFindingDecision | undefined, + hasNewHumanNote: boolean, + newAction: MaintainerFindingDecision['action'] +): boolean { + return existing?.action === 'ignore' && hasNewHumanNote && newAction === 'fix'; +} + /** * 判断 discussion 是否应该被 Maintainer 处理 * @@ -145,15 +199,16 @@ export function isDiscussionPending( const hasUpdatedSourceNote = sourceNoteUpdatedAt > sourceNoteBaseline; const hasPendingDelivery = isDiscussionDeliveryPending(threadState?.delivery); const hasPendingRetry = threadState ? hasPendingRetryDecision(threadState) : false; + const lastHumanNoteAt = getLatestNoteTime(discussion.notes, isHumanNote); + const backfillCapped = threadState ? isNoFixBackfillCapped(threadState, lastHumanNoteAt) : false; const needsNoFixExplanation = threadState - ? !hasCompleteNoFixExplanation(discussion, threadState) && !hasPendingRetry + ? !hasCompleteNoFixExplanation(discussion, threadState) && !hasPendingRetry && !backfillCapped : false; - if (hasPendingDelivery || needsNoFixExplanation) return true; - if ((discussion.resolved || !discussion.resolvable) && !hasPendingDelivery) { - return false; - } - - const lastHumanNoteAt = getLatestNoteTime(discussion.notes, isHumanNote); + if (hasPendingDelivery) return true; + // 已 resolved(或不可 resolve)的 thread 已被闭环:只有未完成的远端投递才允许继续, + // 「补发无需修复说明」不足以复活它——人类已接受结论,重复补发只会制造噪音评论。 + if (discussion.resolved || !discussion.resolvable) return false; + if (needsNoFixExplanation) return true; // 交互式等待回复期间保持静默:只有出现提问之后的新人工回复, // 或等待超时需要收尾时,才进入流程,避免每轮轮询空转打日志。 @@ -162,16 +217,17 @@ export function isDiscussionPending( const askedAt = interactive.askedAt; // 提问 note 已被删除(如人工清理)时,交互状态已脏: // 放行进入流程,让 processDiscussion 清理状态并重新评估 - const askNoteStillExists = discussion.notes.some(note => { - if (!isMaintainerAuthoredNote(note.body)) return false; - return getCommentActivityAt(note) >= askedAt - 1000; - }); + const askNoteStillExists = hasVisibleMaintainerQuestion( + discussion, + askedAt, + interactive.question + ); if (!askNoteStillExists) { return true; } const hasNewReply = lastHumanNoteAt > askedAt; const timedOut = Date.now() - askedAt > INTERACTIVE_REPLY_TIMEOUT_MS; - return hasNewReply || timedOut; + return hasPendingRetry || hasNewReply || timedOut; } const lastMaintainerNoteAt = getLatestNoteTime(discussion.notes, note => @@ -185,10 +241,6 @@ export function isDiscussionPending( return true; } - // 所有 finding 都已判定无需修复,但远端没有对应说明(可能从未发布或被清理): - // 必须重新进入流程补发逐项结论并 resolve,不能只依赖本地决策状态静默跳过。 - if (needsNoFixExplanation) return true; - // 如果 Maintainer 已经回复/提问过,且之后没有新的人工 note: // - 有处理证据(决策记忆/统计报告/非 finding 记录)→ 跳过,防重复回复与自我追问; // - 无处理证据(如旧版本只发过轻松回复/提问)→ 放行重新评估, diff --git a/src/advance/classic/runners/shared/mr-lifecycle.ts b/src/advance/classic/runners/shared/mr-lifecycle.ts new file mode 100644 index 0000000..1e85c4d --- /dev/null +++ b/src/advance/classic/runners/shared/mr-lifecycle.ts @@ -0,0 +1,366 @@ +/** + * Maintainer 单 MR 全生命周期自治管理 + * + * 为 Maintainer 的周期轮询提供「单 MR 视角」的生命周期状态: + * - 跟踪 MR 从发现到 merged/closed/用户中断的完整过程; + * - 聚合讨论闭环、修复/拒绝/挂起与 CI 修复指标,支撑收敛效率度量; + * - MR 进入终态(merged/closed/interrupted)时优雅退出并归档。 + * + * 本模块只包含可独立测试的纯函数与状态类型;远端交互由 MaintainerRunner 编排。 + */ + +import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import type { Discussion, ReviewerComment, CiFailedJob } from '../../provider/types.js'; + +/** 单个 head 上允许的最大 CI 自动修复尝试次数;超过则挂起等待人工 */ +export const MAX_CI_FIX_ATTEMPTS_PER_HEAD = 2; + +/** MR 生命周期记录在状态文件中的 key 前缀 */ +export const MR_LIFECYCLE_KEY_PREFIX = 'mr:'; + +export function buildMrLifecycleKey(mrIid: number): string { + return `${MR_LIFECYCLE_KEY_PREFIX}${mrIid}`; +} + +/** CI 修复进展的生命周期子状态 */ +export interface MrLifecycleCiState { + /** 最近一次观测到的 MR head SHA */ + lastHeadSha?: string; + /** 最近一次观测到的 CI 状态 */ + lastStatus?: string; + /** 最近一次 CI 失败 job 集合哈希,用于识别「同一次失败」 */ + lastFailedJobsHash?: string; + /** 当前 head 上的 CI 修复尝试次数 */ + fixAttempts: number; + /** 累计 CI 修复推送次数 */ + totalFixPushes: number; + /** CI 修复进展关联的 discussion ID(由 Maintainer 创建) */ + discussionId?: string; + /** 多次修复未果后挂起,等待人工介入 */ + suspended?: boolean; + /** 挂起原因 */ + suspendReason?: string; + updatedAt: number; +} + +/** MR 全生命周期聚合指标 */ +export interface MrLifecycleMetrics { + /** resolvable discussion 总数 */ + discussionsTotal: number; + /** 已 resolve 的 discussion 数 */ + discussionsResolved: number; + /** 自动修复成功的 finding 数 */ + findingsFixed: number; + /** 判定为不合理/无需修复并记录拒绝理由的 finding 数(辩) */ + findingsRejected: number; + /** 挂起等待人工澄清的 finding 数(挂起) */ + findingsSuspended: number; + /** 代码推送总次数(reviewer 意见 + CI 修复) */ + fixPushes: number; + /** + * 修复后仍收到人工追评的次数。 + * 作为「误修」信号:自动修复结论被人工再次质疑。 + */ + humanFollowupsAfterFix: number; + // ---- M 系列过程指标(可选,兼容旧归档;达标线见 docs/goals/maintainer-llm-centric-goal.md) ---- + /** M1 只读熔断前动用了「最后一轮行动机会」的轮数 */ + readOnlyFinalActingRounds?: number; + /** M2 commit 首次尝试即成功(未经合规改写)次数 */ + commitFirstTryPasses?: number; + /** M3 commit 首次尝试被合规校验拒绝、进入兜底改写的次数 */ + commitFirstTryRejections?: number; + /** M4 补发说明/汇总命中「已发过、跳过」的次数(去重生效) */ + duplicateSummarySkips?: number; + /** M5 ask 门禁拦截(自答问题转修复自查)次数 */ + askGateInterceptions?: number; + /** M6 hook 失败(lint/test/typecheck)后回流的次数 */ + hookFailureReflows?: number; +} + +/** 用户中断指令记录 */ +export interface MrLifecycleInterrupt { + /** 发出指令的用户名 */ + by: string; + /** 命中指令的评论正文片段 */ + command: string; + /** 指令时间戳(毫秒) */ + at: number; +} + +/** 单 MR 全生命周期状态 */ +export interface MrLifecycleState { + mrIid: number; + title: string; + sourceBranch: string; + targetBranch: string; + webUrl?: string; + /** active:自治维护中;converged:意见已收敛等待合并;archived:已退出并归档 */ + status: 'active' | 'converged' | 'archived'; + /** 归档原因 */ + endReason?: 'merged' | 'closed' | 'interrupted'; + startedAt: number; + lastPolledAt: number; + pollCount: number; + metrics: MrLifecycleMetrics; + interrupted?: MrLifecycleInterrupt; + ci?: MrLifecycleCiState; + archivedAt?: number; + /** 归档文件绝对路径 */ + archivePath?: string; +} + +export function createLifecycleState(mr: { + iid: number; + title: string; + sourceBranch: string; + targetBranch: string; + webUrl?: string; +}): MrLifecycleState { + const now = Date.now(); + return { + mrIid: mr.iid, + title: mr.title, + sourceBranch: mr.sourceBranch, + targetBranch: mr.targetBranch, + webUrl: mr.webUrl, + status: 'active', + startedAt: now, + lastPolledAt: now, + pollCount: 0, + metrics: { + discussionsTotal: 0, + discussionsResolved: 0, + findingsFixed: 0, + findingsRejected: 0, + findingsSuspended: 0, + fixPushes: 0, + humanFollowupsAfterFix: 0, + }, + }; +} + +/** + * 用户中断指令模式。 + * + * 判定刻意保守:只匹配明确的停止指令,避免把「先别修这一条」之类的普通 + * 讨论误判为全局中断。仅对人工发布的 note 生效。 + */ +const INTERRUPT_PATTERNS: RegExp[] = [ + /\/(?:ck|codekeeper|maintainer)[\s-]+(?:stop|halt|pause|abort)\b/i, + /@(?:codekeeper|maintainer)\S*\s+(?:stop|halt|pause)\b/i, + /停止自动(?:修复|维护|处理)/, + /暂停自动(?:修复|维护|处理)/, + /不要再?自动(?:修复|修改|提交)/, +]; + +export interface InterruptDetectionInput { + author: string; + body: string; + createdAt: string; +} + +/** + * 在评论中识别用户中断指令。 + * + * @param notes 候选评论(MR 级评论与 discussion note 均可) + * @param isHuman 判断作者是否为人工(非 Agent/bot)的回调 + * @returns 最新一条命中指令,无命中返回 undefined + */ +export function detectInterruptCommand( + notes: InterruptDetectionInput[], + isHuman: (author: string, body: string) => boolean +): MrLifecycleInterrupt | undefined { + let latest: MrLifecycleInterrupt | undefined; + for (const note of notes) { + if (!isHuman(note.author, note.body)) continue; + const hit = INTERRUPT_PATTERNS.some(pattern => pattern.test(note.body)); + if (!hit) continue; + const at = Date.parse(note.createdAt) || Date.now(); + if (!latest || at > latest.at) { + latest = { + by: note.author, + command: note.body.slice(0, 200), + at, + }; + } + } + return latest; +} + +/** discussion 闭环统计 */ +export interface DiscussionClosureStats { + /** resolvable discussion 总数 */ + total: number; + /** 已 resolve 数 */ + resolved: number; + /** 闭环率(total 为 0 时为 1) */ + closureRate: number; +} + +export function computeClosureStats(discussions: Discussion[]): DiscussionClosureStats { + const resolvable = discussions.filter(d => d.resolvable); + const resolved = resolvable.filter(d => d.resolved).length; + return { + total: resolvable.length, + resolved, + closureRate: resolvable.length === 0 ? 1 : resolved / resolvable.length, + }; +} + +/** + * 判定 MR 是否已收敛: + * - 没有待处理的 discussion; + * - 全部 resolvable discussion 均已 resolve; + * - CI 未处于失败状态; + * - CI 修复未处于挂起状态(挂起说明还有未闭环事项)。 + */ +export function isMrConverged(input: { + pendingDiscussionCount: number; + closure: DiscussionClosureStats; + ciStatus?: string; + ciSuspended?: boolean; +}): boolean { + if (input.pendingDiscussionCount > 0) return false; + if (input.closure.total > 0 && input.closure.resolved < input.closure.total) return false; + if (input.ciStatus === 'failed') return false; + if (input.ciSuspended) return false; + return true; +} + +/** CI 失败的修复策略分类 */ +export type CiFailureKind = 'code' | 'infra' | 'unknown'; + +/** + * GitLab job failure_reason 中明确属于基础设施/环境问题、无法通过修改代码修复的类型。 + */ +const INFRA_FAILURE_REASONS = new Set([ + 'runner_system_failure', + 'runner_unsupported', + 'stuck_or_timeout_failure', + 'scheduler_failure', + 'api_failure', + 'unknown_failure', + 'job_execution_timeout', + 'job_snapshot_timeout', + 'unmet_prerequisites', + 'data_integrity_failure', +]); + +/** + * 对 CI 失败做「修/挂起」分类: + * - infra:runner/调度/超时等基础设施失败,修改代码无意义 → 挂起; + * - code:script_failure 等可通过修改代码修复 → 尝试最小修复; + * - unknown:无失败原因时按 trace 内容兜底判断。 + */ +export function classifyCiFailure( + job: Pick +): CiFailureKind { + if (job.failureReason) { + if (INFRA_FAILURE_REASONS.has(job.failureReason)) return 'infra'; + if (job.failureReason === 'script_failure') return 'code'; + } + const trace = job.traceTail.toLowerCase(); + if ( + trace.includes('no runner') || + trace.includes('runner unavailable') || + trace.includes('network is unreachable') || + trace.includes('could not resolve host') || + trace.includes('job timeout') + ) { + return 'infra'; + } + return job.failureReason ? 'code' : 'unknown'; +} + +/** 计算失败 job 集合的稳定哈希,用于识别同一轮失败是否已处理过(不含 job id,跨 pipeline 复跑保持稳定) */ +export function hashFailedJobs(jobs: Array>): string { + const keys = jobs.map(job => `${job.stage}/${job.name}`).sort(); + let h = 0; + const text = keys.join('|'); + for (let i = 0; i < text.length; i++) { + h = (h << 5) - h + text.charCodeAt(i); + h |= 0; + } + return String(h); +} + +/** + * 从 CI 日志中提取可能存在的仓库文件路径候选。 + * + * 只保留形如 `src/foo/bar.ts` 的相对路径,排除 URL、绝对路径与 node_modules, + * 供调用方用 worktree 逐一验证存在性。 + */ +export function extractFileCandidatesFromTrace(traceTail: string, maxCandidates = 5): string[] { + const candidates: string[] = []; + const seen = new Set(); + const pattern = /(?:^|[\s('"`])((?:[\w@-]+\/)+[\w@.[\]-]+\.[a-zA-Z0-9]{1,10})(?::\d+(?::\d+)?)?/g; + let match: RegExpExecArray | null; + while ((match = pattern.exec(traceTail)) !== null) { + const candidate = match[1]; + if (candidate.startsWith('node_modules/') || candidate.includes('/node_modules/')) continue; + if (candidate.startsWith('http') || candidate.startsWith('/')) continue; + if (seen.has(candidate)) continue; + seen.add(candidate); + candidates.push(candidate); + if (candidates.length >= maxCandidates) break; + } + return candidates; +} + +/** 归档记录:生命周期状态 + 终态快照,写入项目归档目录 */ +export interface MrLifecycleArchiveRecord { + version: 1; + archivedAt: string; + projectId: string; + lifecycle: MrLifecycleState; + /** 终态时的 discussion 闭环快照 */ + closure: DiscussionClosureStats; +} + +/** + * 将生命周期记录归档到 `/maintainer-lifecycle/`。 + * + * @returns 归档文件绝对路径 + */ +export function archiveLifecycleRecord( + archiveRoot: string, + projectId: string, + lifecycle: MrLifecycleState, + closure: DiscussionClosureStats +): string { + const dir = join(archiveRoot, 'maintainer-lifecycle'); + if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + + const record: MrLifecycleArchiveRecord = { + version: 1, + archivedAt: new Date().toISOString(), + projectId, + lifecycle, + closure, + }; + + const filePath = join(dir, `mr-${lifecycle.mrIid}-${Date.now()}.json`); + writeFileSync(filePath, JSON.stringify(record, null, 2), 'utf-8'); + return filePath; +} + +/** + * 汇总 MR 级评论与 discussion note,供中断指令扫描使用。 + */ +export function collectInterruptCandidates( + mrNotes: ReviewerComment[], + discussions: Discussion[] +): InterruptDetectionInput[] { + const candidates: InterruptDetectionInput[] = mrNotes.map(note => ({ + author: note.author, + body: note.body, + createdAt: note.createdAt, + })); + for (const discussion of discussions) { + for (const note of discussion.notes) { + candidates.push({ author: note.author, body: note.body, createdAt: note.createdAt }); + } + } + return candidates; +} diff --git a/src/advance/classic/runners/shared/reply-safety.ts b/src/advance/classic/runners/shared/reply-safety.ts new file mode 100644 index 0000000..62ba031 --- /dev/null +++ b/src/advance/classic/runners/shared/reply-safety.ts @@ -0,0 +1,120 @@ +/** 远端 discussion 回复的硬性安全上限。 */ +export const MAX_DISCUSSION_REPLY_CHARS = 16_000; + +/** 单条 finding 原因的展示上限,避免底层日志淹没整条回复。 */ +export const MAX_DISCUSSION_REASON_CHARS = 1_200; + +const MAX_REPLY_LINE_CHARS = 1_600; +const MAX_REASON_LINES = 12; +const REASON_HEAD_LINES = 3; +const REASON_TAIL_LINES = 3; +const MAX_DIAGNOSTIC_LINES = 5; +const TRUNCATION_NOTICE = + '> 诊断内容过长,已由 Maintainer 自动截断;完整输出保留在本地运行日志中。'; + +const STRONG_DIAGNOSTIC_PATTERN = + /error\s+TS\d+|syntaxerror|typeerror|referenceerror|assertionerror|no exported member|cannot find|could not resolve|is not assignable|expected \d+ arguments?|permission denied|authentication failed|fatal:/i; +const FALLBACK_DIAGNOSTIC_PATTERN = /\b(?:error|failed|failure|rejected)\b/i; + +const ANSI_ESCAPE_SEQUENCE_PATTERN = new RegExp( + `${String.fromCharCode(0x1b)}\\[[0-9;]*[a-zA-Z]`, + 'g' +); +const NULL_CHARACTER = String.fromCharCode(0); + +/** 去除 ANSI 与空字符,避免终端控制序列泄漏到 Git 平台。 */ +export function stripTerminalControlCodes(text: string): string { + return text.replace(ANSI_ESCAPE_SEQUENCE_PATTERN, '').split(NULL_CHARACTER).join(''); +} + +function capLine(line: string, maxChars = MAX_REPLY_LINE_CHARS): string { + if (line.length <= maxChars) return line; + return `${line.slice(0, Math.max(0, maxChars - 1))}…`; +} + +/** 压缩单条失败/忽略原因,同时保留开头、关键错误行和日志尾部。 */ +export function compactDiscussionReason( + reason: string, + maxChars = MAX_DISCUSSION_REASON_CHARS +): string { + const normalized = stripTerminalControlCodes(reason).replace(/\r\n?/g, '\n').trim(); + if (!normalized) return '未提供具体原因'; + + const lines = normalized + .split('\n') + .map(line => line.trimEnd()) + .filter(line => line.trim().length > 0); + const selected = new Set(); + for (let index = 0; index < Math.min(REASON_HEAD_LINES, lines.length); index++) { + selected.add(index); + } + + const strongDiagnostics = lines + .map((line, index) => ({ line, index })) + .filter(item => STRONG_DIAGNOSTIC_PATTERN.test(item.line)) + .slice(0, MAX_DIAGNOSTIC_LINES); + const diagnostics = + strongDiagnostics.length > 0 + ? strongDiagnostics + : lines + .map((line, index) => ({ line, index })) + .filter(item => FALLBACK_DIAGNOSTIC_PATTERN.test(item.line)) + .slice(0, MAX_DIAGNOSTIC_LINES); + for (const diagnostic of diagnostics) selected.add(diagnostic.index); + + for (let index = Math.max(0, lines.length - REASON_TAIL_LINES); index < lines.length; index++) { + selected.add(index); + } + + const visibleLines = Array.from(selected) + .sort((left, right) => left - right) + .slice(0, MAX_REASON_LINES) + .map(index => capLine(lines[index])); + const omittedCount = Math.max(0, lines.length - visibleLines.length); + if (omittedCount > 0) visibleLines.push(`… 已省略 ${omittedCount} 行`); + + const compacted = visibleLines.join('\n'); + if (compacted.length <= maxChars) return compacted; + return `${compacted.slice(0, Math.max(0, maxChars - 1))}…`; +} + +/** + * 对整条 discussion 回复做最后一道确定性限流。 + * + * 保留 Agent footer,正文过长时只发布前部摘要与截断提示;该函数必须保持幂等, + * 以便投递状态可以安全地按压缩后的正文做哈希和重试。 + */ +export function compactDiscussionReplyBody( + body: string, + maxChars = MAX_DISCUSSION_REPLY_CHARS +): string { + let lineTruncated = false; + const normalized = stripTerminalControlCodes(body) + .replace(/\r\n?/g, '\n') + .split('\n') + .map(line => { + if (line.length > MAX_REPLY_LINE_CHARS) lineTruncated = true; + return capLine(line); + }) + .join('\n') + .trim(); + if (normalized.length <= maxChars && !lineTruncated) return normalized; + + const footerMarker = '\n\n---\n*生成于'; + const footerIndex = normalized.lastIndexOf(footerMarker); + const footer = footerIndex >= 0 ? normalized.slice(footerIndex) : ''; + const mainBody = footerIndex >= 0 ? normalized.slice(0, footerIndex) : normalized; + const suffix = `\n\n${TRUNCATION_NOTICE}${footer}`; + const budget = Math.max(0, maxChars - suffix.length); + return `${mainBody.slice(0, budget).trimEnd()}${suffix}`; +} + +/** 与既有状态兼容的稳定字符串哈希。 */ +export function hashDiscussionReplyBody(text: string): string { + let hash = 0; + for (let index = 0; index < text.length; index++) { + hash = (hash << 5) - hash + text.charCodeAt(index); + hash |= 0; + } + return String(hash); +} diff --git a/src/advance/classic/runners/shared/state-utils.ts b/src/advance/classic/runners/shared/state-utils.ts index 8f62142..e7f0750 100755 --- a/src/advance/classic/runners/shared/state-utils.ts +++ b/src/advance/classic/runners/shared/state-utils.ts @@ -69,6 +69,8 @@ export interface DiscussionDeliveryState { resolveStatus: 'not-required' | 'pending' | 'resolved' | 'failed'; /** 累计远端投递尝试次数 */ attempts: number; + /** 首次生成该投递正文的时间戳;用于淘汰跨多轮遗留的陈旧回复 */ + createdAt?: number; /** 最近一次投递错误 */ lastError?: string; /** 回复成功后是否应进入等待人工回复状态 */ @@ -177,6 +179,7 @@ function normalizeState(parsed: MrAgentState): MrAgentState { parsed.maintainerThreadState ??= {}; parsed.reviewerThreadState ??= {}; parsed.reviewCommentDelivery ??= {}; + parsed.mrLifecycle ??= {}; return parsed; } @@ -227,6 +230,9 @@ function mergeOwnedState( if (incoming.maintainerThreadState !== undefined) { merged.maintainerThreadState = incoming.maintainerThreadState; } + if (incoming.mrLifecycle !== undefined) { + merged.mrLifecycle = incoming.mrLifecycle; + } } else if (incoming.archiverState !== undefined) { merged.archiverState = incoming.archiverState; } @@ -277,6 +283,8 @@ export interface MaintainerFindingDecision { question?: string; /** fix 时是否标记为删除文件 */ deleteFile?: boolean; + /** finding 的改动范围,用于重试时继续执行写入边界校验。 */ + scope?: 'trivial' | 'local' | 'cross-file' | 'needs-clarification'; /** fix 失败时的累计重试次数 */ failedAttempts: number; /** fix 是否已经成功 */ @@ -320,9 +328,17 @@ export interface MaintainerThreadState { lastSummaryAt?: number; /** 上一次发布 summary 的内容哈希,用于去重 */ lastSummaryHash?: string; + /** + * 「无需修复说明」补发熔断时间戳。 + * 补发过一次后置位;此后若远端说明识别仍失败(如行号漂移), + * 不再仅因此重复补发——除非有新人工回复或决策更新。 + */ + noFixExplanationBackfilledAt?: number; /** 当前或最近一次远端回复投递状态 */ delivery?: DiscussionDeliveryState; lastProcessedHeadSha?: string; + /** Maintainer 历史状态自愈迁移版本。 */ + repairVersion?: number; } /** @@ -374,6 +390,8 @@ export interface MrAgentState { >; /** Archiver 项目知识批次的可恢复状态。 */ archiverState?: ArchiverState; + /** Maintainer 单 MR 全生命周期状态(key 为 `mr:`) */ + mrLifecycle?: Record; } export function getStatePath(project: Project): string { diff --git a/src/advance/classic/worktree/worktree-manager.ts b/src/advance/classic/worktree/worktree-manager.ts index caa5c18..ab870d2 100755 --- a/src/advance/classic/worktree/worktree-manager.ts +++ b/src/advance/classic/worktree/worktree-manager.ts @@ -1,5 +1,14 @@ import simpleGit, { type SimpleGit, CleanOptions } from 'simple-git'; -import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, statSync, unlinkSync, createReadStream } from 'node:fs'; +import { + readFileSync, + writeFileSync, + appendFileSync, + existsSync, + mkdirSync, + statSync, + unlinkSync, + createReadStream, +} from 'node:fs'; import { dirname, join, resolve } from 'node:path'; import { execFile } from 'node:child_process'; import { promisify } from 'node:util'; @@ -31,6 +40,24 @@ export interface RunScriptResult { reason?: string; } +export interface PrepareEnvironmentOptions { + /** + * 修复任务允许 source branch 在进入工具循环前已经无法通过 workspace 编译。 + * 依赖安装失败仍然属于硬错误,只有 compile:packages 失败可降级为基线诊断。 + */ + allowCompileFailure?: boolean; +} + +export interface PrepareEnvironmentResult { + /** 修复前已经存在的 workspace 编译失败,供上层注入修复上下文。 */ + compilePackagesFailure?: string; +} + +export interface WorktreeChangedFile { + path: string; + deleted: boolean; +} + export interface WorkspaceSearchMatch { file: string; line: number; @@ -58,7 +85,11 @@ export interface WorktreeManagerOptions { gitUserEmail?: string; } -async function defaultRunScript(script: string, cwd: string, args?: string[]): Promise { +async function defaultRunScript( + script: string, + cwd: string, + args?: string[] +): Promise { try { // Windows 上 npm 是 .cmd 脚本,execFile 直接执行需要 shell 支持 const npmArgs = args && args.length > 0 ? ['run', script, '--', ...args] : ['run', script]; @@ -70,7 +101,9 @@ async function defaultRunScript(script: string, cwd: string, args?: string[]): P } catch (err) { logger.warn({ err, script }, `运行 ${script} 失败`); const execErr = err as Error & { stdout?: string; stderr?: string }; - const reason = [execErr.message, execErr.stdout ?? '', execErr.stderr ?? ''].filter(Boolean).join('\n'); + const reason = [execErr.message, execErr.stdout ?? '', execErr.stderr ?? ''] + .filter(Boolean) + .join('\n'); return { success: false, reason }; } } @@ -102,7 +135,9 @@ async function defaultRunSetupCommand(command: string, cwd: string): Promise { + async prepareEnvironment( + options: PrepareEnvironmentOptions = {} + ): Promise { const packageJsonPath = join(this.worktreePath, 'package.json'); const nodeModulesPath = join(this.worktreePath, 'node_modules'); if (!existsSync(packageJsonPath)) { logger.info({ worktreePath: this.worktreePath }, 'worktree 无 package.json,跳过环境准备'); - return; + return {}; } let needInstall = true; @@ -241,21 +275,39 @@ export class WorktreeManager { // monorepo workspace 包需要额外编译才能被 typecheck 解析 try { - const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as { scripts?: Record }; + const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as { + scripts?: Record; + }; if (pkg.scripts?.['compile:packages']) { logger.info({ worktreePath: this.worktreePath }, 'worktree 编译 workspace 包'); const runner = this.options.runScript ?? defaultRunScript; const compileResult = await runner('compile:packages', this.worktreePath); if (!compileResult.success) { - throw new WorktreeError('compile:packages', compileResult.reason ?? '编译 workspace 包失败'); + if (options.allowCompileFailure) { + const reason = compileResult.reason ?? '编译 workspace 包失败'; + logger.warn( + { worktreePath: this.worktreePath }, + 'worktree 基线编译失败,保留诊断并继续进入修复循环' + ); + return { compilePackagesFailure: reason }; + } + throw new WorktreeError( + 'compile:packages', + compileResult.reason ?? '编译 workspace 包失败' + ); } } } catch (err) { if (err instanceof WorktreeError) { throw err; } - logger.warn({ err, worktreePath: this.worktreePath }, '读取 package.json 或编译 workspace 包失败'); + logger.warn( + { err, worktreePath: this.worktreePath }, + '读取 package.json 或编译 workspace 包失败' + ); } + + return {}; } /** @@ -276,7 +328,10 @@ export class WorktreeManager { const targetPath = join(this.worktreePath, relPath); const stats = statSync(targetPath); if (stats.size > MAX_READ_FILE_SIZE) { - throw new WorktreeError('read', `文件 ${relPath} 过大(${stats.size} bytes),超过 ${MAX_READ_FILE_SIZE} bytes 读取上限`); + throw new WorktreeError( + 'read', + `文件 ${relPath} 过大(${stats.size} bytes),超过 ${MAX_READ_FILE_SIZE} bytes 读取上限` + ); } return readFileSync(targetPath, 'utf-8'); } @@ -346,14 +401,7 @@ export class WorktreeManager { if (!normalizedKeyword || maxResults <= 0) return []; try { - const output = await this.getGit().raw([ - 'grep', - '-n', - '-I', - '-F', - '--', - normalizedKeyword, - ]); + const output = await this.getGit().raw(['grep', '-n', '-I', '-F', '--', normalizedKeyword]); return output .split(/\r?\n/) .filter(Boolean) @@ -445,19 +493,17 @@ export class WorktreeManager { const result = await this.getGit().raw(['ls-files', '-z', '--exclude-standard']); const files = result .split('\0') - .filter((f) => f.length > 0) - .map((f) => f.replace(/\\/g, '/')); + .filter(f => f.length > 0) + .map(f => f.replace(/\\/g, '/')); - const matches = files.filter( - (f) => f === basename || f.endsWith(`/${basename}`) - ); + const matches = files.filter(f => f === basename || f.endsWith(`/${basename}`)); if (matches.length === 1) { return matches[0]; } // 若有多项匹配,尝试用原始 relPath 做子路径匹配 - const subPathMatch = files.find((f) => f.endsWith(relPath.replace(/\\/g, '/'))); + const subPathMatch = files.find(f => f.endsWith(relPath.replace(/\\/g, '/'))); if (subPathMatch) { return subPathMatch; } @@ -533,7 +579,12 @@ export class WorktreeManager { * * 返回两项校验是否分别通过。 */ - async validate(): Promise<{ lint: boolean; typecheck: boolean; lintReason?: string; typecheckReason?: string }> { + async validate(): Promise<{ + lint: boolean; + typecheck: boolean; + lintReason?: string; + typecheckReason?: string; + }> { const runner = this.options.runScript ?? defaultRunScript; const [lint, typecheck] = await Promise.all([ @@ -549,6 +600,15 @@ export class WorktreeManager { }; } + /** 读取 git 工作区的权威变更列表,避免只依赖工具调用记录而漏掉脚本产生的修改。 */ + async listChangedFiles(): Promise { + const status = await this.getGit().status(); + return status.files.map(file => ({ + path: file.path.replace(/\\/g, '/'), + deleted: file.index === 'D' || file.working_dir === 'D', + })); + } + /** * 在 worktree 中运行任意 npm script */ diff --git a/src/advance/types.ts b/src/advance/types.ts index 1a8a162..aa45333 100755 --- a/src/advance/types.ts +++ b/src/advance/types.ts @@ -53,6 +53,8 @@ export interface MaintainerConfig extends BaseRoleConfig { resolveOthersDiscussions: boolean; /** 认知深度,默认 deep */ cognitiveDepth?: 'fast' | 'standard' | 'deep'; + /** CI 失败时是否自动执行最小修复,默认 true;false 时仅感知状态不做修复 */ + ciFixEnabled?: boolean; } /** diff --git a/src/assets/prompts/cognitive-already-fixed-task.md b/src/assets/prompts/cognitive-already-fixed-task.md index 50e853a..d178111 100755 --- a/src/assets/prompts/cognitive-already-fixed-task.md +++ b/src/assets/prompts/cognitive-already-fixed-task.md @@ -24,6 +24,8 @@ - 修复方式可以不是 Reviewer 提出的方法;只要当前代码已经不存在 finding 描述的问题,就返回 `alreadyFixed=true`。 2. 优先根据上面「代码(聚焦窗口)」中第 `{{findingLine}}` 行附近的代码判断。 3. 如果聚焦窗口里的代码**清楚显示问题已修复**,返回 `alreadyFixed=true`,并在 `evidence` 中给出具体证据(行号、代码片段)。 + - 同时在 `evidenceSnippet` 中原样摘录最小代码片段;该片段必须真实出现在当前目标文件或上方明确提供的额外文件上下文中。 + - 证据只能说明当前 `{{findingFile}}:{{findingLine}}` 对应的 finding,禁止引用同一评论中的其他文件、函数或 finding。 4. 如果聚焦窗口里的代码**清楚显示问题仍然存在**,返回 `alreadyFixed=false`,并在 `reason` 中说明问题在哪。 5. **如果聚焦窗口太窄,缺少判断所必需的上下文**(例如相关类型定义、imports、跨函数引用在窗口外看不到),不要猜测,请返回: - `alreadyFixed=false` @@ -41,13 +43,14 @@ 请输出 JSON: { - "alreadyFixed": true|false, - "reason": "简要说明", - "evidence": "具体证据(如第 X 行已包含 ...)", - "needsMoreContext": true|false +"alreadyFixed": true|false, +"reason": "简要说明", +"evidence": "具体证据(如第 X 行已包含 ...)", +"evidenceSnippet": "原样摘录的最小代码片段", +"evidenceLine": 123, +"needsMoreContext": true|false } - ## Additional constraints - For findings about unused code, dead code, missing call sites, or placeholder definitions, seeing only the reported function, method, or interface definition is not evidence that the problem is fixed. Require a real call site, removal of the definition, or other direct evidence that eliminates the reported problem. diff --git a/src/assets/prompts/fix-tool-loop-final-acting-round.md b/src/assets/prompts/fix-tool-loop-final-acting-round.md new file mode 100644 index 0000000..48756e8 --- /dev/null +++ b/src/assets/prompts/fix-tool-loop-final-acting-round.md @@ -0,0 +1,11 @@ +框架已对该问题执行 already-fixed 回查,结论如下: + +- 回查结论:{{verdictReason}} +- 回查证据:{{verdictEvidence}} + +你之前有较多只读探索但未产生文件变更。现在给你最后 {{steps}} 步行动机会,请基于上面的回查结论做出明确选择,二选一: + +1. 问题仍然存在:立即用 apply_patch / write_file 做最小修改,然后运行 validate,最后 finish({ success: true })。不要继续只读探索。 +2. 问题在当前代码中已不存在、或该意见本就不应修改:调用 finish({ success: false, reason: "向 Reviewer 说明的辩驳理由,需引用具体行号或代码证据" })。 + +如果这 {{steps}} 步内你仍不产生文件变更、也不调用 finish,框架将按修复失败结束并附上回查结论。 diff --git a/src/assets/prompts/fix-tool-loop-read-only-failure-reason.md b/src/assets/prompts/fix-tool-loop-read-only-failure-reason.md index 194ad08..b632579 100755 --- a/src/assets/prompts/fix-tool-loop-read-only-failure-reason.md +++ b/src/assets/prompts/fix-tool-loop-read-only-failure-reason.md @@ -1 +1 @@ -连续 {{steps}} 步没有产生文件变更,修复停留在只读探索阶段;已触发 already-fixed 回查但未确认问题已消失 +连续 {{steps}} 步没有产生文件变更,修复停留在只读探索阶段。already-fixed 回查结论:{{verdictReason}}(证据:{{verdictEvidence}});框架已给予最后一轮带诊断的行动机会,LLM 仍未修改文件或明确 finish diff --git a/src/assets/prompts/fix-tool-loop-system.md b/src/assets/prompts/fix-tool-loop-system.md index 2fed5a1..70381c6 100755 --- a/src/assets/prompts/fix-tool-loop-system.md +++ b/src/assets/prompts/fix-tool-loop-system.md @@ -20,4 +20,5 @@ 16. 在调用 finish({ success: true, ... }) 之前,必须已经通过 write_file、apply_patch 或 delete_file 实际修改或删除了至少一个文件;如果你尚未做任何文件变更,不要调用 finish,否则我会要求你重新修改。 17. Reviewer 的修改建议仅供参考。你应先理解问题根因,再决定最合适的修复方式;如果建议本身不合理、无法直接实施,或存在更简洁/更安全的替代方案,你可以选择自己的方案,并在 finish reason 中简要说明为什么这样做。 18. 如果问题涉及 singleton、模块级状态、reset、dispose 或多实例行为,必须先搜索定义、注入、重置和生命周期调用点,确认状态的实际拥有者;重点验证销毁实例 A 不会清空实例 B 的状态。不能只修改注释或测试来规避架构问题。 +19. 如果读取当前目标文件后确认 finding 已被其他提交修复、当前代码已不存在该问题,调用 finish,并额外设置 alreadyFixed=true;reason 与 evidence 只能描述当前目标 finding,不能引用同一 discussion 的其他 finding。框架会再次独立回查,不会直接采信该结论。 {{extraSystemPrompt}} diff --git a/src/assets/prompts/maintainer-already-fixed-reply.md b/src/assets/prompts/maintainer-already-fixed-reply.md index 74ea50c..350f2a6 100755 --- a/src/assets/prompts/maintainer-already-fixed-reply.md +++ b/src/assets/prompts/maintainer-already-fixed-reply.md @@ -1,3 +1,3 @@ -✅ {{maintainerName}} 经检查,本 discussion 指出的问题在当前代码中似乎已经修复:{{replyBody}} +✅ {{maintainerName}} 经检查,本 discussion 指出的问题在当前代码中已经修复:{{replyBody}} -请 Reviewer 复核确认。 +以上结论附具体代码证据,本 thread 将由 Maintainer 直接关闭;如 Reviewer 对结论有异议,欢迎 reopen 并指出仍存在的问题。 diff --git a/src/gitlab/client.ts b/src/gitlab/client.ts index df04ec3..e966392 100755 --- a/src/gitlab/client.ts +++ b/src/gitlab/client.ts @@ -62,6 +62,33 @@ export class GitLabClient { return response.json() as Promise; } + /** + * 读取纯文本响应(如 job trace 日志),不走 JSON 解析。 + */ + private async requestText(endpoint: string): Promise { + const url = `${this.baseUrl}/api/v4${endpoint}`; + const headers: Record = { 'PRIVATE-TOKEN': this.token }; + + logger.debug(`GitLab API GET(text) ${endpoint}`); + + let response: Response; + try { + response = await fetch(url, { method: 'GET', headers }); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + logger.error({ url, err: message }, `GitLab API fetch failed: GET(text) ${endpoint}`); + throw new Error(`GitLab API fetch failed: ${message}`); + } + + if (!response.ok) { + const errorText = await response.text(); + logger.error({ status: response.status, body: errorText }, `GitLab API error: GET(text) ${endpoint}`); + throw new Error(`GitLab API ${response.status}: ${errorText}`); + } + + return response.text(); + } + /** * 读取 GitLab 列表接口的全部分页。 * @@ -316,6 +343,33 @@ export class GitLabClient { `/projects/${this.projectId}/merge_requests?${query.toString()}` ); } + + /** + * List pipelines of a merge request (latest first) + */ + async getMergeRequestPipelines(iid: number, perPage = 5): Promise { + return this.request( + 'GET', + `/projects/${this.projectId}/merge_requests/${iid}/pipelines?per_page=${perPage}` + ); + } + + /** + * List jobs of a pipeline + */ + async listPipelineJobs(pipelineId: number, perPage = 100): Promise { + return this.request( + 'GET', + `/projects/${this.projectId}/pipelines/${pipelineId}/jobs?per_page=${perPage}` + ); + } + + /** + * Get the raw trace (log) of a job + */ + async getJobTrace(jobId: number): Promise { + return this.requestText(`/projects/${this.projectId}/jobs/${jobId}/trace`); + } } // GitLab API response types @@ -411,3 +465,24 @@ export interface GitLabDiffPosition { new_line: number; old_line?: number; } + +export interface GitLabPipeline { + id: number; + sha: string; + ref: string; + status: string; + web_url?: string; + created_at?: string; + updated_at?: string; +} + +export interface GitLabJob { + id: number; + name: string; + stage: string; + status: string; + web_url?: string; + failure_reason?: string; + started_at?: string; + finished_at?: string; +} diff --git a/src/scheduler.ts b/src/scheduler.ts index eed1776..862234f 100755 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -1,11 +1,11 @@ -import cron from 'node-cron'; +import cron, { type ScheduledTask } from 'node-cron'; import { logger } from './core/logger.js'; import { runReview, runLearning } from './index.js'; import type { ProjectConfig } from './types.js'; interface ScheduledJob { task: string; - job: cron.ScheduledTask; + job: ScheduledTask; } const jobs: ScheduledJob[] = []; @@ -84,7 +84,6 @@ function scheduleJob( } }, { - scheduled: true, timezone, } ); diff --git a/tests/advance/classic/fix/ask-gate.test.ts b/tests/advance/classic/fix/ask-gate.test.ts new file mode 100644 index 0000000..de85eb7 --- /dev/null +++ b/tests/advance/classic/fix/ask-gate.test.ts @@ -0,0 +1,65 @@ +/** + * ask-gate 单元测试(L2) + * + * 正面夹具取材自真实 MR 的索问(已按 RULES §3 脱敏)。 + */ + +import { describe, it, expect } from 'vitest'; +import { isSelfAnswerableQuestion, isRepoContentReply } from '../../../../src/advance/classic/fix/ask-gate.js'; + +describe('isSelfAnswerableQuestion', () => { + it('真实现场:索要仓库内文件内容被拦截', () => { + expect( + isSelfAnswerableQuestion( + '请提供 packages/example-memory/src/core/foundation/telemetry/tracker.ts 文件的内容,以便分析全局 tracker 的当前实现,以及评估三种修复方案对 telemetry 模块的影响。' + ) + ).toBe(true); + }); + + it('请贴出代码片段被拦截', () => { + expect(isSelfAnswerableQuestion('请贴出 memoryFacade.ts 中 dispose 方法的代码片段')).toBe(true); + }); + + it('能否提供 xx 的实现被拦截', () => { + expect(isSelfAnswerableQuestion('能否提供一下 sink 注册部分的实现?')).toBe(true); + }); + + it('英文索要文件内容被拦截', () => { + expect(isSelfAnswerableQuestion('Could you please provide the content of tracker.ts?')).toBe( + true + ); + }); + + it('意图澄清类问题放行(真正需要人回答)', () => { + expect(isSelfAnswerableQuestion('我尝试自动修复但未成功,请补充期望的修改方式或范围。')).toBe( + false + ); + expect(isSelfAnswerableQuestion('这个全局 reset 是有意设计还是历史遗留?')).toBe(false); + expect(isSelfAnswerableQuestion('多实例场景下是否允许遥测数据丢失?')).toBe(false); + }); + + it('空问题放行', () => { + expect(isSelfAnswerableQuestion('')).toBe(false); + }); +}); + + +describe('isRepoContentReply(G7 漏判候选信号)', () => { + it('含代码围栏的回复判定为仓库内容', () => { + expect(isRepoContentReply('可以直接这样改:\n```ts\nresetTracker(this);\n```')).toBe(true); + }); + + it('含文件路径引用的回复判定为仓库内容', () => { + expect(isRepoContentReply('参考 packages/core/src/tracker.ts:913 的 dispose 实现')).toBe(true); + expect(isRepoContentReply('配置在 config/deploy.yaml 里')).toBe(true); + }); + + it('纯方案讨论/意图澄清回复不判定为仓库内容', () => { + expect(isRepoContentReply('保留兼容旧接口,按方案二处理')).toBe(false); + expect(isRepoContentReply('这是有意设计,多实例场景允许丢失')).toBe(false); + }); + + it('空回复不判定为仓库内容', () => { + expect(isRepoContentReply('')).toBe(false); + }); +}); diff --git a/tests/advance/classic/fix/cognitive-engine.test.ts b/tests/advance/classic/fix/cognitive-engine.test.ts index fd0d4e0..630d1dc 100755 --- a/tests/advance/classic/fix/cognitive-engine.test.ts +++ b/tests/advance/classic/fix/cognitive-engine.test.ts @@ -1,5 +1,8 @@ import { describe, it, expect, vi } from 'vitest'; -import { CognitiveEngine } from '../../../../src/advance/classic/cognitive-engine.js'; +import { + CognitiveEngine, + isAlreadyFixedEvidenceGrounded, +} from '../../../../src/advance/classic/cognitive-engine.js'; import { LlmClient } from '../../../../src/advance/llm/client.js'; import type { CognitiveContext } from '../../../../src/advance/classic/fix/cognitive-types.js'; import type { IMemoryClient } from '../../../../src/advance/classic/memory/types.js'; @@ -74,6 +77,39 @@ function makeAlreadyFixedLlmClient(alreadyFixed: boolean): LlmClient { }); } +describe('isAlreadyFixedEvidenceGrounded', () => { + it('拒绝引用其他 finding 函数的错位代码证据', () => { + expect( + isAlreadyFixedEvidenceGrounded({ + findingFile: 'src/a.ts', + fileContent: 'export function targetFunction() { return true; }', + evidence: '`otherFunction` 已经包含所需保护', + }) + ).toBe(false); + expect( + isAlreadyFixedEvidenceGrounded({ + findingFile: 'src/a.ts', + fileContent: 'export function targetFunction() { return true; }', + evidence: '`targetFunction` 已经包含所需保护', + }) + ).toBe(true); + expect( + isAlreadyFixedEvidenceGrounded({ + findingFile: 'src/a.ts', + fileContent: 'export function targetFunction() { return true; }', + evidence: 'otherFunction 已经包含所需保护', + }) + ).toBe(false); + expect( + isAlreadyFixedEvidenceGrounded({ + findingFile: 'src/feature/index.ts', + fileContent: 'export function targetFunction() { return true; }', + evidence: 'src/other/index.ts 中已包含所需保护', + }) + ).toBe(false); + }); +}); + describe('CognitiveEngine', () => { it('fast 模式解析 CognitiveDecision', async () => { const engine = new CognitiveEngine({ @@ -447,9 +483,9 @@ describe('CognitiveEngine', () => { ], }, }); - const searchWorkspace = vi.fn().mockResolvedValue([ - { file: 'src/facade.ts', line: 30, content: 'facade.dispose();' }, - ]); + const searchWorkspace = vi + .fn() + .mockResolvedValue([{ file: 'src/facade.ts', line: 30, content: 'facade.dispose();' }]); const worktreeManager = mockOf({ searchWorkspace }); const engine = new CognitiveEngine({ llmClient, worktreeManager }); diff --git a/tests/advance/classic/fix/commit-pipeline.test.ts b/tests/advance/classic/fix/commit-pipeline.test.ts new file mode 100644 index 0000000..34ee296 --- /dev/null +++ b/tests/advance/classic/fix/commit-pipeline.test.ts @@ -0,0 +1,138 @@ +/** + * commit-pipeline 单元测试 + * + * 夹具取材自真实 MR 的失败现场(已按 RULES §3 脱敏,见回归文档)。 + */ + +import { describe, it, expect } from 'vitest'; +import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { + classifyCommitFailure, + detectCommitConvention, + distillCommitFailure, + buildDefaultBatchMessage, + buildDefaultDeleteMessage, + buildDefaultFixMessage, +} from '../../../../src/advance/classic/fix/commit-pipeline.js'; + +const CONVENTIONAL = /^[a-z]+(?:\([^)]*\))?:\s/i; + +describe('classifyCommitFailure', () => { + it('真实现场:几千行 lint 噪音尾部的 commit-msg 拒绝归类为 commit-message', () => { + const lintNoise = Array.from( + { length: 500 }, + (_, i) => `src/some/file-${i}.ts\n ${i}:26 warning Forbidden non-null assertion` + ).join('\n'); + const raw = `Worktree commit 失败:\n${lintNoise}\n❌ Commit message 不符合 Conventional Commits 规范。\n格式: ():\ntypes: feat | fix | docs | chore\n当前: 批量修复 1 个 Reviewer 问题`; + expect(classifyCommitFailure(raw)).toBe('commit-message'); + }); + + it('项目自定义模板(提交标题不符合项目模板)归类为 commit-message', () => { + const raw = `❌ 提交标题不符合项目模板。\n要求: [任务编号] 简短说明\n当前: 批量修复 1 个 Reviewer 问题`; + expect(classifyCommitFailure(raw)).toBe('commit-message'); + }); + + it('eslint error 归类为 lint', () => { + const raw = `src/index.ts\n 2:7 error no-unused-vars\n✖ 3 problems (3 errors, 0 warnings)`; + expect(classifyCommitFailure(raw)).toBe('lint'); + }); + + it('测试失败归类为 test', () => { + const raw = ` FAIL src/index.test.ts > 用例\nTests 1 failed | 3 passed`; + expect(classifyCommitFailure(raw)).toBe('test'); + }); + + it('类型错误归类为 typecheck', () => { + const raw = `src/index.ts:8:8 - error TS2503: Cannot find namespace 'cron'.`; + expect(classifyCommitFailure(raw)).toBe('typecheck'); + }); + + it('权限拒绝归类为 permission', () => { + expect(classifyCommitFailure('remote: Permission to repo denied (403).')).toBe('permission'); + }); + + it('非快进 push 归类为 push', () => { + expect(classifyCommitFailure('! [rejected] feature -> feature (non-fast-forward)')).toBe('push'); + }); + + it('无法识别归类为 unknown', () => { + expect(classifyCommitFailure('一些完全无法识别的输出')).toBe('unknown'); + }); +}); + +describe('distillCommitFailure', () => { + it('几千行原文蒸馏为 ≤10 行,首行是归类,噪音被剔除', () => { + const lintNoise = Array.from( + { length: 800 }, + (_, i) => ` ${i}:26 warning Forbidden non-null assertion` + ).join('\n'); + const raw = `Worktree commit 失败:\n${lintNoise}\n❌ Commit message 不符合 Conventional Commits 规范。\n当前: 批量修复 1 个 Reviewer 问题`; + const distilled = distillCommitFailure(raw); + const lines = distilled.split('\n'); + expect(lines.length).toBeLessThanOrEqual(10); + expect(lines[0]).toContain('【提交失败分类: commit-message】'); + expect(distilled).toContain('批量修复 1 个 Reviewer 问题'); + expect(distilled).not.toContain('warning Forbidden non-null assertion\n 100:'); + }); +}); + +describe('detectCommitConvention', () => { + it('commitlint.config.js 命中', () => { + const dir = mkdtempSync(join(tmpdir(), 'ck-conv-')); + writeFileSync(join(dir, 'commitlint.config.js'), 'module.exports = {};'); + expect(detectCommitConvention(dir)).toContain('Conventional Commits'); + }); + + it('package.json commitlint 键命中', () => { + const dir = mkdtempSync(join(tmpdir(), 'ck-conv-')); + writeFileSync(join(dir, 'package.json'), JSON.stringify({ commitlint: { extends: [] } })); + expect(detectCommitConvention(dir)).toContain('Conventional Commits'); + }); + + it('.husky/commit-msg 命中', () => { + const dir = mkdtempSync(join(tmpdir(), 'ck-conv-')); + mkdirSync(join(dir, '.husky')); + writeFileSync(join(dir, '.husky', 'commit-msg'), 'npx commitlint --edit $1'); + expect(detectCommitConvention(dir)).toContain('Conventional Commits'); + }); + + it('无任何配置时返回 undefined', () => { + const dir = mkdtempSync(join(tmpdir(), 'ck-conv-')); + writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'plain' })); + expect(detectCommitConvention(dir)).toBeUndefined(); + }); +}); + +describe('合规默认提交信息(F2 第三级兜底)', () => { + it('单 finding 默认信息具备合规形态', () => { + const message = buildDefaultFixMessage({ + message: '变量未使用', + ruleId: 'no-unused-vars', + file: 'src/index.ts', + line: 2, + }); + expect(message.split('\n')[0]).toMatch(CONVENTIONAL); + expect(message).toContain('变量未使用'); + }); + + it('已具备合规形态的 subject 不重复加前缀', () => { + const message = buildDefaultFixMessage({ + message: 'fix(api): 变量未使用', + file: 'src/index.ts', + line: 2, + }); + expect(message.split('\n')[0]).toBe('fix(api): 变量未使用'); + }); + + it('批量默认信息具备合规形态', () => { + const message = buildDefaultBatchMessage(['src/a.ts'], ['docs/b.md']); + expect(message.split('\n')[0]).toMatch(CONVENTIONAL); + expect(message).toContain('批量修复 2 个 Reviewer 问题'); + }); + + it('删除文件默认信息具备合规形态', () => { + expect(buildDefaultDeleteMessage('telemetry-plan.md')).toMatch(CONVENTIONAL); + }); +}); diff --git a/tests/advance/classic/fix/fix-tool-loop.test.ts b/tests/advance/classic/fix/fix-tool-loop.test.ts index 8f70842..6bc1132 100755 --- a/tests/advance/classic/fix/fix-tool-loop.test.ts +++ b/tests/advance/classic/fix/fix-tool-loop.test.ts @@ -1,6 +1,7 @@ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; import { FixToolLoop } from '../../../../src/advance/classic/fix/fix-tool-loop.js'; import { LlmClient } from '../../../../src/advance/llm/client.js'; +import { defaultPromptLoader } from '../../../../src/advance/llm/prompts/loader.js'; import type { WorktreeManager } from '../../../../src/advance/classic/worktree/worktree-manager.js'; import type { ReviewFinding, @@ -189,6 +190,47 @@ describe('FixToolLoop', () => { expect(loop.getAppliedFiles()).toEqual([]); }); + it('finish 显式声明 alreadyFixed 时经框架回查后返回独立终态', async () => { + const recheckAlreadyFixed = vi.fn().mockResolvedValue({ + alreadyFixed: true, + reason: '当前目标文件已经包含所需保护', + evidence: 'guardValue 在返回前完成空值检查', + }); + const loop = new FixToolLoop({ + llmClient: createMockLlmClient([ + { + toolCalls: [ + { + id: '1', + name: 'finish', + input: { + success: false, + alreadyFixed: true, + reason: '问题已由其他提交修复', + evidence: 'guardValue 已完成检查', + }, + }, + ], + }, + ]), + worktreeManager: createMockWorktreeManager(), + finding: mockFinding, + mr: mockMR, + recheckAlreadyFixed, + }); + + const result = await loop.run(); + + expect(recheckAlreadyFixed).toHaveBeenCalledOnce(); + expect(result).toEqual({ + success: true, + alreadyFixed: true, + reason: '当前目标文件已经包含所需保护', + evidence: 'guardValue 在返回前完成空值检查', + }); + expect(loop.getAppliedFiles()).toEqual([]); + }); + it('读取同一文件的不同窗口视为有进展,不因 5 步无进展早退', async () => { const loop = new FixToolLoop({ llmClient: createMockLlmClient([ @@ -299,6 +341,117 @@ describe('FixToolLoop', () => { reason: '当前代码已经满足 Reviewer 要求', }); }); + + it('只读上限后回灌回查结论并给最后行动机会,LLM 修改后修复成功', async () => { + const loadedPrompts: string[] = []; + const spyLoader = { + load: (name: string, vars?: Record) => { + loadedPrompts.push(`${name} ${JSON.stringify(vars ?? {})}`); + return defaultPromptLoader.load(name, vars); + }, + register: () => undefined, + setAssetDir: () => undefined, + }; + const recheckAlreadyFixed = vi.fn().mockResolvedValue({ + alreadyFixed: false, + reason: '问题仍存在:缺少 TODO 注释', + evidence: '第 25 行未见 TODO 标记', + }); + const loop = new FixToolLoop({ + llmClient: createMockLlmClient([ + { + toolCalls: [ + { + id: '1', + name: 'read_file', + input: { relPath: 'src/index.ts', startLine: 1, endLine: 10 }, + }, + ], + }, + { + toolCalls: [ + { + id: '2', + name: 'read_file', + input: { relPath: 'src/index.ts', startLine: 11, endLine: 20 }, + }, + ], + }, + { + toolCalls: [ + { + id: '3', + name: 'read_file', + input: { relPath: 'src/index.ts', startLine: 21, endLine: 30 }, + }, + ], + }, + // 最后行动机会内实际修改 + { + toolCalls: [ + { id: '4', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '5', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]), + worktreeManager: createMockWorktreeManager(), + finding: mockFinding, + mr: mockMR, + maxSteps: 20, + maxReadOnlySteps: 3, + readOnlyReminderStep: 2, + finalActingSteps: 3, + recheckAlreadyFixed, + promptLoader: spyLoader, + }); + + const result = await loop.run(); + + expect(result.success).toBe(true); + expect(recheckAlreadyFixed).toHaveBeenCalledTimes(1); + // 谢幕消息必须携带回查结论(带诊断谢幕,而非机械暴毙) + const finalRound = loadedPrompts.find(entry => + entry.startsWith('fix-tool-loop-final-acting-round') + ); + expect(finalRound).toBeDefined(); + expect(finalRound).toContain('缺少 TODO 注释'); + expect(finalRound).toContain('第 25 行未见 TODO'); + }); + + it('最后行动机会内仍只读探索则失败,失败原因携带回查结论', async () => { + const recheckAlreadyFixed = vi.fn().mockResolvedValue({ + alreadyFixed: false, + reason: '问题仍存在:缺少 TODO 注释', + evidence: '第 25 行未见 TODO 标记', + }); + const readResponses = Array.from({ length: 6 }, (_, index) => ({ + toolCalls: [ + { + id: String(index + 1), + name: 'read_file', + input: { relPath: 'src/index.ts', startLine: index * 10 + 1, endLine: index * 10 + 10 }, + }, + ], + })); + const loop = new FixToolLoop({ + llmClient: createMockLlmClient(readResponses), + worktreeManager: createMockWorktreeManager(), + finding: mockFinding, + mr: mockMR, + maxSteps: 20, + maxReadOnlySteps: 3, + readOnlyReminderStep: 2, + finalActingSteps: 3, + recheckAlreadyFixed, + }); + + const result = await loop.run(); + + expect(result.success).toBe(false); + expect(result.reason).toContain('缺少 TODO 注释'); + expect(result.reason).toContain('第 25 行未见 TODO'); + expect(result.reason).toContain('最后一轮带诊断的行动机会'); + }); it('可配置 maxStepsWithoutProgress,缩短无进展早退阈值', async () => { const loop = new FixToolLoop({ llmClient: createMockLlmClient([ diff --git a/tests/advance/classic/fix/maintainer-actor.test.ts b/tests/advance/classic/fix/maintainer-actor.test.ts index 9accbd6..1afd667 100755 --- a/tests/advance/classic/fix/maintainer-actor.test.ts +++ b/tests/advance/classic/fix/maintainer-actor.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { MaintainerActor, stripAnsiCodes, @@ -17,6 +17,7 @@ import type { import type { WorktreeManager } from '../../../../src/advance/classic/worktree/worktree-manager.js'; import type { MrAgentState } from '../../../../src/advance/classic/runners/shared/state-utils.js'; import type { IMemoryClient } from '../../../../src/advance/classic/memory/types.js'; +import type { MrLifecycleMetrics } from '../../../../src/advance/classic/runners/shared/mr-lifecycle.js'; function createMockBrain(overrides: Partial = {}) { return { @@ -39,12 +40,21 @@ const mockMR: MergeRequest = { webUrl: '', }; -const mockDiscussion: Discussion = { - id: 'd-1', - resolvable: true, - resolved: false, - notes: [], -}; +/** + * 每个用例使用独立的 discussion 夹具。 + * deliverDiscussionReply 会就地写入 resolved/notes,模块级共享对象会跨用例污染, + * 导致后续用例因 discussion.resolved 已为 true 而断言不到 resolveDiscussion 调用。 + */ +let mockDiscussion: Discussion; + +beforeEach(() => { + mockDiscussion = { + id: 'd-1', + resolvable: true, + resolved: false, + notes: [], + }; +}); const mockFinding: ReviewFinding = { severity: 'MEDIUM', @@ -208,13 +218,333 @@ describe('MaintainerActor', () => { confidence: 'medium', }; - const result = await actor.executeFix(mockMR, mockDiscussion, mockFinding, decision, createState()); + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); expect(result.codeApplied).toBe(false); expect(captured.task).toContain('变量未使用'); expect(captured.task).toContain('删除'); expect(captured.system).toContain('检查 singleton reset 与 dispose 的多实例影响'); }); + + it('Runner 接管重试时单次失败不立即向 Reviewer 求助', async () => { + const provider = createMockProvider(); + const decision: CognitiveDecision = { + action: 'fix', + reason: '需要修复', + fixDescription: '调整当前实现', + analysis: '', + consideredOptions: [], + reasoning: '', + confidence: 'medium', + }; + const actor = new MaintainerActor({ + provider, + llmClient: createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'finish', input: { success: false, reason: '本轮尚未完成' } }, + ], + }, + ]), + worktreeManager: createMockWorktreeManager(), + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + + const result = await actor.applyDecision( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState(), + { askOnFixFailure: false } + ); + + expect(result.codeApplied).toBe(false); + expect(provider.addDiscussionNote).not.toHaveBeenCalled(); + expect(decision.question).toBeUndefined(); + }); + + it('局部 finding 越界修改其他文件时拒绝提交', async () => { + const worktreeManager = createMockWorktreeManager(); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient: createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { + toolCalls: [ + { + id: '2', + name: 'write_file', + input: { relPath: 'virtual/module-b.ts', content: 'unexpected' }, + }, + ], + }, + { toolCalls: [{ id: '3', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]), + worktreeManager, + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '局部修复', + fixDescription: '只调整目标文件', + scope: 'local', + analysis: '', + consideredOptions: [], + reasoning: '', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(false); + expect(result.error).toContain('越界修改'); + expect(worktreeManager.commitAndPush).not.toHaveBeenCalled(); + }); + + it('批量局部 finding 越界修改未批准文件时拒绝整批提交', async () => { + const changedFiles = new Set(); + const worktreeManager = createMockWorktreeManager({ + writeFile: vi.fn().mockImplementation((filePath: string) => { + changedFiles.add(filePath); + }), + listChangedFiles: vi + .fn() + .mockImplementation(async () => + Array.from(changedFiles, filePath => ({ path: filePath, deleted: false })) + ), + }); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient: createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/a.ts', content: 'fixed a' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'a done' } }] }, + { + toolCalls: [ + { id: '3', name: 'write_file', input: { relPath: 'src/b.ts', content: 'fixed b' } }, + ], + }, + { + toolCalls: [ + { + id: '4', + name: 'write_file', + input: { relPath: 'virtual/module-c.ts', content: 'unexpected' }, + }, + ], + }, + { toolCalls: [{ id: '5', name: 'finish', input: { success: true, reason: 'b done' } }] }, + ]), + worktreeManager, + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + const findings: ReviewFinding[] = [ + { + severity: 'LOW', + file: 'src/a.ts', + line: 10, + message: '修正 a 的局部逻辑', + suggestion: '只修改 a', + }, + { + severity: 'MEDIUM', + file: 'src/b.ts', + line: 20, + message: '修正 b 的局部逻辑', + suggestion: '只修改 b', + }, + ]; + + const result = await actor.executeBatchFix( + mockMR, + findings.map(finding => ({ finding, fileContent: 'current', scope: 'local' })), + '批量修复两个局部问题' + ); + + expect(result.success).toBe(false); + expect(result.reason).toContain('virtual/module-c.ts'); + expect(result.itemResults).toEqual( + expect.arrayContaining([ + expect.objectContaining({ file: 'src/a.ts', status: 'deferred' }), + expect.objectContaining({ file: 'src/b.ts', status: 'failed' }), + ]) + ); + expect(worktreeManager.commitAndPush).not.toHaveBeenCalled(); + }); + + it('坏基线编译不会阻止进入修复循环', async () => { + const captured: { system?: string } = {}; + const llmClient = createMockLlmClient([]); + const responses = [ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]; + vi.spyOn(llmClient, 'completeWithTools').mockImplementation( + async (_messages, _tools, options) => { + captured.system = options?.system; + return { content: '', ...responses.shift()!, stopReason: 'tool_use' }; + } + ); + const prepareEnvironment = vi.fn().mockResolvedValue({ + compilePackagesFailure: 'src/module.ts(8,2): error TS2305: missing export', + }); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager: createMockWorktreeManager({ prepareEnvironment }), + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '需要修复', + fixDescription: '调整目标文件', + scope: 'local', + analysis: '', + consideredOptions: [], + reasoning: '', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(true); + expect(prepareEnvironment).toHaveBeenCalledWith({ allowCompileFailure: true }); + expect(captured.system).toContain('修复前基线'); + expect(captured.system).toContain('error TS2305'); + }); + + it('CI 修复使用解析后的仓库路径并可穿过坏基线', async () => { + const captured: { task?: string } = {}; + const llmClient = createMockLlmClient([]); + const responses = [ + { + toolCalls: [ + { + id: '1', + name: 'write_file', + input: { relPath: 'packages/example/src/module.ts', content: 'fixed' }, + }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]; + vi.spyOn(llmClient, 'completeWithTools').mockImplementation(async (messages, _tools) => { + captured.task = String(messages[0]?.content ?? ''); + return { content: '', ...responses.shift()!, stopReason: 'tool_use' }; + }); + const prepareEnvironment = vi.fn().mockResolvedValue({ + compilePackagesFailure: 'src/module.ts(12,15): error TS2305: Module has no exported member.', + }); + const worktreeManager = createMockWorktreeManager({ + prepareEnvironment, + resolveFilePath: vi.fn().mockResolvedValue('packages/example/src/module.ts'), + }); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + + const result = await actor.executeCiFix(mockMR, { + status: 'failed', + pipelineId: 10, + failedJobs: [ + { + id: 20, + name: 'build', + stage: 'verify', + failureReason: 'script_failure', + traceTail: 'src/module.ts(12,15): error TS2305: Module has no exported member.', + }, + ], + }); + + expect(result.codeApplied).toBe(true); + expect(result.appliedFiles).toContain('packages/example/src/module.ts'); + expect(captured.task).toContain('packages/example/src/module.ts'); + expect(prepareEnvironment).toHaveBeenCalledWith({ allowCompileFailure: true }); + }); + + it('批量修复只把当前 finding 注入工具循环,不混入同 discussion 的其他证据', async () => { + const llmClient = createMockLlmClient([]); + const captured: { task?: string; system?: string } = {}; + vi.spyOn(llmClient, 'completeWithTools').mockImplementation( + async (messages, _tools, options) => { + captured.task = String(messages[0]?.content ?? ''); + captured.system = options?.system; + return { + content: '', + toolCalls: [ + { id: '1', name: 'finish', input: { success: false, reason: '当前项无法自动修复' } }, + ], + stopReason: 'tool_use', + }; + } + ); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager: createMockWorktreeManager(), + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + const finding: ReviewFinding = { + severity: 'MEDIUM', + file: 'src/a.ts', + line: 10, + message: '当前函数缺少边界保护', + suggestion: '补充空值判断', + }; + + await actor.executeBatchFix( + mockMR, + [{ finding, fileContent: 'export function current() {}' }], + 'src/b.ts:20 的 `otherFunction` 已经修复,src/c.ts:30 仍需检查' + ); + + expect(captured.task).toContain('src/a.ts'); + expect(captured.task).not.toContain('src/b.ts'); + expect(captured.task).not.toContain('otherFunction'); + expect(captured.system).not.toContain('src/b.ts'); + expect(captured.system).not.toContain('otherFunction'); + }); + it('commit 被 hook 拒绝时学习提交规范、写入项目记忆并重试', async () => { const provider = createMockProvider(); const commitAndPush = vi @@ -460,9 +790,10 @@ describe('MaintainerActor', () => { expect.stringContaining('移除不应上传的文件'), { setUpstream: false } ); + // F2:无项目记忆/静态探测命中时,默认提交信息也必须具备合规形态 expect(worktreeManager.commitAndPush).toHaveBeenCalledWith( 'feature/test', - expect.not.stringMatching(/^[a-z]+(?:\([^)]*\))?:\s/i), + expect.stringMatching(/^chore\(review\): 移除不应上传的文件/), { setUpstream: false } ); expect(provider.resolveDiscussion).toHaveBeenCalledWith(mockMR.iid, mockDiscussion.id); @@ -607,10 +938,109 @@ describe('MaintainerActor', () => { reason: '默认 sink 路径已有测试覆盖', }, ], + itemResults: [ + { + file: 'src/index.ts', + line: 2, + status: 'already-fixed', + reason: '默认 sink 路径已有测试覆盖', + }, + ], }); expect(worktreeManager.commitAndPush).not.toHaveBeenCalled(); }); + it('后续 finding 失败时保留 already-fixed,并把未执行项标记为 deferred', async () => { + const firstFinding: ReviewFinding = { + severity: 'LOW', + file: 'src/a.ts', + line: 10, + message: '确认现有保护是否完整', + suggestion: '检查当前实现', + }; + const secondFinding: ReviewFinding = { + severity: 'MEDIUM', + file: 'src/b.ts', + line: 20, + message: '补充边界判断', + suggestion: '修正逻辑', + }; + const thirdFinding: ReviewFinding = { + severity: 'LOW', + file: 'src/c.ts', + line: 30, + message: '清理冗余分支', + suggestion: '删除多余代码', + }; + const recheckAlreadyFixed = vi.fn().mockResolvedValue({ + alreadyFixed: true, + reason: '当前代码已经满足要求', + evidence: '目标函数已经包含所需保护', + }); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient: createMockLlmClient([ + { + toolCalls: [ + { + id: '1', + name: 'finish', + input: { + success: false, + alreadyFixed: true, + reason: '当前代码已经修复', + evidence: '目标函数已经包含所需保护', + }, + }, + ], + }, + { + toolCalls: [ + { id: '2', name: 'finish', input: { success: false, reason: '无法安全修改当前项' } }, + ], + }, + ]), + worktreeManager: createMockWorktreeManager(), + brain: createMockBrain({ recheckAlreadyFixed }), + maintainerName: 'Maintainer', + }); + + const result = await actor.executeBatchFix( + mockMR, + [ + { finding: firstFinding, fileContent: 'export function first() {}' }, + { finding: secondFinding, fileContent: 'export function second() {}' }, + { finding: thirdFinding, fileContent: 'export function third() {}' }, + ], + '三个独立 finding' + ); + + expect(result.success).toBe(false); + expect(result.alreadyFixedItems).toEqual([ + { file: 'src/a.ts', line: 10, reason: '目标函数已经包含所需保护' }, + ]); + expect(result.itemResults).toEqual([ + { + file: 'src/a.ts', + line: 10, + status: 'already-fixed', + reason: '目标函数已经包含所需保护', + }, + { + file: 'src/b.ts', + line: 20, + status: 'failed', + reason: '无法安全修改当前项', + }, + { + file: 'src/c.ts', + line: 30, + status: 'deferred', + reason: '前序 finding 未完成,本轮尚未执行', + }, + ]); + }); + it('汇总全部为无需修复项时逐项回复并 resolve discussion', async () => { const provider = createMockProvider(); const actor = new MaintainerActor({ @@ -644,17 +1074,57 @@ describe('MaintainerActor', () => { ); expect(provider.resolveDiscussion).toHaveBeenCalledWith(mockMR.iid, mockDiscussion.id); }); -}); -describe('提交信息输出预处理', () => { - it('stripAnsiCodes 移除 ANSI 转义码', () => { - expect(stripAnsiCodes('警告')).toBe('警告'); - expect(stripAnsiCodes('无转义字符')).toBe('无转义字符'); - }); + it('等待 Reviewer 时发布新进度不会刷新首次提问时间', async () => { + const provider = createMockProvider(); + const actor = new MaintainerActor({ + provider, + llmClient: createMockLlmClient([]), + worktreeManager: createMockWorktreeManager(), + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + const state = createState(); + const askedAt = Date.now() - 60_000; + state.interactiveThreads[mockDiscussion.id] = { + status: 'awaiting-reply', + askedAt, + question: '请确认预期行为', + filePath: 'src/a.ts', + }; - it('extractCommitRejectionSection 只保留冗长输出尾部诊断窗口', () => { - const noise = Array.from({ length: 150 }, (_, index) => `lint 警告 ${index}`).join('\n'); - const section = + await actor.postSummary( + mockMR, + mockDiscussion, + [], + ['src/b.ts:20 — 本轮修复失败'], + [], + [], + [], + state + ); + + expect(state.interactiveThreads[mockDiscussion.id]?.askedAt).toBe(askedAt); + expect(state.maintainerThreadState?.[mockDiscussion.id]?.delivery?.awaitingReplyAt).toBe( + askedAt + ); + expect(provider.addDiscussionNote).toHaveBeenCalledWith( + mockMR.iid, + mockDiscussion.id, + expect.stringContaining('请确认预期行为') + ); + }); +}); + +describe('提交信息输出预处理', () => { + it('stripAnsiCodes 移除 ANSI 转义码', () => { + expect(stripAnsiCodes('警告')).toBe('警告'); + expect(stripAnsiCodes('无转义字符')).toBe('无转义字符'); + }); + + it('extractCommitRejectionSection 只保留冗长输出尾部诊断窗口', () => { + const noise = Array.from({ length: 150 }, (_, index) => `lint 警告 ${index}`).join('\n'); + const section = '❌ Commit message 不符合 Conventional Commits 规范。\n格式: (): '; const extracted = extractCommitRejectionSection(`${noise}\n${section}`); expect(extracted).toContain('Commit message'); @@ -664,9 +1134,520 @@ describe('提交信息输出预处理', () => { }); it('extractCommitRejectionSection 无相关标记时仍返回尾部诊断', () => { - const text = Array.from({ length: 150 }, (_, index) => `完全无关的日志内容 ${index}`).join('\n'); + const text = Array.from({ length: 150 }, (_, index) => `完全无关的日志内容 ${index}`).join( + '\n' + ); const extracted = extractCommitRejectionSection(text); expect(extracted).not.toContain('完全无关的日志内容 0\n'); expect(extracted).toContain('完全无关的日志内容 149'); }); }); + +describe('提交管道(F3/L3)', () => { + it('lint 类 hook 失败回流修复循环,消除错误后重试提交成功', async () => { + const lintFailure = + 'Worktree commit 失败:\nsrc/index.ts\n 2:7 error no-unused-vars\n✖ 3 problems (3 errors, 0 warnings)'; + const commitAndPush = vi + .fn() + .mockRejectedValueOnce(new Error(lintFailure)) + .mockResolvedValue(undefined); + const worktreeManager = createMockWorktreeManager({ commitAndPush }); + const brain = createMockBrain({ + recheckAlreadyFixed: vi + .fn() + .mockResolvedValue({ alreadyFixed: false, reason: '校验错误仍存在' }), + }); + const llmClient = createMockLlmClient([ + // 第一轮修复:改文件 + finish + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + // 回流轮:根据蒸馏诊断再改 + finish + { + toolCalls: [ + { + id: '3', + name: 'write_file', + input: { relPath: 'src/index.ts', content: 'lint-fixed' }, + }, + ], + }, + { toolCalls: [{ id: '4', name: 'finish', input: { success: true, reason: 'lint done' } }] }, + ]); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + }); + + const result = await actor.executeBatchFix( + mockMR, + [{ finding: mockFinding, fileContent: 'const unused = 1;' }], + 'Reviewer 要求删除未使用变量' + ); + + expect(result.success).toBe(true); + expect(commitAndPush).toHaveBeenCalledTimes(2); + }); + + it('permission 类失败不回流不重试,错误为 ≤10 行蒸馏诊断而非原文', async () => { + const noise = Array.from({ length: 200 }, (_, i) => `第 ${i} 行 hook 日志输出`).join('\n'); + const commitAndPush = vi + .fn() + .mockRejectedValue(new Error(`${noise}\nremote: Permission to repo denied (403).`)); + const worktreeManager = createMockWorktreeManager({ commitAndPush }); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '删除未使用变量', + fixDescription: '删除未使用变量', + analysis: '存在未使用变量', + consideredOptions: ['删除'], + reasoning: '删除更干净', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(false); + expect(commitAndPush).toHaveBeenCalledTimes(1); + expect(result.error).toContain('【提交失败分类: permission】'); + expect(result.error).not.toContain('第 0 行 hook 日志输出'); + expect(result.error?.split('\n').length).toBeLessThanOrEqual(10); + }); + + it('提交信息重写后的第二次失败仍只返回蒸馏诊断', async () => { + const firstNoise = Array.from({ length: 120 }, (_, index) => `lint warning ${index}`).join( + '\n' + ); + const secondNoise = Array.from({ length: 200 }, (_, index) => `push detail ${index}`).join( + '\n' + ); + const commitAndPush = vi + .fn() + .mockRejectedValueOnce( + new Error( + `${firstNoise}\n\u001b[31mCommit message 不符合项目格式\u001b[0m\n要求: [任务编号] 简短说明` + ) + ) + .mockRejectedValueOnce( + new Error( + `${secondNoise}\n\u001b[33mremote: Permission to repository denied (403).\u001b[0m` + ) + ); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + vi.spyOn(llmClient, 'completeJson').mockResolvedValue( + JSON.stringify({ + retry: true, + convention: '提交标题使用 [任务编号] 简短说明', + message: '[TASK-1] 修正边界处理', + }) + ); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager: createMockWorktreeManager({ commitAndPush }), + brain: createMockBrain(), + maintainerName: 'Maintainer', + }); + + const result = await actor.executeBatchFix( + mockMR, + [{ finding: mockFinding, fileContent: 'const unused = 1;' }], + '修正边界处理' + ); + + expect(commitAndPush).toHaveBeenCalledTimes(2); + expect(result.success).toBe(false); + expect(result.reason).toContain('【提交失败分类: permission】'); + expect(result.reason).not.toContain('\u001b['); + expect(result.reason).not.toContain('push detail 0'); + expect(result.reason.length).toBeLessThanOrEqual(6_000); + expect(result.reason.split('\n').length).toBeLessThanOrEqual(10); + expect(result.itemResults[0]).toMatchObject({ status: 'failed' }); + }); +}); + +describe('ask 门禁(L2)与修复终局插桩(M7)', () => { + it('仓库内可自查的索问被门禁拦截,转为修复自查且不发布原索问', async () => { + const provider = createMockProvider(); + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const actor = new MaintainerActor({ + provider, + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + }); + const decision: CognitiveDecision = { + action: 'ask', + reason: '需要文件内容才能分析', + question: '请提供 src/index.ts 文件的内容,以便分析当前实现。', + analysis: '缺少文件内容', + consideredOptions: ['索要文件'], + reasoning: '没有文件无法分析', + confidence: 'low', + }; + + const result = await actor.applyDecision( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + // 门禁后转为修复:走了 commit,且从未把原索问发布到 MR + expect(result.codeApplied).toBe(true); + expect(worktreeManager.commitAndPush).toHaveBeenCalled(); + const postedBodies = provider.addDiscussionNote.mock.calls.map(call => String(call[2])); + expect(postedBodies.some(body => body.includes('请提供 src/index.ts 文件的内容'))).toBe(false); + }); + + it('修复循环失败时写入 EverOS 终局记录(outcome:failure)', async () => { + const memoryClient = { + context: { projectId: 'p1' }, + recordFixAttempt: vi.fn().mockResolvedValue(undefined), + } as unknown as IMemoryClient; + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [{ id: '1', name: 'finish', input: { success: false, reason: '无法定位根因' } }], + }, + ]); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + memoryClient, + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '修复未使用变量', + fixDescription: '删除未使用变量', + analysis: '存在未使用变量', + consideredOptions: ['删除'], + reasoning: '删除更干净', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(false); + expect(memoryClient.recordFixAttempt).toHaveBeenCalledWith( + expect.objectContaining({ + mrIid: mockMR.iid, + file: mockFinding.file, + success: false, + reason: expect.stringContaining('outcome:failure'), + }) + ); + }); + + it('修复成功时写入 EverOS 终局记录(outcome:success)', async () => { + const memoryClient = { + context: { projectId: 'p1' }, + recordFixAttempt: vi.fn().mockResolvedValue(undefined), + } as unknown as IMemoryClient; + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + memoryClient, + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '修复未使用变量', + fixDescription: '删除未使用变量', + analysis: '存在未使用变量', + consideredOptions: ['删除'], + reasoning: '删除更干净', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(true); + expect(memoryClient.recordFixAttempt).toHaveBeenCalledWith( + expect.objectContaining({ + success: true, + reason: expect.stringContaining('outcome:success'), + }) + ); + }); +}); + +describe('M 系列过程指标(G8)', () => { + function createMetrics(): MrLifecycleMetrics { + return { + discussionsTotal: 0, + discussionsResolved: 0, + findingsFixed: 0, + findingsRejected: 0, + findingsSuspended: 0, + fixPushes: 0, + humanFollowupsAfterFix: 0, + }; + } + + it('commit 首次尝试成功计入 commitFirstTryPasses', async () => { + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const metrics = createMetrics(); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + metrics, + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '删除未使用变量', + fixDescription: '删除未使用变量', + analysis: '存在未使用变量', + consideredOptions: ['删除'], + reasoning: '删除更干净', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(true); + expect(metrics.commitFirstTryPasses).toBe(1); + expect(metrics.commitFirstTryRejections ?? 0).toBe(0); + expect(metrics.hookFailureReflows ?? 0).toBe(0); + }); + + it('lint 回流计入 commitFirstTryRejections 与 hookFailureReflows,重试成功不再计首试通过', async () => { + const lintFailure = + 'Worktree commit 失败:\nsrc/index.ts\n 2:7 error no-unused-vars\n✖ 3 problems (3 errors, 0 warnings)'; + const commitAndPush = vi + .fn() + .mockRejectedValueOnce(new Error(lintFailure)) + .mockResolvedValue(undefined); + const worktreeManager = createMockWorktreeManager({ commitAndPush }); + const brain = createMockBrain({ + recheckAlreadyFixed: vi + .fn() + .mockResolvedValue({ alreadyFixed: false, reason: '校验错误仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + { + toolCalls: [ + { + id: '3', + name: 'write_file', + input: { relPath: 'src/index.ts', content: 'lint-fixed' }, + }, + ], + }, + { toolCalls: [{ id: '4', name: 'finish', input: { success: true, reason: 'lint done' } }] }, + ]); + const metrics = createMetrics(); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + metrics, + }); + + const result = await actor.executeBatchFix( + mockMR, + [{ finding: mockFinding, fileContent: 'const unused = 1;' }], + 'Reviewer 要求删除未使用变量' + ); + + expect(result.success).toBe(true); + expect(metrics.commitFirstTryRejections).toBe(1); + expect(metrics.hookFailureReflows).toBe(1); + expect(metrics.commitFirstTryPasses ?? 0).toBe(0); + }); + + it('ask 门禁拦截计入 askGateInterceptions', async () => { + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const metrics = createMetrics(); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + metrics, + }); + const decision: CognitiveDecision = { + action: 'ask', + reason: '需要文件内容才能分析', + question: '请提供 src/index.ts 文件的内容,以便分析当前实现。', + analysis: '缺少文件内容', + consideredOptions: ['索要文件'], + reasoning: '没有文件无法分析', + confidence: 'low', + }; + + const result = await actor.applyDecision( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(true); + expect(metrics.askGateInterceptions).toBe(1); + }); + + it('未注入 metrics 时指标路径静默跳过(兼容旧调用方)', async () => { + const worktreeManager = createMockWorktreeManager(); + const brain = createMockBrain({ + recheckAlreadyFixed: vi.fn().mockResolvedValue({ alreadyFixed: false, reason: '问题仍存在' }), + }); + const llmClient = createMockLlmClient([ + { + toolCalls: [ + { id: '1', name: 'write_file', input: { relPath: 'src/index.ts', content: 'fixed' } }, + ], + }, + { toolCalls: [{ id: '2', name: 'finish', input: { success: true, reason: 'done' } }] }, + ]); + const actor = new MaintainerActor({ + provider: createMockProvider(), + llmClient, + worktreeManager, + brain, + maintainerName: 'Maintainer', + }); + const decision: CognitiveDecision = { + action: 'fix', + reason: '删除未使用变量', + fixDescription: '删除未使用变量', + analysis: '存在未使用变量', + consideredOptions: ['删除'], + reasoning: '删除更干净', + confidence: 'high', + }; + + const result = await actor.executeFix( + mockMR, + mockDiscussion, + mockFinding, + decision, + createState() + ); + + expect(result.codeApplied).toBe(true); + }); +}); diff --git a/tests/advance/classic/replay/real-mr-replay.test.ts b/tests/advance/classic/replay/real-mr-replay.test.ts new file mode 100644 index 0000000..6111ec8 --- /dev/null +++ b/tests/advance/classic/replay/real-mr-replay.test.ts @@ -0,0 +1,187 @@ +/** + * G2:真实 MR 快照回放 harness + * + * 数据来源:tests/fixtures/real-mr-snapshot/discussions.json + * 由 .tmp-mr-analysis/extract_fixture.py 从 GitLab 页面快照(2026-07-30 抓取)提取, + * 快照本身体积过大不入库;fixture 保留了全部 25 条讨论的评论时间线, + * 已按 RULES §3 去品牌化/去真实路径脱敏(.tmp-mr-analysis/sanitize_fixture.py)。 + * + * 该 MR 曾暴露三类 Maintainer 失控模式,本 harness 用真实评论正文做回归断言: + * 1. 重复评论:已发过「✅ 已修复」的 discussion 被再次补发 already-fixed 说明 + * (190140ab / ac669e74 的第二条 maintainer note); + * 2. 修复失败提问:fix 失败后向 Reviewer 索要修改方式(8dbe20a5); + * 3. 陈旧 pending 投递重试:7-27 生成的说明 7-30 才被补投(190140ab note 2 时间差)。 + * + * 断言分两层: + * - 分类层:真实 note 正文必须被署名/已修复说明识别函数正确归类(熔断机制的前置条件); + * - 过滤层:基线状态回放 isDiscussionPending,已闭环讨论不得复活、补发熔断必须生效。 + */ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import type { Discussion, ReviewerComment } from '../../../../src/advance/classic/provider/types.js'; +import type { + MaintainerThreadState, + MrAgentState, +} from '../../../../src/advance/classic/runners/shared/state-utils.js'; +import { + isDiscussionPending, + isNoFixBackfillCapped, +} from '../../../../src/advance/classic/runners/shared/maintainer-filter.js'; +import { + isMaintainerAuthoredNote, + isMaintainerNoFixExplanationNote, +} from '../../../../src/advance/classic/runners/shared/review-utils.js'; + +const FIXTURE_PATH = join( + dirname(fileURLToPath(import.meta.url)), + '../../../fixtures/real-mr-snapshot/discussions.json' +); + +interface FixtureNote { + noteId: string; + author: string; + authorKind: 'bot' | 'human'; + kind: 'review-agent' | 'maintainer-agent' | 'system' | 'comment'; + at: string | null; + body: string; +} + +interface FixtureDiscussion { + discussionId: string; + resolvable: boolean; + resolved: boolean; + notes: FixtureNote[]; +} + +const fixture = JSON.parse(readFileSync(FIXTURE_PATH, 'utf-8')) as FixtureDiscussion[]; +const byId = new Map(fixture.map(d => [d.discussionId.slice(0, 8), d])); + +function toDiscussion(d: FixtureDiscussion): Discussion { + const notes: ReviewerComment[] = d.notes.map(n => ({ + id: Number(n.noteId), + author: n.author, + body: n.body, + createdAt: n.at ?? '', + updatedAt: n.at ?? undefined, + })); + return { id: d.discussionId, resolvable: d.resolvable, resolved: d.resolved, notes }; +} + +function lastNoteAt(d: FixtureDiscussion): number { + return d.notes.reduce((max, n) => Math.max(max, n.at ? Date.parse(n.at) : 0), 0); +} + +/** 基线状态:最后一轮轮询已在所有评论之后完成 */ +function baselinedState(d: FixtureDiscussion): Pick< + MrAgentState, + 'interactiveThreads' | 'processedDiscussions' | 'maintainerThreadState' +> { + return { + interactiveThreads: {}, + processedDiscussions: { + [d.discussionId]: { noteCount: d.notes.length, processedAt: lastNoteAt(d) + 1000 }, + }, + maintainerThreadState: {}, + }; +} + +describe('真实 MR fixture 完整性', () => { + it('覆盖 25 条讨论与关键失控场景', () => { + expect(fixture).toHaveLength(25); + // 重复 already-fixed 补发的两条讨论 + expect(byId.get('190140ab')?.notes.filter(n => n.kind === 'maintainer-agent')).toHaveLength(2); + expect(byId.get('ac669e74')?.notes.filter(n => n.kind === 'maintainer-agent')).toHaveLength(2); + // 修复失败向 Reviewer 索要修改方式的讨论 + expect(byId.get('8dbe20a5')?.notes.some(n => n.body.includes('未成功'))).toBe(true); + }); +}); + +describe('真实评论正文的分类识别', () => { + it('所有 maintainer-agent 评论都被署名识别(自我评论不触发再处理)', () => { + const maintainerNotes = fixture.flatMap(d => + d.notes.filter(n => n.kind === 'maintainer-agent') + ); + expect(maintainerNotes.length).toBeGreaterThanOrEqual(8); + for (const note of maintainerNotes) { + expect(isMaintainerAuthoredNote(note.body)).toBe(true); + } + }); + + it('already-fixed 补发说明被识别为最终说明(补发熔断可生效)', () => { + for (const [key, noteIdx] of [ + ['190140ab', 2], + ['ac669e74', 2], + ['ea4d32a4', 1], + ] as const) { + const note = byId.get(key)!.notes[noteIdx]; + expect(isMaintainerNoFixExplanationNote(note.body)).toBe(true); + } + }); + + it('修复失败提问评论被识别为 Maintainer 自述而非人工输入', () => { + const note = byId.get('8dbe20a5')!.notes[1]; + expect(note.body).toContain('未成功'); + expect(isMaintainerAuthoredNote(note.body)).toBe(true); + }); +}); + +describe('过滤层回放:闭环讨论不复活', () => { + it('所有已 resolved 讨论在基线状态下均不 pending(不会再发任何评论)', () => { + const resolved = fixture.filter(d => d.resolved); + expect(resolved.length).toBeGreaterThanOrEqual(15); + for (const d of resolved) { + expect(isDiscussionPending(toDiscussion(d), baselinedState(d))).toBe(false); + } + }); + + it('190140ab:已修复 + 已补发的讨论即使未 resolved,也被补发熔断压住', () => { + const d = byId.get('190140ab')!; + const discussion = { ...toDiscussion(d), resolved: false }; + const backfilledAt = Date.parse(d.notes[2].at!); + const threadState: MaintainerThreadState = { + decisions: { + // 行号漂移场景:note 正文匹配不到该 fileLine,识别不完整 + 'docs/internal/plans/2026-06-24-telemetry-plan.md:99': { + action: 'ignore', + alreadyFixed: true, + reason: '文件已删除', + failedAttempts: 0, + decidedAt: Date.parse(d.notes[1].at!), + }, + }, + lastReviewerNoteAt: Date.parse(d.notes[0].at!), + noFixExplanationBackfilledAt: backfilledAt, + }; + const lastHumanNoteAt = Date.parse(d.notes[0].at!); + + expect(isNoFixBackfillCapped(threadState, lastHumanNoteAt)).toBe(true); + const state = { + ...baselinedState(d), + maintainerThreadState: { [d.discussionId]: threadState }, + }; + expect(isDiscussionPending(discussion, state)).toBe(false); + }); + + it('补发后出现新人工回复时熔断解除(允许重新评估)', () => { + const d = byId.get('ac669e74')!; + const backfilledAt = Date.parse(d.notes[2].at!); + const threadState: MaintainerThreadState = { + decisions: { + 'docs/internal/specs/2026-06-24-telemetry-design.md:1': { + action: 'ignore', + alreadyFixed: true, + reason: '文件已删除', + failedAttempts: 0, + decidedAt: Date.parse(d.notes[1].at!), + }, + }, + lastReviewerNoteAt: Date.parse(d.notes[0].at!), + noFixExplanationBackfilledAt: backfilledAt, + }; + const newHumanReplyAt = backfilledAt + 60_000; + + expect(isNoFixBackfillCapped(threadState, newHumanReplyAt)).toBe(false); + }); +}); diff --git a/tests/advance/classic/runners/maintainer-runner.test.ts b/tests/advance/classic/runners/maintainer-runner.test.ts index 1c291df..b41b300 100755 --- a/tests/advance/classic/runners/maintainer-runner.test.ts +++ b/tests/advance/classic/runners/maintainer-runner.test.ts @@ -3,9 +3,12 @@ import { MaintainerRunner, buildSummaryStateHash, classifyBatchFixItems, + getDiscussionDeliveryInvalidationReason, hasHeadChangedSinceProcessing, + repairLegacyMaintainerThreadState, refreshDiscussionProcessedHeadSha, runDiscussionTasks, + type CiHandlingResult, } from '../../../../src/advance/classic/runners/maintainer-runner.js'; import { LlmClient } from '../../../../src/advance/llm/client.js'; import type { @@ -18,7 +21,15 @@ import type { MaintainerBrain } from '../../../../src/advance/classic/fix/mainta import type { MaintainerActor } from '../../../../src/advance/classic/fix/maintainer-actor.js'; import type { WorktreeManager } from '../../../../src/advance/classic/worktree/worktree-manager.js'; import type { MemoryClient } from '../../../../src/advance/classic/memory/memory-client.js'; -import type { MrAgentState } from '../../../../src/advance/classic/runners/shared/state-utils.js'; +import type { MaintainerConfig } from '../../../../src/advance/types.js'; +import { + createLifecycleState, + type MrLifecycleState, +} from '../../../../src/advance/classic/runners/shared/mr-lifecycle.js'; +import type { + MaintainerThreadState, + MrAgentState, +} from '../../../../src/advance/classic/runners/shared/state-utils.js'; import { mockOf } from '../../../helpers/mock-of.js'; function makeLlmClient(): LlmClient { @@ -114,6 +125,13 @@ describe('buildSummaryStateHash', () => { expect(duplicateHash).toBe(singleHash); }); + + it('暂缓与失败属于不同处理状态', () => { + const deferredHash = buildSummaryStateHash([], [], [], [], [], ['src/a.ts:10 — 本轮尚未执行']); + const failedHash = buildSummaryStateHash([], ['src/a.ts:10 — 修复失败'], [], [], []); + + expect(deferredHash).not.toBe(failedHash); + }); }); describe('refreshDiscussionProcessedHeadSha', () => { @@ -149,6 +167,74 @@ const mockFinding: ReviewFinding = { }; describe('MaintainerRunner', () => { + it('代码型 CI 修复未成功时仍阻断本轮普通 discussion', async () => { + const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); + const provider = mockOf({ + getCIStatus: vi.fn().mockResolvedValue('failed'), + getCiFailureReport: vi.fn().mockResolvedValue({ + status: 'failed', + pipelineId: 42, + failedJobs: [ + { + id: 7, + name: 'typecheck', + stage: 'build', + failureReason: 'script_failure', + traceTail: 'src/module.ts(12,15): error TS2305: Module has no exported member.', + }, + ], + }), + createDiscussion: vi.fn().mockResolvedValue('ci-discussion'), + addDiscussionNote: vi.fn().mockResolvedValue(undefined), + }); + const actor = mockOf({ + executeCiFix: vi.fn().mockResolvedValue({ + codeApplied: false, + reason: '本轮未能消除类型错误', + appliedFiles: [], + }), + }); + const lifecycle = createLifecycleState(mockMR); + const config: MaintainerConfig = { + role: 'maintainer', + enabled: true, + reviewSchedule: '*/10 * * * *', + learningEnabled: true, + maintainerName: 'Maintainer', + autoFixEnabled: true, + resolveOthersDiscussions: true, + }; + const ciRunner = runner as unknown as { + handleCiStatus( + provider: GitLabProvider, + actor: MaintainerActor, + mr: MergeRequest, + lifecycle: MrLifecycleState, + config: MaintainerConfig, + maintainerName: string, + currentHeadSha?: string + ): Promise; + }; + + const result = await ciRunner.handleCiStatus( + provider, + actor, + mockMR, + lifecycle, + config, + 'Maintainer', + 'head-1' + ); + + expect(actor.executeCiFix).toHaveBeenCalledOnce(); + expect(result).toEqual({ + fixAttempted: true, + fixPushed: false, + deferDiscussionProcessing: true, + }); + expect(lifecycle.ci?.fixAttempts).toBe(1); + }); + it('合并路径别名后复用成功终态,不再重复处理同一 finding', async () => { const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); const canonicalFile = 'modules/example-a/src/tracker.test.ts'; @@ -276,11 +362,11 @@ describe('MaintainerRunner', () => { }); const worktreeManager = mockOf({ + getWorktreePath: vi.fn().mockReturnValue('/worktree'), ensureWorktree: vi.fn().mockResolvedValue(undefined), checkoutBranch: vi.fn().mockResolvedValue(undefined), prepareEnvironment: vi.fn().mockResolvedValue(undefined), resolveFilePath: vi.fn().mockResolvedValue('src/index.ts'), - getWorktreePath: vi.fn().mockReturnValue('/worktree'), readFileWindow: vi.fn().mockResolvedValue({ imports: '', snippet: 'const a = 1;\nconst b = 2;', @@ -319,6 +405,122 @@ describe('MaintainerRunner', () => { expect(provider.getMRDiff).toHaveBeenCalledWith(mockMR.iid); }); + it('单条 finding 首次修复失败时保留自动重试而不立即提问', async () => { + const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); + const finding: ReviewFinding = { + severity: 'MEDIUM', + file: 'src/a.ts', + line: 8, + message: '需要调整边界条件', + suggestion: '修正判断逻辑', + }; + const discussion: Discussion = { + id: 'd-single-retry', + resolvable: true, + resolved: false, + notes: [ + { + id: 1, + author: 'reviewer-bot', + body: 'src/a.ts:8 | 需要调整边界条件', + createdAt: '2026-08-04T00:00:00Z', + resolved: false, + }, + ], + }; + const brain = mockOf({ + parseFindings: vi.fn().mockResolvedValue([finding]), + enrichFindingsWithCases: vi.fn().mockImplementation(async findings => findings), + decide: vi.fn().mockResolvedValue({ + action: 'fix', + reason: '需要修复', + fixDescription: '修正判断逻辑', + scope: 'local', + }), + }); + const actor = mockOf({ + applyDecision: vi.fn().mockResolvedValue({ + codeApplied: false, + replyPosted: false, + resolved: false, + awaitingReply: false, + pending: false, + error: '本地验证暂未通过', + }), + postSummary: vi.fn().mockResolvedValue({ + replyPosted: true, + resolved: false, + pending: false, + }), + }); + const worktreeManager = mockOf({ + ensureWorktree: vi.fn().mockResolvedValue(undefined), + checkoutBranch: vi.fn().mockResolvedValue(undefined), + resolveFilePath: vi.fn().mockResolvedValue(finding.file), + getWorktreePath: vi.fn().mockReturnValue('/virtual-worktree'), + readFileWindow: vi.fn().mockResolvedValue({ + imports: '', + snippet: 'export const value = true;', + snippetStartLine: 1, + snippetEndLine: 12, + totalLines: 12, + truncated: false, + targetLine: finding.line, + }), + }); + const state = mockOf({ interactiveThreads: {}, processedDiscussions: {} }); + + await runner.processDiscussion( + mockMR, + discussion, + mockOf({ + getMRDiff: vi.fn().mockResolvedValue([ + { + filePath: finding.file, + additions: 1, + deletions: 0, + oldPath: finding.file, + newPath: finding.file, + newFile: false, + deletedFile: false, + diff: '', + }, + ]), + }), + brain, + actor, + worktreeManager, + 'CodeKeeper Maintainer', + state, + '/virtual-project' + ); + + expect(actor.applyDecision).toHaveBeenCalledWith( + mockMR, + discussion, + finding, + expect.objectContaining({ action: 'fix' }), + state, + { askOnFixFailure: false } + ); + expect(actor.postSummary).toHaveBeenCalledWith( + mockMR, + discussion, + [], + ['src/a.ts:8 — 本地验证暂未通过'], + [], + [], + [], + state + ); + expect(state.maintainerThreadState?.[discussion.id]?.decisions['src/a.ts:8']).toMatchObject({ + action: 'fix', + failedAttempts: 1, + fixSucceeded: false, + }); + expect(state.interactiveThreads[discussion.id]).toBeUndefined(); + }); + it('无法解析 finding 时由 LLM 决策 record,只录入记忆不回复', async () => { const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); @@ -680,11 +882,11 @@ describe('MaintainerRunner', () => { }); const worktreeManager = mockOf({ + getWorktreePath: vi.fn().mockReturnValue('/worktree'), ensureWorktree: vi.fn().mockResolvedValue(undefined), checkoutBranch: vi.fn().mockResolvedValue(undefined), prepareEnvironment: vi.fn().mockResolvedValue(undefined), resolveFilePath: vi.fn().mockResolvedValue('src/index.ts'), - getWorktreePath: vi.fn().mockReturnValue('/worktree'), readFileWindow: vi.fn().mockResolvedValue({ imports: '', snippet: 'const a = 1;\nconst b = 2;', @@ -1677,6 +1879,268 @@ describe('MaintainerRunner', () => { expect(state.processedDiscussions?.['d-agent-interactive']).toBeDefined(); }); + it('等待 Reviewer 回复时继续处理同 discussion 的可重试 finding', async () => { + const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); + const askedAt = Date.now() - 60_000; + const findings: ReviewFinding[] = [ + { + severity: 'MEDIUM', + file: 'src/a.ts', + line: 10, + message: '需要确认业务意图', + suggestion: '请确认预期行为', + }, + { + severity: 'MEDIUM', + file: 'src/b.ts', + line: 20, + message: '缺少边界保护', + suggestion: '补充边界判断', + }, + ]; + const discussion: Discussion = { + id: 'd-awaiting-with-retry', + resolvable: true, + resolved: false, + notes: [ + { + id: 1, + author: 'reviewer-agent', + body: '包含两个待处理 finding', + createdAt: new Date(askedAt - 60_000).toISOString(), + resolved: false, + }, + { + id: 2, + author: 'maintainer', + body: '请确认业务意图\n\n---\n*生成于 2026/08/03 10:00:00 · CodeKeeper Advance MR 维护 Agent · bot*', + createdAt: new Date(askedAt).toISOString(), + resolved: false, + }, + ], + }; + const brain = mockOf({ + parseFindings: vi.fn().mockResolvedValue(findings), + enrichFindingsWithCases: vi.fn().mockImplementation(async items => items), + decide: vi.fn().mockResolvedValue({ + action: 'fix', + reason: '可以自动补充保护', + fixDescription: '补充边界判断', + scope: 'local', + }), + }); + const actor = mockOf({ + executeBatchFix: vi.fn().mockResolvedValue({ + success: true, + reason: '已推送', + appliedFiles: ['src/b.ts'], + deletedFiles: [], + alreadyFixedItems: [], + itemResults: [{ file: 'src/b.ts', line: 20, status: 'fixed' }], + }), + postSummary: vi.fn().mockResolvedValue({ + replyPosted: true, + resolved: false, + pending: false, + }), + }); + const provider = mockOf({ getMRDiff: vi.fn().mockResolvedValue([]) }); + const worktreeManager = mockOf({ + getWorktreePath: vi.fn().mockReturnValue('/worktree'), + ensureWorktree: vi.fn().mockResolvedValue(undefined), + checkoutBranch: vi.fn().mockResolvedValue(undefined), + resolveFilePath: vi.fn().mockImplementation(async (path: string) => path), + readFileWindow: vi.fn().mockImplementation(async (_path: string, finding: ReviewFinding) => ({ + imports: '', + snippet: `line ${finding.line}`, + snippetStartLine: finding.line, + snippetEndLine: finding.line, + totalLines: 30, + truncated: false, + targetLine: finding.line, + })), + }); + const state = mockOf({ + interactiveThreads: { + [discussion.id]: { + status: 'awaiting-reply', + askedAt, + question: '请确认业务意图', + filePath: 'src/a.ts', + }, + }, + processedDiscussions: {}, + maintainerThreadState: { + [discussion.id]: { + decisions: { + 'src/a.ts:10': { + action: 'ask', + reason: '需要人工确认', + question: '请确认业务意图', + failedAttempts: 0, + decidedAt: askedAt, + }, + 'src/b.ts:20': { + action: 'fix', + reason: '需要补充保护', + failedAttempts: 1, + fixSucceeded: false, + decidedAt: askedAt, + }, + }, + activeFindingKeys: ['src/a.ts:10', 'src/b.ts:20'], + lastReviewerNoteAt: askedAt - 60_000, + lastHumanNoteAt: 0, + }, + }, + }); + + await runner.processDiscussion( + mockMR, + discussion, + provider, + brain, + actor, + worktreeManager, + 'CodeKeeper Maintainer', + state, + '/project' + ); + + expect(actor.executeBatchFix).toHaveBeenCalledOnce(); + expect(actor.postSummary).toHaveBeenCalledOnce(); + expect(vi.mocked(actor.postSummary).mock.calls[0][2]).toEqual(['src/b.ts:20']); + expect(vi.mocked(actor.postSummary).mock.calls[0][4]).toEqual([]); + expect(state.interactiveThreads[discussion.id]).toMatchObject({ + status: 'awaiting-reply', + question: '请确认业务意图', + }); + }); + + it('按逐 finding 批量结果更新状态,暂缓项不累计失败次数', async () => { + const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); + const findings: ReviewFinding[] = [ + { + severity: 'LOW', + file: 'src/a.ts', + line: 10, + message: '检查已存在的保护', + suggestion: '确认当前实现', + }, + { + severity: 'MEDIUM', + file: 'src/b.ts', + line: 20, + message: '补充边界判断', + suggestion: '修正函数逻辑', + }, + { + severity: 'LOW', + file: 'src/c.ts', + line: 30, + message: '清理多余分支', + suggestion: '删除冗余代码', + }, + ]; + const discussion: Discussion = { + id: 'd-item-results', + resolvable: true, + resolved: false, + notes: [ + { + id: 1, + author: 'reviewer-agent', + body: '三个独立的检查项', + createdAt: '2026-08-03T00:00:00.000Z', + resolved: false, + }, + ], + }; + const brain = mockOf({ + parseFindings: vi.fn().mockResolvedValue(findings), + enrichFindingsWithCases: vi.fn().mockImplementation(async items => items), + decide: vi.fn().mockResolvedValue({ + action: 'fix', + reason: '可以自动处理', + fixDescription: '按 finding 修改目标文件', + scope: 'local', + }), + }); + const actor = mockOf({ + executeBatchFix: vi.fn().mockResolvedValue({ + success: false, + reason: '第二项修复失败', + appliedFiles: [], + deletedFiles: [], + alreadyFixedItems: [{ file: 'src/a.ts', line: 10, reason: '当前代码已有所需保护' }], + itemResults: [ + { + file: 'src/a.ts', + line: 10, + status: 'already-fixed', + reason: '当前代码已有所需保护', + }, + { file: 'src/b.ts', line: 20, status: 'failed', reason: '目标函数仍缺少保护' }, + { file: 'src/c.ts', line: 30, status: 'deferred', reason: '本轮尚未执行' }, + ], + }), + postSummary: vi.fn().mockResolvedValue({ + replyPosted: true, + resolved: false, + pending: false, + }), + }); + const provider = mockOf({ getMRDiff: vi.fn().mockResolvedValue([]) }); + const worktreeManager = mockOf({ + getWorktreePath: vi.fn().mockReturnValue('/worktree'), + ensureWorktree: vi.fn().mockResolvedValue(undefined), + checkoutBranch: vi.fn().mockResolvedValue(undefined), + resolveFilePath: vi.fn().mockImplementation(async (path: string) => path), + readFileWindow: vi.fn().mockImplementation(async (_path: string, finding: ReviewFinding) => ({ + imports: '', + snippet: `line ${finding.line}`, + snippetStartLine: finding.line, + snippetEndLine: finding.line, + totalLines: 40, + truncated: false, + targetLine: finding.line, + })), + }); + const state = mockOf({ interactiveThreads: {}, processedDiscussions: {} }); + + await runner.processDiscussion( + mockMR, + discussion, + provider, + brain, + actor, + worktreeManager, + 'CodeKeeper Maintainer', + state, + '/project' + ); + + const decisions = state.maintainerThreadState?.[discussion.id]?.decisions; + expect(decisions?.['src/a.ts:10']).toMatchObject({ + action: 'ignore', + alreadyFixed: true, + failedAttempts: 0, + }); + expect(decisions?.['src/b.ts:20']).toMatchObject({ + action: 'fix', + failedAttempts: 1, + lastFailureReason: '目标函数仍缺少保护', + }); + expect(decisions?.['src/c.ts:30']).toMatchObject({ + action: 'fix', + failedAttempts: 0, + }); + expect(vi.mocked(actor.postSummary).mock.calls[0][3]).toEqual([ + 'src/b.ts:20 — 目标函数仍缺少保护', + ]); + expect(vi.mocked(actor.postSummary).mock.calls[0][8]).toEqual(['src/c.ts:30 — 本轮尚未执行']); + }); + it('非 finding 讨论已有 Maintainer 回复但无处理记录时静默补记跳过', async () => { const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); @@ -1856,6 +2320,101 @@ describe('MaintainerRunner', () => { ); }); + it('首条 Reviewer note 编辑后即使仍为 fix 也会重新执行修复', async () => { + const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); + const previousActivityAt = Date.parse('2026-07-20T00:00:00.000Z'); + const finding: ReviewFinding = { + severity: 'MEDIUM', + file: 'virtual/module-b.ts', + line: 24, + message: '编辑后的修复要求', + suggestion: '按新要求调整实现', + }; + const discussion: Discussion = { + id: 'd-edited-fix', + resolvable: true, + resolved: false, + notes: [ + { + id: 31, + author: 'reviewer-bot', + body: `${finding.file}:${finding.line} | ${finding.message}`, + createdAt: '2026-07-20T00:00:00.000Z', + updatedAt: '2026-07-21T00:00:00.000Z', + resolved: false, + }, + ], + }; + const brain = mockOf({ + parseFindings: vi.fn().mockResolvedValue([finding]), + enrichFindingsWithCases: vi.fn().mockImplementation(async findings => findings), + decide: vi.fn().mockResolvedValue({ + action: 'fix', + reason: '需要按编辑后的要求继续修改', + fixDescription: '调整当前实现', + }), + }); + const actor = mockOf({ + applyDecision: vi.fn().mockResolvedValue({ + codeApplied: true, + replyPosted: true, + resolved: true, + awaitingReply: false, + pending: false, + }), + }); + const worktreeManager = mockOf({ + ensureWorktree: vi.fn().mockResolvedValue(undefined), + checkoutBranch: vi.fn().mockResolvedValue(undefined), + resolveFilePath: vi.fn().mockResolvedValue(finding.file), + getWorktreePath: vi.fn().mockReturnValue('/virtual-worktree'), + readFileWindow: vi.fn().mockResolvedValue({ + imports: '', + snippet: 'export const currentValue = true;', + snippetStartLine: 1, + snippetEndLine: 30, + totalLines: 30, + truncated: false, + targetLine: finding.line, + }), + }); + const state = mockOf({ + interactiveThreads: {}, + processedDiscussions: { + [discussion.id]: { noteCount: 1, processedAt: previousActivityAt }, + }, + maintainerThreadState: { + [discussion.id]: { + decisions: { + [`${finding.file}:${finding.line}`]: { + action: 'fix', + reason: '旧修复要求', + failedAttempts: 0, + fixSucceeded: true, + decidedAt: previousActivityAt, + }, + }, + lastReviewerNoteAt: previousActivityAt, + lastHumanNoteAt: 0, + }, + }, + }); + + await runner.processDiscussion( + mockMR, + discussion, + mockOf({ getMRDiff: vi.fn().mockResolvedValue([]) }), + brain, + actor, + worktreeManager, + 'CodeKeeper Maintainer', + state, + '/virtual-project' + ); + + expect(actor.applyDecision).toHaveBeenCalledOnce(); + }); + it('非 finding 首条 note 被编辑后不被已有 Maintainer 回复静默吞掉', async () => { const runner = new MaintainerRunner({ llmClient: makeLlmClient() }); const previousActivityAt = Date.parse('2026-07-20T00:00:00.000Z'); @@ -2327,7 +2886,8 @@ describe('MaintainerRunner', () => { { fileLine: 'src/index.ts:2', reason: '后续提交已满足原 finding' }, { fileLine: 'src/other.ts:4', reason: '后续提交已满足原 finding' }, ], - state + state, + [] ); expect(state.maintainerThreadState?.['d-stale-recheck']?.decisions).toMatchObject({ 'src/index.ts:2': { action: 'ignore', alreadyFixed: true }, @@ -2783,4 +3343,193 @@ describe('classifyBatchFixItems', () => { expect(fixedItems).toEqual([]); expect(failedItems[0]).toContain('src/dead.ts:1'); }); + + it('优先使用逐 finding 结果,不把一个失败原因复制给暂缓项', () => { + const { fixedItems, failedItems, deferredItems } = classifyBatchFixItems( + [ + { file: 'src/a.ts', line: 1 }, + { file: 'src/b.ts', line: 2 }, + { file: 'src/c.ts', line: 3 }, + ], + { + success: false, + reason: '批量修复未完成', + appliedFiles: ['src/a.ts'], + deletedFiles: [], + itemResults: [ + { file: 'src/a.ts', line: 1, status: 'deferred', reason: '事务尚未提交' }, + { file: 'src/b.ts', line: 2, status: 'failed', reason: '目标函数仍缺少保护' }, + { file: 'src/c.ts', line: 3, status: 'deferred', reason: '本轮尚未执行' }, + ], + } + ); + + expect(fixedItems).toEqual([]); + expect(failedItems).toEqual(['src/b.ts:2 — 目标函数仍缺少保护']); + expect(deferredItems).toEqual(['src/a.ts:1 — 事务尚未提交', 'src/c.ts:3 — 本轮尚未执行']); + }); +}); + +describe('legacy maintainer state repair', () => { + it('回复已发布但 resolve 未完成时,源评论更新会淘汰旧投递', () => { + const generatedAt = Date.parse('2026-08-03T06:00:00.000Z'); + const threadState: MaintainerThreadState = { + decisions: {}, + lastReviewerNoteAt: generatedAt - 60_000, + delivery: { + replyBody: '旧结论', + replyHash: 'old', + replyStatus: 'posted', + replyNoteId: 2, + resolveRequired: true, + resolveStatus: 'failed', + attempts: 1, + createdAt: generatedAt, + updatedAt: generatedAt, + }, + }; + + const reason = getDiscussionDeliveryInvalidationReason({ + discussion: { + id: 'd-updated-before-resolve', + resolvable: true, + resolved: false, + notes: [ + { + id: 1, + author: 'reviewer-agent', + body: 'src/a.ts:1 更新后的问题', + createdAt: new Date(generatedAt - 60_000).toISOString(), + updatedAt: new Date(generatedAt + 60_000).toISOString(), + resolved: false, + }, + { + id: 2, + author: 'maintainer', + body: '旧结论', + createdAt: new Date(generatedAt).toISOString(), + resolved: false, + }, + ], + }, + threadState, + now: generatedAt + 120_000, + }); + + expect(reason).toContain('源评论'); + }); + + it('按首次生成时间淘汰跨日重试的陈旧超长投递', () => { + const generatedAt = Date.parse('2026-07-28T06:00:00.000Z'); + const retriedAt = Date.parse('2026-08-03T06:00:00.000Z'); + const threadState: MaintainerThreadState = { + decisions: {}, + lastReviewerNoteAt: 0, + lastSummaryAt: generatedAt, + delivery: { + replyBody: `\u001b[31m失败\u001b[0m\n${'x'.repeat(430_000)}`, + replyHash: 'legacy', + replyStatus: 'failed', + resolveRequired: false, + resolveStatus: 'not-required', + attempts: 3, + updatedAt: retriedAt, + }, + }; + + const repaired = repairLegacyMaintainerThreadState(threadState, retriedAt); + const reason = getDiscussionDeliveryInvalidationReason({ + discussion: { + id: 'd-stale-delivery', + resolvable: true, + resolved: false, + notes: [ + { + id: 1, + author: 'reviewer-agent', + body: 'src/a.ts:1 需要检查边界条件', + createdAt: '2026-07-28T05:00:00.000Z', + resolved: false, + }, + ], + }, + threadState, + now: retriedAt, + }); + + expect(repaired.changed).toBe(true); + expect(threadState.delivery?.createdAt).toBe(generatedAt); + expect(threadState.delivery?.replyBody.length).toBeLessThanOrEqual(16_000); + expect(threadState.delivery?.replyBody).not.toContain('\u001b['); + expect(reason).toContain('超过两小时'); + }); + + it('把历史仓库自查型 ask 回流为 fix', () => { + const threadState: MaintainerThreadState = { + decisions: { + 'src/a.ts:8': { + action: 'ask', + reason: '需要读取实现', + question: '请提供 src/a.ts 文件的完整内容,以便判断当前实现。', + failedAttempts: 2, + decidedAt: 1, + }, + }, + lastReviewerNoteAt: 0, + }; + + const repaired = repairLegacyMaintainerThreadState(threadState, 100); + + expect(repaired.repairedSelfAnswerableAsk).toBe(true); + expect(threadState.decisions['src/a.ts:8']).toMatchObject({ + action: 'fix', + failedAttempts: 0, + }); + expect(threadState.decisions['src/a.ts:8'].question).toBeUndefined(); + }); + + it('把未耗尽重试次数的历史修复失败求助回流为自动重试', () => { + const question = + '我尝试自动修复 src/a.ts:8,但未成功。请 Reviewer 补充期望的修改方式或范围,我会再试一次。'; + const threadState: MaintainerThreadState = { + decisions: { + 'src/a.ts:8': { + action: 'fix', + reason: '需要修复', + question, + failedAttempts: 1, + fixSucceeded: false, + lastFailureReason: '首次修复未完成', + decidedAt: 1, + }, + }, + lastReviewerNoteAt: 0, + repairVersion: 1, + delivery: { + replyBody: question, + replyHash: 'legacy', + replyStatus: 'posted', + resolveRequired: false, + resolveStatus: 'not-required', + attempts: 1, + awaitingReply: true, + awaitingReplyAt: 1, + question, + filePath: 'src/a.ts', + updatedAt: 1, + }, + }; + + const repaired = repairLegacyMaintainerThreadState(threadState, 100); + + expect(repaired.repairedPrematureFixAsk).toBe(true); + expect(threadState.decisions['src/a.ts:8']).toMatchObject({ + action: 'fix', + failedAttempts: 1, + fixSucceeded: false, + }); + expect(threadState.decisions['src/a.ts:8'].question).toBeUndefined(); + expect(threadState.delivery?.awaitingReply).toBe(false); + expect(threadState.repairVersion).toBe(2); + }); }); diff --git a/tests/advance/classic/runners/shared/discussion-delivery.test.ts b/tests/advance/classic/runners/shared/discussion-delivery.test.ts index 3378abd..7eb4906 100755 --- a/tests/advance/classic/runners/shared/discussion-delivery.test.ts +++ b/tests/advance/classic/runners/shared/discussion-delivery.test.ts @@ -3,8 +3,13 @@ import { deliverDiscussionReply, isDiscussionDeliveryPending, } from '../../../../../src/advance/classic/runners/shared/discussion-delivery.js'; -import type { Discussion, IGitProvider, MergeRequest } from '../../../../../src/advance/classic/provider/types.js'; +import type { + Discussion, + IGitProvider, + MergeRequest, +} from '../../../../../src/advance/classic/provider/types.js'; import type { DiscussionDeliveryState } from '../../../../../src/advance/classic/runners/shared/state-utils.js'; +import { MAX_DISCUSSION_REPLY_CHARS } from '../../../../../src/advance/classic/runners/shared/reply-safety.js'; const mr: MergeRequest = { iid: 17, @@ -210,6 +215,75 @@ describe('deliverDiscussionReply', () => { expect(provider.addDiscussionNote).not.toHaveBeenCalled(); expect(provider.resolveDiscussion).not.toHaveBeenCalled(); }); + + it('发布前移除 ANSI 并压缩超长回复正文', async () => { + const provider = { + addDiscussionNote: vi.fn().mockResolvedValue(21), + resolveDiscussion: vi.fn().mockResolvedValue(undefined), + } as unknown as IGitProvider; + const discussion = makeDiscussion(); + let delivery: DiscussionDeliveryState | undefined; + const oversizedBody = `\u001b[31m错误\u001b[0m\n${'x'.repeat(430_000)}\n\n---\n*生成于 2026/08/03 12:00:00 · CodeKeeper Maintainer*`; + + await deliverDiscussionReply({ + provider, + mr, + discussion, + body: oversizedBody, + resolve: false, + delivery, + setDelivery: next => { + delivery = next; + }, + checkpoint: () => undefined, + }); + + const postedBody = vi.mocked(provider.addDiscussionNote).mock.calls[0][2]; + expect(postedBody.length).toBeLessThanOrEqual(MAX_DISCUSSION_REPLY_CHARS); + expect(postedBody).not.toContain('\u001b['); + expect(postedBody).toContain('诊断内容过长'); + expect(delivery?.replyBody).toBe(postedBody); + }); + + it('进度回复正文变化时保留首次提问时间', async () => { + const provider = { + addDiscussionNote: vi.fn().mockResolvedValueOnce(31).mockResolvedValueOnce(32), + resolveDiscussion: vi.fn().mockResolvedValue(undefined), + } as unknown as IGitProvider; + const discussion = makeDiscussion(); + let delivery: DiscussionDeliveryState | undefined; + const askedAt = Date.now() - 60_000; + + await deliverDiscussionReply({ + provider, + mr, + discussion, + body: '首次提问。', + resolve: false, + awaitingReply: { question: '请确认预期行为', filePath: 'src/example.ts', askedAt }, + delivery, + setDelivery: next => { + delivery = next; + }, + checkpoint: () => undefined, + }); + + await deliverDiscussionReply({ + provider, + mr, + discussion, + body: '仍在等待确认,同时继续处理其他 finding。', + resolve: false, + awaitingReply: { question: '请确认预期行为', filePath: 'src/example.ts', askedAt }, + delivery, + setDelivery: next => { + delivery = next; + }, + checkpoint: () => undefined, + }); + + expect(delivery?.awaitingReplyAt).toBe(askedAt); + }); }); describe('isDiscussionDeliveryPending', () => { diff --git a/tests/advance/classic/runners/shared/maintainer-filter.test.ts b/tests/advance/classic/runners/shared/maintainer-filter.test.ts index 3c833d9..01dda2a 100755 --- a/tests/advance/classic/runners/shared/maintainer-filter.test.ts +++ b/tests/advance/classic/runners/shared/maintainer-filter.test.ts @@ -3,9 +3,15 @@ */ import { describe, it, expect } from 'vitest'; -import { isDiscussionPending } from '../../../../../src/advance/classic/runners/shared/maintainer-filter.js'; +import { + isDiscussionPending, + isJudgmentFlipped, +} from '../../../../../src/advance/classic/runners/shared/maintainer-filter.js'; import type { Discussion } from '../../../../../src/advance/classic/provider/types.js'; -import type { MrAgentState } from '../../../../../src/advance/classic/runners/shared/state-utils.js'; +import type { + MrAgentState, + MaintainerFindingDecision, +} from '../../../../../src/advance/classic/runners/shared/state-utils.js'; function makeDiscussion(overrides: Partial = {}): Discussion { return { @@ -155,6 +161,58 @@ describe('isDiscussionPending', () => { expect(isDiscussionPending(d, state)).toBe(false); }); + it('交互式等待不会阻塞同 discussion 内仍可重试的 fix', () => { + const now = Date.now(); + const d = makeDiscussion({ + notes: [ + { + author: 'reviewer-agent', + body: 'src/a.ts:10 需要确认,src/b.ts:20 仍需修复', + createdAt: new Date(now - 60_000).toISOString(), + }, + { + author: 'maintainer', + body: '请确认业务意图\n\n---\n*生成于 2026/08/03 10:00:00 · CodeKeeper Advance MR 维护 Agent · bot*', + createdAt: new Date(now - 30_000).toISOString(), + }, + ], + }); + const state = makeState({ + interactiveThreads: { + 'd-1': { + status: 'awaiting-reply', + askedAt: now - 30_000, + question: '请确认业务意图', + filePath: 'src/a.ts', + }, + }, + processedDiscussions: { 'd-1': { noteCount: 2, processedAt: now - 30_000 } }, + maintainerThreadState: { + 'd-1': { + decisions: { + 'src/a.ts:10': { + action: 'ask', + reason: '需要人工确认', + failedAttempts: 0, + decidedAt: now - 30_000, + }, + 'src/b.ts:20': { + action: 'fix', + reason: '需要继续修复', + failedAttempts: 1, + fixSucceeded: false, + decidedAt: now - 30_000, + }, + }, + activeFindingKeys: ['src/a.ts:10', 'src/b.ts:20'], + lastReviewerNoteAt: now - 60_000, + }, + }, + }); + + expect(isDiscussionPending(d, state)).toBe(true); + }); + it('交互式等待中出现新人工回复时进入流程', () => { const now = Date.now(); const d = makeDiscussion({ @@ -212,6 +270,37 @@ describe('isDiscussionPending', () => { expect(isDiscussionPending(d, state)).toBe(true); }); + it('提问被删除后不能用无关进度回复维持等待状态', () => { + const now = Date.now(); + const d = makeDiscussion({ + notes: [ + { + author: 'human', + body: '这里为什么要这么改?', + createdAt: new Date(now - 60_000).toISOString(), + }, + { + author: 'maintainer', + body: '⏭️ 其他 finding 将在下一轮继续处理\n\n---\n*生成于 2026/08/03 10:00:00 · CodeKeeper Advance MR 维护 Agent · bot*', + createdAt: new Date(now - 10_000).toISOString(), + }, + ], + }); + const state = makeState({ + interactiveThreads: { + 'd-1': { + status: 'awaiting-reply', + askedAt: now - 30_000, + question: '请确认预期行为', + filePath: 'src/a.ts', + }, + }, + processedDiscussions: { 'd-1': { noteCount: 2, processedAt: now - 10_000 } }, + }); + + expect(isDiscussionPending(d, state)).toBe(true); + }); + it('交互式等待超时后进入流程以便收尾', () => { const d = makeDiscussion(); const state = makeState({ @@ -613,4 +702,188 @@ describe('isDiscussionPending', () => { expect(isDiscussionPending(d, state)).toBe(false); }); + + it('resolved 的 discussion 不因缺少无需修复说明而复活补发', () => { + // F1:人类已 resolve 的 thread 已闭环,「补发说明」不足以复活它制造噪音评论 + const d = makeDiscussion({ + resolved: true, + notes: [ + { + author: 'reviewer', + body: 'src/a.ts:1 与 src/b.ts:2 都有问题', + createdAt: '2026-01-01T00:00:00Z', + }, + ], + }); + const state = makeState({ + maintainerThreadState: { + 'd-1': { + decisions: { + 'src/a.ts:1': { + action: 'ignore', + alreadyFixed: true, + reason: '已修复', + failedAttempts: 0, + decidedAt: 1, + }, + 'src/b.ts:2': { action: 'ignore', reason: '无需修改', failedAttempts: 0, decidedAt: 1 }, + }, + lastReviewerNoteAt: 0, + }, + }, + }); + expect(isDiscussionPending(d, state)).toBe(false); + }); + + it('未 resolved 且缺少无需修复说明时仍进入流程补发', () => { + // 与上一用例对照:未 resolved 时补发逻辑保持原有行为 + const d = makeDiscussion({ + notes: [ + { + author: 'reviewer', + body: 'src/a.ts:1 与 src/b.ts:2 都有问题', + createdAt: '2026-01-01T00:00:00Z', + }, + ], + }); + const state = makeState({ + maintainerThreadState: { + 'd-1': { + decisions: { + 'src/a.ts:1': { + action: 'ignore', + alreadyFixed: true, + reason: '已修复', + failedAttempts: 0, + decidedAt: 1, + }, + 'src/b.ts:2': { action: 'ignore', reason: '无需修改', failedAttempts: 0, decidedAt: 1 }, + }, + lastReviewerNoteAt: 0, + }, + }, + }); + expect(isDiscussionPending(d, state)).toBe(true); + }); + + it('无需修复说明补发过一次后熔断,不因行号漂移反复补发', () => { + // F4:补发过一次后,远端说明逐条 file:line 匹配仍失败(行号漂移)也不再重复补发 + const backfilledAt = Date.parse('2026-01-03T00:00:00Z'); + const d = makeDiscussion({ + notes: [ + { + author: 'reviewer', + body: 'src/a.ts:1 与 src/b.ts:2 都有问题', + createdAt: '2026-01-01T00:00:00Z', + }, + { + author: 'maintainer', + // 说明中只提到 src/a.ts:1(src/b.ts:2 因行号漂移匹配不上) + body: '✅ 已修复(无需重复修改):\n- src/a.ts:1: 已满足要求\n\n---\n*生成于 2026/01/03 · CodeKeeper Advance MR 维护 Agent · bot*', + createdAt: '2026-01-03T00:00:00Z', + }, + ], + }); + const state = makeState({ + maintainerThreadState: { + 'd-1': { + decisions: { + 'src/a.ts:1': { + action: 'ignore', + alreadyFixed: true, + reason: '已修复', + failedAttempts: 0, + decidedAt: 1, + }, + 'src/b.ts:2': { action: 'ignore', reason: '无需修改', failedAttempts: 0, decidedAt: 1 }, + }, + lastReviewerNoteAt: 0, + noFixExplanationBackfilledAt: backfilledAt, + }, + }, + }); + expect(isDiscussionPending(d, state)).toBe(false); + }); + + it('补发熔断后出现新人工回复时解除熔断重新进入流程', () => { + const backfilledAt = Date.parse('2026-01-03T00:00:00Z'); + const d = makeDiscussion({ + notes: [ + { + author: 'reviewer', + body: 'src/a.ts:1 与 src/b.ts:2 都有问题', + createdAt: '2026-01-01T00:00:00Z', + }, + { + author: 'maintainer', + body: '✅ 已修复(无需重复修改):\n- src/a.ts:1: 已满足要求\n\n---\n*生成于 2026/01/03 · CodeKeeper Advance MR 维护 Agent · bot*', + createdAt: '2026-01-03T00:00:00Z', + }, + { + author: 'reviewer', + body: 'src/b.ts:2 的说明在哪里?', + createdAt: '2026-01-04T00:00:00Z', + }, + ], + }); + const state = makeState({ + maintainerThreadState: { + 'd-1': { + decisions: { + 'src/a.ts:1': { + action: 'ignore', + alreadyFixed: true, + reason: '已修复', + failedAttempts: 0, + decidedAt: 1, + }, + 'src/b.ts:2': { action: 'ignore', reason: '无需修改', failedAttempts: 0, decidedAt: 1 }, + }, + lastReviewerNoteAt: 0, + noFixExplanationBackfilledAt: backfilledAt, + }, + }, + }); + expect(isDiscussionPending(d, state)).toBe(true); + }); +}); + +describe('isJudgmentFlipped(M7 推翻判定)', () => { + const ignoreDecision: MaintainerFindingDecision = { + action: 'ignore', + reason: '此前判断无需修复', + failedAttempts: 0, + decidedAt: 1, + }; + + it('ignore + 新人工回复 + 新决策 fix → 判定为推翻', () => { + expect(isJudgmentFlipped(ignoreDecision, true, 'fix')).toBe(true); + }); + + it('alreadyFixed 的 ignore 被推翻同样成立', () => { + expect(isJudgmentFlipped({ ...ignoreDecision, alreadyFixed: true }, true, 'fix')).toBe(true); + }); + + it('无新人工回复不判定为推翻(Agent 自动重扫不带新信息)', () => { + expect(isJudgmentFlipped(ignoreDecision, false, 'fix')).toBe(false); + }); + + it('此前是 fix 决策不算推翻', () => { + const fixDecision: MaintainerFindingDecision = { + action: 'fix', + reason: '此前修复失败', + failedAttempts: 1, + decidedAt: 1, + }; + expect(isJudgmentFlipped(fixDecision, true, 'fix')).toBe(false); + }); + + it('新决策仍是 ignore/ask 不算推翻', () => { + expect(isJudgmentFlipped(ignoreDecision, true, 'ignore')).toBe(false); + expect(isJudgmentFlipped(ignoreDecision, true, 'ask')).toBe(false); + }); + + it('无历史决策不算推翻', () => { + expect(isJudgmentFlipped(undefined, true, 'fix')).toBe(false); + }); }); diff --git a/tests/advance/classic/runners/shared/mr-lifecycle.test.ts b/tests/advance/classic/runners/shared/mr-lifecycle.test.ts new file mode 100644 index 0000000..204264a --- /dev/null +++ b/tests/advance/classic/runners/shared/mr-lifecycle.test.ts @@ -0,0 +1,281 @@ +import { describe, it, expect } from 'vitest'; +import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { + archiveLifecycleRecord, + buildMrLifecycleKey, + classifyCiFailure, + collectInterruptCandidates, + computeClosureStats, + createLifecycleState, + detectInterruptCommand, + extractFileCandidatesFromTrace, + hashFailedJobs, + isMrConverged, + MAX_CI_FIX_ATTEMPTS_PER_HEAD, + type MrLifecycleArchiveRecord, +} from '../../../../../src/advance/classic/runners/shared/mr-lifecycle.js'; +import type { Discussion } from '../../../../../src/advance/classic/provider/types.js'; + +const alwaysHuman = () => true; +const agentIsNotHuman = (author: string) => author !== 'codekeeper-bot'; + +function makeDiscussion(overrides: Partial): Discussion { + return { + id: 'd-1', + resolvable: true, + resolved: false, + notes: [], + ...overrides, + }; +} + +describe('buildMrLifecycleKey', () => { + it('按 MR iid 生成稳定 key', () => { + expect(buildMrLifecycleKey(42)).toBe('mr:42'); + }); +}); + +describe('createLifecycleState', () => { + it('初始化 active 状态与零值指标', () => { + const lifecycle = createLifecycleState({ + iid: 7, + title: 'feat: x', + sourceBranch: 'feat/x', + targetBranch: 'main', + webUrl: 'https://gitlab.example.com/mr/7', + }); + expect(lifecycle.status).toBe('active'); + expect(lifecycle.pollCount).toBe(0); + expect(lifecycle.metrics.findingsFixed).toBe(0); + expect(lifecycle.metrics.humanFollowupsAfterFix).toBe(0); + }); +}); + +describe('detectInterruptCommand', () => { + const cases: Array<[string, string]> = [ + ['/ck stop', '斜杠命令'], + ['/codekeeper stop', 'codekeeper 命令'], + ['/maintainer pause', 'maintainer 命令'], + ['@codekeeper stop 先别改了', 'mention 停止'], + ['请停止自动修复这个 MR', '中文停止修复'], + ['暂停自动维护', '中文暂停维护'], + ['不要再自动提交了', '中文禁止提交'], + ]; + + it.each(cases)('识别人工中断指令:%s(%s)', body => { + const interrupt = detectInterruptCommand( + [{ author: 'dev', body, createdAt: '2026-07-29T10:00:00Z' }], + alwaysHuman + ); + expect(interrupt).toBeDefined(); + expect(interrupt?.by).toBe('dev'); + }); + + it('忽略普通讨论内容', () => { + const interrupt = detectInterruptCommand( + [ + { author: 'dev', body: '这个函数先别改,我想想', createdAt: '2026-07-29T10:00:00Z' }, + { author: 'dev', body: '修复方案没问题', createdAt: '2026-07-29T10:01:00Z' }, + ], + alwaysHuman + ); + expect(interrupt).toBeUndefined(); + }); + + it('忽略 Agent/bot 发布的停止指令', () => { + const interrupt = detectInterruptCommand( + [{ author: 'codekeeper-bot', body: '/ck stop', createdAt: '2026-07-29T10:00:00Z' }], + agentIsNotHuman + ); + expect(interrupt).toBeUndefined(); + }); + + it('多条命中时取最新一条', () => { + const interrupt = detectInterruptCommand( + [ + { author: 'dev', body: '/ck stop', createdAt: '2026-07-29T10:00:00Z' }, + { author: 'lead', body: '停止自动修复', createdAt: '2026-07-29T12:00:00Z' }, + ], + alwaysHuman + ); + expect(interrupt?.by).toBe('lead'); + }); +}); + +describe('computeClosureStats', () => { + it('统计 resolvable discussion 的闭环率', () => { + const stats = computeClosureStats([ + makeDiscussion({ id: 'a', resolved: true }), + makeDiscussion({ id: 'b', resolved: false }), + makeDiscussion({ id: 'c', resolved: true }), + ]); + expect(stats.total).toBe(3); + expect(stats.resolved).toBe(2); + expect(stats.closureRate).toBeCloseTo(2 / 3); + }); + + it('忽略非 resolvable discussion', () => { + const stats = computeClosureStats([ + makeDiscussion({ id: 'a', resolvable: false, resolved: false }), + ]); + expect(stats.total).toBe(0); + expect(stats.closureRate).toBe(1); + }); +}); + +describe('isMrConverged', () => { + const closure = { total: 2, resolved: 2, closureRate: 1 }; + + it('全部闭环且 CI 正常时判定收敛', () => { + expect(isMrConverged({ pendingDiscussionCount: 0, closure, ciStatus: 'success' })).toBe(true); + }); + + it('存在待处理 discussion 时不收敛', () => { + expect(isMrConverged({ pendingDiscussionCount: 1, closure, ciStatus: 'success' })).toBe(false); + }); + + it('存在未 resolve discussion 时不收敛', () => { + expect( + isMrConverged({ + pendingDiscussionCount: 0, + closure: { total: 2, resolved: 1, closureRate: 0.5 }, + ciStatus: 'success', + }) + ).toBe(false); + }); + + it('CI 失败或 CI 修复挂起时不收敛', () => { + expect(isMrConverged({ pendingDiscussionCount: 0, closure, ciStatus: 'failed' })).toBe(false); + expect( + isMrConverged({ pendingDiscussionCount: 0, closure, ciStatus: 'success', ciSuspended: true }) + ).toBe(false); + }); +}); + +describe('classifyCiFailure', () => { + it('script_failure 归类为代码问题(修)', () => { + expect(classifyCiFailure({ failureReason: 'script_failure', traceTail: '' })).toBe('code'); + }); + + it('runner/超时类失败归类为基础设施问题(挂起)', () => { + expect(classifyCiFailure({ failureReason: 'runner_system_failure', traceTail: '' })).toBe( + 'infra' + ); + expect(classifyCiFailure({ failureReason: 'stuck_or_timeout_failure', traceTail: '' })).toBe( + 'infra' + ); + }); + + it('无失败原因时按日志内容兜底判断', () => { + expect( + classifyCiFailure({ failureReason: undefined, traceTail: 'ERROR: no runner available' }) + ).toBe('infra'); + expect(classifyCiFailure({ failureReason: undefined, traceTail: 'jest: 2 tests failed' })).toBe( + 'unknown' + ); + }); +}); + +describe('hashFailedJobs', () => { + it('同批 job 哈希稳定且与顺序无关', () => { + const first = hashFailedJobs([ + { name: 'lint', stage: 'test' }, + { name: 'build', stage: 'build' }, + ]); + const second = hashFailedJobs([ + { name: 'build', stage: 'build' }, + { name: 'lint', stage: 'test' }, + ]); + expect(first).toBe(second); + }); + + it('job 集合变化时哈希变化', () => { + const first = hashFailedJobs([{ name: 'lint', stage: 'test' }]); + const second = hashFailedJobs([{ name: 'unit-test', stage: 'test' }]); + expect(first).not.toBe(second); + }); +}); + +describe('extractFileCandidatesFromTrace', () => { + it('从日志中提取仓库相对路径候选', () => { + const trace = [ + 'FAIL src/utils/parser.test.ts', + ' at Object. (src/utils/parser.ts:42:11)', + 'error TS2304 in packages/core/src/index.ts:7', + ].join('\n'); + const candidates = extractFileCandidatesFromTrace(trace); + expect(candidates).toContain('src/utils/parser.test.ts'); + expect(candidates).toContain('src/utils/parser.ts'); + expect(candidates).toContain('packages/core/src/index.ts'); + }); + + it('排除 node_modules 与 URL,且去重、限量', () => { + const trace = [ + 'at node_modules/react/index.js:1:1', + 'see https://example.com/docs/a.ts', + 'src/a.ts:1 src/a.ts:2 src/b.ts:3 src/c.ts:4 src/d.ts:5 src/e.ts:6', + ].join('\n'); + const candidates = extractFileCandidatesFromTrace(trace, 5); + expect(candidates.some(c => c.includes('node_modules'))).toBe(false); + expect(candidates.some(c => c.startsWith('http'))).toBe(false); + expect(candidates.length).toBeLessThanOrEqual(5); + expect(new Set(candidates).size).toBe(candidates.length); + }); +}); + +describe('collectInterruptCandidates', () => { + it('合并 MR 级评论与 discussion note', () => { + const candidates = collectInterruptCandidates( + [{ id: 1, author: 'dev', body: 'a', createdAt: '2026-07-29T00:00:00Z' }], + [ + makeDiscussion({ + id: 'd-1', + notes: [ + { id: 2, author: 'dev', body: 'b', createdAt: '2026-07-29T01:00:00Z' }, + { id: 3, author: 'dev', body: 'c', createdAt: '2026-07-29T02:00:00Z' }, + ], + }), + ] + ); + expect(candidates.map(c => c.body)).toEqual(['a', 'b', 'c']); + }); +}); + +describe('archiveLifecycleRecord', () => { + it('将生命周期记录写入归档目录并可读回', () => { + const dir = mkdtempSync(join(tmpdir(), 'ck-lifecycle-')); + try { + const lifecycle = createLifecycleState({ + iid: 9, + title: 'fix: y', + sourceBranch: 'fix/y', + targetBranch: 'main', + }); + lifecycle.status = 'archived'; + lifecycle.endReason = 'merged'; + lifecycle.metrics.discussionsTotal = 10; + lifecycle.metrics.discussionsResolved = 10; + + const closure = { total: 10, resolved: 10, closureRate: 1 }; + const filePath = archiveLifecycleRecord(dir, 'project-x', lifecycle, closure); + + expect(existsSync(filePath)).toBe(true); + const record = JSON.parse(readFileSync(filePath, 'utf-8')) as MrLifecycleArchiveRecord; + expect(record.version).toBe(1); + expect(record.projectId).toBe('project-x'); + expect(record.lifecycle.mrIid).toBe(9); + expect(record.lifecycle.endReason).toBe('merged'); + expect(record.closure.closureRate).toBe(1); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); + +describe('CI 修复配额', () => { + it('单 head 最大修复尝试次数为 2', () => { + expect(MAX_CI_FIX_ATTEMPTS_PER_HEAD).toBe(2); + }); +}); diff --git a/tests/advance/classic/runners/shared/reply-safety.test.ts b/tests/advance/classic/runners/shared/reply-safety.test.ts new file mode 100644 index 0000000..a7f9ade --- /dev/null +++ b/tests/advance/classic/runners/shared/reply-safety.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; +import { + compactDiscussionReason, + stripTerminalControlCodes, +} from '../../../../../src/advance/classic/runners/shared/reply-safety.js'; + +describe('reply safety', () => { + it('压缩长日志时保留中部真正的 TypeScript 诊断', () => { + const reason = [ + 'Worktree compile:packages 失败: Command failed', + 'npm error code 2', + ...Array.from({ length: 30 }, (_, index) => `构建步骤 ${index} 已完成`), + 'src/module.ts(12,15): error TS2305: Module has no exported member.', + ...Array.from({ length: 20 }, (_, index) => `后续构建步骤 ${index}`), + 'npm error command failed', + ].join('\n'); + + const compacted = compactDiscussionReason(reason); + + expect(compacted).toContain('error TS2305'); + expect(compacted).toContain('已省略'); + expect(compacted).not.toContain('构建步骤 15 已完成'); + }); + + it('移除终端控制字符', () => { + expect(stripTerminalControlCodes('\u001b[31m失败\u001b[0m\0')).toBe('失败'); + }); +}); diff --git a/tests/advance/classic/runners/shared/state-utils.test.ts b/tests/advance/classic/runners/shared/state-utils.test.ts index 828c84a..9fc2975 100755 --- a/tests/advance/classic/runners/shared/state-utils.test.ts +++ b/tests/advance/classic/runners/shared/state-utils.test.ts @@ -134,6 +134,40 @@ describe('state-utils 角色隔离保存', () => { expect(JSON.parse(readFileSync(`${path}.bak`, 'utf-8')).discussions).toEqual({}); }); + it('Maintainer 保存时持久化 MR 生命周期记录且不覆盖其他角色状态', () => { + const project = makeProject(); + const maintainerState = loadState(project); + maintainerState.mrLifecycle = { + 'mr:7': { + mrIid: 7, + title: 'feat: x', + sourceBranch: 'feat/x', + targetBranch: 'main', + status: 'active', + startedAt: 1, + lastPolledAt: 2, + pollCount: 3, + metrics: { + discussionsTotal: 4, + discussionsResolved: 2, + findingsFixed: 1, + findingsRejected: 1, + findingsSuspended: 0, + fixPushes: 1, + humanFollowupsAfterFix: 0, + }, + }, + }; + saveState(project, maintainerState, 'maintainer'); + + // 其他角色保存后生命周期记录仍然保留 + saveState(project, loadState(project), 'reviewer'); + + const restored = loadState(project); + expect(restored.mrLifecycle?.['mr:7']?.pollCount).toBe(3); + expect(restored.mrLifecycle?.['mr:7']?.metrics.discussionsResolved).toBe(2); + }); + it('中文归档路径上的陈旧锁可被回收且保存后正常释放', () => { const project = makeProject('状态归档'); const path = getStatePath(project); diff --git a/tests/advance/classic/worktree-manager.test.ts b/tests/advance/classic/worktree-manager.test.ts index d8aa1ca..0cc846a 100755 --- a/tests/advance/classic/worktree-manager.test.ts +++ b/tests/advance/classic/worktree-manager.test.ts @@ -2,7 +2,10 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { mkdtempSync, rmSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; -import { WorktreeManager, WorktreeError } from '../../../src/advance/classic/worktree/worktree-manager'; +import { + WorktreeManager, + WorktreeError, +} from '../../../src/advance/classic/worktree/worktree-manager'; const mockClone = vi.fn(); const mockFetch = vi.fn(); @@ -51,6 +54,7 @@ describe('WorktreeManager', () => { remoteUrl = 'https://git.example.com/group/project.git'; vi.clearAllMocks(); mockGetConfig.mockResolvedValue({ value: '' }); + mockStatus.mockResolvedValue({ files: [] }); }); afterEach(() => { @@ -75,11 +79,10 @@ describe('WorktreeManager', () => { await manager.ensureWorktree(); expect(mockClone).toHaveBeenCalledOnce(); - expect(mockClone).toHaveBeenCalledWith( - remoteUrl, - manager.getWorktreePath(), - ['--origin', 'origin'] - ); + expect(mockClone).toHaveBeenCalledWith(remoteUrl, manager.getWorktreePath(), [ + '--origin', + 'origin', + ]); }); it('ensureWorktree 已存在时应 fetch 更新', async () => { @@ -303,6 +306,45 @@ describe('WorktreeManager', () => { expect(runScript).toHaveBeenCalledWith('compile:packages', manager.getWorktreePath()); }); + it('prepareEnvironment 修复模式应保留基线编译失败并继续', async () => { + mkdirSync(join(tmp, '.codekeeper-worktree', 'p1'), { recursive: true }); + writeFileSync( + join(tmp, '.codekeeper-worktree', 'p1', 'package.json'), + JSON.stringify({ scripts: { 'compile:packages': 'npm run build' } }) + ); + const install = vi.fn().mockResolvedValue({ success: true }); + const runScript = vi.fn().mockResolvedValue({ + success: false, + reason: 'src/module.ts(12,3): error TS2305: missing export', + }); + const manager = new WorktreeManager({ + projectId: 'p1', + rootPath, + remoteUrl, + install, + runScript, + }); + + const result = await manager.prepareEnvironment({ allowCompileFailure: true }); + + expect(result.compilePackagesFailure).toContain('error TS2305'); + }); + + it('listChangedFiles 应返回 git status 中的权威变更', async () => { + mockStatus.mockResolvedValue({ + files: [ + { path: 'src/a.ts', index: 'M', working_dir: ' ' }, + { path: 'virtual/module-b.ts', index: 'D', working_dir: ' ' }, + ], + }); + const manager = new WorktreeManager({ projectId: 'p1', rootPath, remoteUrl }); + + await expect(manager.listChangedFiles()).resolves.toEqual([ + { path: 'src/a.ts', deleted: false }, + { path: 'virtual/module-b.ts', deleted: true }, + ]); + }); + it('runScript 应透传 args 参数', async () => { mkdirSync(join(tmp, '.codekeeper-worktree', 'p1'), { recursive: true }); const runScript = vi.fn().mockResolvedValue({ success: true }); @@ -315,6 +357,8 @@ describe('WorktreeManager', () => { await manager.runScript('test', ['packages/foo/src/bar.test.ts']); - expect(runScript).toHaveBeenCalledWith('test', manager.getWorktreePath(), ['packages/foo/src/bar.test.ts']); + expect(runScript).toHaveBeenCalledWith('test', manager.getWorktreePath(), [ + 'packages/foo/src/bar.test.ts', + ]); }); }); diff --git a/tests/advance/llm/prompts/prompt-assets.test.ts b/tests/advance/llm/prompts/prompt-assets.test.ts index 947b7f5..ea3ec44 100755 --- a/tests/advance/llm/prompts/prompt-assets.test.ts +++ b/tests/advance/llm/prompts/prompt-assets.test.ts @@ -122,8 +122,19 @@ describe('prompt assets', () => { expect(defaultPromptLoader.load('fix-tool-loop-stale-reminder')).toContain('陷入循环'); expect(defaultPromptLoader.load('fix-tool-loop-read-only-reminder')).toContain('只读探索'); expect( - defaultPromptLoader.load('fix-tool-loop-read-only-failure-reason', { steps: '3' }) + defaultPromptLoader.load('fix-tool-loop-read-only-failure-reason', { + steps: '3', + verdictReason: '问题仍存在', + verdictEvidence: '第 25 行未见修改', + }) ).toContain('3'); + expect( + defaultPromptLoader.load('fix-tool-loop-final-acting-round', { + steps: '3', + verdictReason: '问题仍存在', + verdictEvidence: '第 25 行未见修改', + }) + ).toContain('最后 3 步'); expect(defaultPromptLoader.load('fix-tool-loop-unchanged-finish-reminder')).toContain( '没有检测到' ); diff --git a/tests/fixtures/real-mr-snapshot/discussions.json b/tests/fixtures/real-mr-snapshot/discussions.json new file mode 100644 index 0000000..dd16b06 --- /dev/null +++ b/tests/fixtures/real-mr-snapshot/discussions.json @@ -0,0 +1,423 @@ +[ + { + "discussionId": "1dba48c21bb8bec8d5ccb68d0a83cd0487f7321d", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20251565", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-07T10:16:42.421+08:00", + "body": "ESLint Report\nSeverity\nCount\nError\n0\nWarning\n2724\nTop rules\nRule\nCount\nno-console\n1251\n@typescript-eslint/no-non-null-assertion\n673\n@typescript-eslint/no-explicit-any\n374\n@typescript-eslint/no-unused-vars\n182\nno-empty\n57\nno-restricted-globals\n53\neqeqeq\n51\nreact-hooks/exhaustive-deps\n20\n@typescript-eslint/ban-ts-comment\n15\nno-useless-escape\n14\nTop files\nFile\nErrors\nWarnings\nsrc/app/main.ts\n0\n203\npackages/gateway/src/imTalk/imTalk.ts\n0\n188\nsrc/app/libs/example/sso.ts\n0\n123\npackages/example-infra/src/account/business-sid-manager.ts\n0\n57\nsrc/app/ipc/account.ts\n0\n49\ntests/fixtures/download-url.test.ts\n0\n44\nsrc/app/storage/__tests__/agentSessionStore.test.ts\n0\n40\nsrc/app/notificationBridge/__tests__/notificationBridge.test.ts\n0\n36\nsrc/app/platform/appUpdateInstaller.ts\n0\n28\npackages/example-infra/src/account/legacy-importer.ts\n0\n27" + } + ] + }, + { + "discussionId": "1c9302f42bd2ddda0de73900f68c6118251bc473", + "resolvable": true, + "resolved": true, + "notes": [] + }, + { + "discussionId": "a6c86bbe993e2cbcad02105cff9ac04a5d7ef98b", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20251762", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-07T10:21:07.196+08:00", + "body": "🤖\nCI Review · Round 1 · commit\nf0456135\n基线:origin/main | 模式:full (first-round) | 25 files changed, 1836 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n⚠️\n建议修改后合入\n0\n🔴\n/ 1\n🟡\n/ 5\n🟢\n改动意图:为 memory 模块添加语义化 telemetry tracker,通过 DI 注入 sink 将工具调用和 LLM 调用映射为固定事件上报。\n🟡\n中风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:35\n| 测试覆盖 | no-op 测试未验证真正的 noop 状态 | 在第二个 describe 的 beforeEach 中调用 setMemoryTracker(noopTracker) 重置\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:38\n|\nmemoryLlmCall({ durationMs: 10 })\n缺必填字段\nscene\n,tsc 可能报错\npackages/example-memory/src/core/foundation/telemetry/tracker.ts:20\n|\nsink\n模块单例未在 facade.dispose() 时重置为 noop,遵循 Logger 已有模式但存在多实例泄漏可能\nsrc/app/telemetry/memoryTelemetrySink.ts:87\n|\nmemoryUserCall\n已定义但全 diff 无任何调用点,属死代码占位\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:58\n|\nToolCallParams\n/\nLlmCallParams\n/\nUserCallParams\n注释写\"不对外导出\"但实际是 export,仅靠 index.ts 不 re-export 来隐藏\ndocs/internal/plans/2026-06-24-memory-telemetry-plan.md\n| 835 行计划文档不属于\ndocs/architecture/\n路径,与 CLAUDE.md 方案文档规范无冲突但增加仓库体积\n优点\n遵循现有 Logger DI 模式,tracker 未注入时 no-op 不阻塞主流程,设计干净\nLLM 调用埋点只上报长度/耗时,不泄露用户内容,安全意识到位\n测试覆盖完整(单元 + 集成 + 错误路径),每个 tool 的 success/validation-error/runtime-error 均有 case" + } + ] + }, + { + "discussionId": "8bc4b50d5f41c6d0a91a4f8e033717275ccb0857", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20262686", + "author": "reviewer01", + "authorKind": "human", + "kind": "review-agent", + "at": "2026-07-07T11:33:07.655+08:00", + "body": "🤖\nCodeKeeper 自动评审\nMR\n: Draft: feat(tracer): memory 模块支持 track 固定事件上报 V2\n分支\n:\nfeat/memory-track\n→\nmain\n发现项\n: 7 个\nMR整体设计良好,实现了语义化埋点、依赖注入和失败安全等关键原则。主要问题在于类型定义不一致(\nMemoryLlmCallParams\n缺少\nerror\n字段)可能导致编译错误,以及部分工具中tracker调用模式可能冗余或可优化。此外,存在一些代码风格和文档相关的低风险问题。建议优先修复HIGH和MEDIUM级别的问题以确保代码的正确性和可维护性。\n⚠️\n发现项\n🔴\n高\n(1)\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:31\n· 规则\nTYPE-SAFETY\nMemoryLlmCallParams接口定义缺少\nerror\n字段,但在多个文件(如ltmMetadataGenerator.ts、llmClassifier.ts)的调用点传入了\nerror: 1\n。这会导致TypeScript类型检查失败。\n建议\n:在MemoryLlmCallParams接口中添加可选的\nerror\n字段。例如:\nerror?: number;\n。\n🟠\n中\n(2)\npackages/example-memory/src/core/tools/memoryDejavuTool.ts:64\n· 规则\nREDUNDANT-CODE\n函数在多个提前返回点都调用了\nmemoryTracker.memoryDejavu()\n,可能产生冗余的tracker调用。特别是当\nstore\n不存在时,除了记录错误,还应在函数末尾统一调用一次tracker。\n建议\n:重构逻辑,确保每个函数路径只调用一次tracker。可以在try块开始时记录start,并在try和catch的最终出口处调用tracker,避免在多个中间验证失败点重复调用。\npackages/example-memory/src/core/tools/memorySearchTool.ts:92\n· 规则\nCODE-STRUCTURE\n在输入验证失败时,代码在构造错误响应之前调用了\nmemoryTracker.memorySearch()\n。虽然功能正确,但这种在验证逻辑中提前调用tracker的方式可能让代码流不够清晰,且与其他文件(如\nmemoryDejavuTool.ts\n)的模式不一致。\n建议\n:考虑将tracker调用统一放在成功或失败的最终出口处,与\nmemoryDejavuTool.ts\n等其他文件保持风格一致。\n🟡\n低\n(4)\npackages/example-memory/src/core/tools/memoryRecordTool.ts:204\n· 规则\nCHANGE-MANAGEMENT\n该MR在实现埋点的同时,移除了\nmemoryRecordTool.ts\n中一段被注释掉的重复代码。这是一个有益的清理,但通常建议将这种代码清理放在单独的提交或MR中,以保持功能变更和代码清理的分离,便于追溯。\n建议\n:本次提交可以接受,但建议团队未来遵循约定:功能性变更与纯代码清理分离。\nsrc/app/telemetry/memoryTelemetrySink.ts:25\n· 规则\nPERFORMANCE\ntoTrackParams\n函数每次调用都检查\nprocess.env.DEBUG_MEMORY_TELEMETRY\n。在热路径中,频繁访问环境变量可能带来微小性能开销。虽然当前为no-op sink,但未来接入真实SDK后,若此函数被高频调用,可能需要考虑缓存环境变量值。\n建议\n:可以将环境变量的检查结果缓存在模块作用域的常量中(例如\nconst DEBUG = !!process.env.DEBUG_MEMORY_TELEMETRY;\n),避免每次调用都读取。\nsrc/app/main.ts:1764\n· 规则\nDOCUMENTATION\n在\ncreateMemoryExtensionConfig\n中,\ntracker: createMemoryTelemetrySink()\n调用没有传入\ntrack\n实例,当前是占位实现。虽然描述中说明是“占位”,但缺少明确的\nTODO\n注释来标识这是一个待完成的临时实现。\n建议\n:添加清晰的TODO注释,例如:\ntracker: createMemoryTelemetrySink() // TODO: 传入真实track SDK实例\n。\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:91\n· 规则\nCODE-QUALITY\nLlmCallParams\n接口中\nstop_reason\n类型包含一个‘xx’值(\n'end_turn' | 'tool_use' | 'xx'\n),这看起来像是一个占位符或测试值。应使用正式的、有意义的枚举值。\n建议\n:将\n'xx'\n替换为符合业务逻辑的实际枚举值,或如果当前无其他有效值,可以暂时只定义\n'end_turn' | 'tool_use'\n。\n生成于 2026/7/7 11:33:07 · CodeKeeper Advance MR 评审 Agent · 评审助手" + }, + { + "noteId": "20930140", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-30T17:46:28.135+08:00", + "body": "✅\n已修复(无需重复修改):\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:31: 第33行定义了error?: number;字段,位于MemoryLlmCallParams接口内。\npackages/example-memory/src/core/tools/memorySearchTool.ts:92: memorySearchTool.ts 第 92-96 行:验证 query 失败时调用 memoryTracker.memorySearch() 后返回;memoryDejavuTool.ts 第 72-78 行:验证 query 失败时调用 memoryTracker.memoryDejavu() 后返回。两个文件采用了完全一致的模式。\npackages/example-memory/src/core/tools/memoryRecordTool.ts:204: 聚焦窗口(第180-220行)展示的是干净的工具执行逻辑,包括:参数验证(第182-188行)、内容处理(第191-194行)、短期缓存查重(第196-206行)、优先级验证(第208-218行)、调用Facade方法(第220行起)。没有任何被注释掉的重复代码存在,确认代码清理已完成。\n⏸️\n尝试修复未成功:\npackages/example-memory/src/core/tools/memoryDejavuTool.ts:64 — 连续 8 步没有产生文件变更,修复停留在只读探索阶段;已触发 already-fixed 回查但未确认问题已消失\nsrc/app/telemetry/memoryTelemetrySink.ts:25 — 连续 8 步没有产生文件变更,修复停留在只读探索阶段;已触发 already-fixed 回查但未确认问题已消失\nsrc/app/main.ts:1764 — 连续 8 步没有产生文件变更,修复停留在只读探索阶段;已触发 already-fixed 回查但未确认问题已消失\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:91 — 连续 8 步没有产生文件变更,修复停留在只读探索阶段;已触发 already-fixed 回查但未确认问题已消失\n生成于 2026/7/28 13:37:01 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + }, + { + "discussionId": "3446f34a89f5a8e4d3b1909a6df4d4f611c12ac7", + "resolvable": true, + "resolved": true, + "notes": [] + }, + { + "discussionId": "ea4d32a444eabb8776db94c00273c01ce890ad5e", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20263663", + "author": "reviewer01", + "authorKind": "human", + "kind": "review-agent", + "at": "2026-07-07T11:40:51.897+08:00", + "body": "📝\n补充评审(MR 有更新)\nMR\n: Draft: feat(tracer): memory 模块支持 track 固定事件上报 V2\n新增发现项\n: 3 个\n🟡\n低\n(3)\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:30\n· 规则\ntype-consistency\nMemoryLlmCallParams 接口中 error 字段与其他 Params 接口(MemorySearchParams, MemoryRecordParams, MemoryDejavuParams, MemoryUserCallParams)的 error 字段类型不一致。前者类型为\nnumber\n,后者为可选的\nnumber\n(即\nerror?: number\n)。这可能导致使用混乱。\n建议\n:为保持一致性和清晰语义,建议统一将\nerror\n字段类型定义为可选的\nnumber\n,即\nerror?: number\n。在当前实现中,sink 层 (\nmemoryTelemetrySink.ts\n) 会通过\nerror ?? 0\n来处理\nundefined\n情况,因此将类型改为\nerror?: number\n不会影响功能。\npackages/example-memory/src/core/tools/memoryRecordTool.ts:204\n· 规则\ncode-cleanliness\n文件中存在大段被注释掉的代码(持久化存储查重逻辑)。虽然不影响功能,但降低了代码可读性,并可能引起维护困惑。\n建议\n:如果这段代码已确认不再需要,建议彻底删除。如果是为了未来参考,建议将其移至技术文档或使用\n// TODO:\n或\n// NOTE:\n等更规范的注释说明。\npackages/example-memory/src/core/domains/summaries/sessionSummaryGenerator.ts:150\n· 规则\ndata-completeness\n在\nsessionSummaryGenerator.ts\n的 LLM 调用埋点中,\nsystemPromptLen\n被硬编码为\n0\n。虽然这反映了该场景可能没有独立系统提示的实际情况,但从类型定义\nMemoryLlmCallParams\n看,此字段是可选的。不传递该字段比传递\n0\n语义更清晰,也避免了潜在的误导。\n建议\n:建议在构造上报参数时,不设置\nsystemPromptLen\n字段(即不包含该键),而不是显式设置为\n0\n。\n生成于 2026/7/7 11:40:51 · CodeKeeper Advance MR 评审 Agent · 评审助手" + }, + { + "noteId": "20930141", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-30T17:46:28.515+08:00", + "body": "✅\n已修复(无需重复修改):\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:30: 第 27-35 行:MemoryLlmCallParams 接口中 error 字段已定义为\nerror?: number\n(第 34 行),与 MemorySearchParams(第 14 行)、MemoryRecordParams(第 19 行)、MemoryDejavuParams(第 24 行)、MemoryUserCallParams(第 38 行)的 error?: number 类型一致。\npackages/example-memory/src/core/tools/memoryRecordTool.ts:204: The full 256-line file contains no commented-out code blocks. Around line 204, the code shows active validation logic for priority input (lines 200-220). The deduplication mechanism is implemented as active short-term cache code:\nrecentRecords\nMap (line 38),\nhashContent()\n(line 62),\nisRecentlyRecorded()\n(line 72),\nmarkAsRecorded()\n(line 88), and the check at line 193-204. No commented-out persistent storage deduplication logic exists in the file.\npackages/example-memory/src/core/domains/summaries/sessionSummaryGenerator.ts:150: 第 158-163 行和第 167-173 行的两次 memoryLlmCall 调用中,参数对象只包含 scene、durationMs、userPromptLen、outputLen(以及 error 路径的 error: 1),不再包含 systemPromptLen 字段。\n生成于 2026/7/27 11:53:03 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + }, + { + "discussionId": "190140ab110fd610f26d7c4d5f3c7f938ec4d983", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20266907", + "author": "reviewer01", + "authorKind": "human", + "kind": "comment", + "at": "2026-07-07T14:33:30.126+08:00", + "body": "这个设计文件不该被上传" + }, + { + "noteId": "20517158", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-15T16:35:49.240+08:00", + "body": "✅\n维护助手 已根据 Reviewer 的意见删除文件\ndocs/internal/plans/2026-06-24-memory-telemetry-plan.md\n并推送至本分支。\n问题分析\n问题指出设计文件 'docs/internal/plans/2026-06-24-memory-telemetry-plan.md' 不应被上传到版本控制中。该文件路径明确属于设计文档(docs/),且问题描述直接表明其不应存在。根据决策原则,对于明确指出不应上传的设计文档,应选择fix并删除文件。\n考虑过的方案\n方案1: 从版本控制中永久删除该设计文件,并清理Git历史以彻底移除痕迹。\n方案2: 保留文件但大幅修改内容,移除所有敏感信息,仅保留通用的架构描述。\n方案3: 将文件移动到非公开的内部文档目录(如internal/docs/),并设置访问权限。\n最终决策\n问题明确指出文件不应上传,且文件路径属于设计文档。方案1是唯一完全删除文件的方案,符合决策原则和数据最小化原则。虽然需要重写Git历史并协调团队,但这是彻底解决问题的必要步骤。方案2和3都未能彻底移除文件,可能导致未来泄露风险。\n请 Reviewer 复核变更。\n生成于 2026/7/15 16:35:47 · CodeKeeper Advance MR 维护 Agent · 维护助手" + }, + { + "noteId": "20930142", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-30T17:46:28.941+08:00", + "body": "✅\n维护助手 经检查,本 discussion 指出的问题在当前代码中似乎已经修复:当前分支无法定位 docs/internal/plans/2026-06-24-memory-telemetry-plan.md,该文件已被删除或移动\n请 Reviewer 复核确认。\n生成于 2026/7/27 11:45:17 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + }, + { + "discussionId": "ac669e74e883b0de6d9f163a59dcc942e2bef87e", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20266910", + "author": "reviewer01", + "authorKind": "human", + "kind": "comment", + "at": "2026-07-07T14:33:35.017+08:00", + "body": "这个设计文件不该被上传" + }, + { + "noteId": "20495188", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-14T19:53:13.458+08:00", + "body": "✅\n维护助手 已根据 Reviewer 的意见自动修复并推送至本分支。\n问题分析\n该文件是 Memory 模块 track 埋点的设计文档,包含接口定义、架构图、参数规范等内部实现细节。问题描述明确指出\"这个设计文件不该被上传\",说明这是一次误提交。文件中的接口定义(MemorySearchParams、MemoryTracker 等)、埋点事件映射规则、隐私约束等属于内部设计规范,不应暴露在代码仓库中。\n考虑过的方案\n方案1:直接删除文件并从 Git 历史清除\n方案2:迁移到内部文档平台后删除并加入 .gitignore\n方案3:保留但脱敏处理\n最终决策\n选择方案1的原因:1) 问题描述已明确该文件不该被上传,最直接的解决方案就是删除;2) 方案2需要额外的迁移工作且增加复杂度;方案3脱敏后文档价值降低且仍可能泄露部分信息;3) 删除操作简单、风险低、一步到位;4) 如果团队需要该文档,可以从内部文档平台或 Git 历史中获取,不依赖代码仓库存储。\n请 Reviewer 复核变更。\n生成于 2026/7/14 19:53:12 · CodeKeeper Advance MR 维护 Agent · 维护助手" + }, + { + "noteId": "20811490", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-27T11:46:51.681+08:00", + "body": "✅\n维护助手 经检查,本 discussion 指出的问题在当前代码中似乎已经修复:当前分支无法定位 docs/internal/specs/2026-06-24-memory-telemetry-design.md,该文件已被删除或移动\n请 Reviewer 复核确认。\n生成于 2026/7/27 11:46:49 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + }, + { + "discussionId": "5d9b7eb6983839cb333136997cab805050901787", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20495681", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-14T20:02:38.242+08:00", + "body": "🤖\nCI Review · Round 2 · commit\n38f9d6d3\n基线:origin/main | 模式:incremental since\nf0456135\n(incremental-since-last-review) | 24 files changed, 1530 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 0\n🟢\n改动意图:移除误提交的设计文档\ndocs/internal/specs/2026-06-24-memory-telemetry-design.md\n优点\n及时清理不应入库的设计文档,保持仓库整洁\ncommit message 明确说明了删除原因" + } + ] + }, + { + "discussionId": "dda8db9a21fa8e426e2586e3bcc2a465d269cb6b", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20496338", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-14T20:13:22.677+08:00", + "body": "ESLint Report (delta)\nMetric\nPrevious\nCurrent\nDelta\nError\n0\n0\n+0\nWarning\n2724\n2723\n-1" + } + ] + }, + { + "discussionId": "9e803d45c903bc566c8025ced94b104bd7be836a", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20496484", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-14T20:15:29.045+08:00", + "body": "🤖\nCI Review · Round 3 · commit\nd0e61cb0\n基线:origin/main | 模式:incremental since\n38f9d6d3\n(incremental-since-last-review) | 24 files changed, 1567 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 2\n🟢\n改动意图:补充 memory telemetry tracker 的 no-op 测试覆盖(返回值验证 + 委托验证)\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:33\n| describe 命名\"no-op default\"实际注入了 mock,并非测试真正的未注入默认态\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:62\n| \"delegates calls to the injected noopTracker\" 与第一个 describe block 功能重复\n优点\n测试覆盖了返回值为 undefined 的断言,补齐了原有仅断言不抛异常的空白\n参数传递验证用不同的 durationMs 值区分各方法,可读性好" + } + ] + }, + { + "discussionId": "514a30f5de5ea103beeae76427bb3a4b2d80916c", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20498168", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-14T20:50:53.515+08:00", + "body": "ESLint Report (delta)\nMetric\nPrevious\nCurrent\nDelta\nError\n0\n0\n+0\nWarning\n2724\n2723\n-1" + } + ] + }, + { + "discussionId": "a2f158fa9498b9fe99f4bb69ca5ec7a91280fae2", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20498214", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-14T20:52:15.609+08:00", + "body": "🤖\nCI Review · Round 4 · commit\ndc4203c7\n基线:origin/main | 模式:incremental since\nd0e61cb0\n(incremental-since-last-review) | 24 files changed, 1556 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:合并重复的 tracker delegation 测试用例,消除冗余并改善命名准确性\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:17\n| 多个方法断言合入单个\nit\n块,失败时定位粒度略降,可接受\n优点\n消除了两个 describe 块之间的重复 delegation 断言,测试意图更清晰\nnoopTracker\n→\nmockTracker\n命名更准确(实际是\nvi.fn()\nmock 而非真正 no-op)\n所有 5 个 tracker 方法的覆盖完整保留,无遗漏" + } + ] + }, + { + "discussionId": "49f9d267bfd6831d3a118eb1faa34d035f442c8e", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20517570", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-15T16:42:43.080+08:00", + "body": "ESLint Report (delta)\nMetric\nPrevious\nCurrent\nDelta\nError\n0\n0\n+0\nWarning\n2724\n2723\n-1" + } + ] + }, + { + "discussionId": "c5459ee4736c68d757112ea32848a9fc52a73e28", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20517621", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-15T16:43:49.495+08:00", + "body": "🤖\nCI Review · Round 5 · commit\nefc2e8d5\n基线:origin/main | 模式:incremental since\ndc4203c7\n(incremental-since-last-review) | 23 files changed, 721 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 0\n🟢\n改动意图:移除误提交的设计计划文档\ndocs/internal/plans/2026-06-24-memory-telemetry-plan.md\n优点\n及时清理不应纳入版本管理的过程性计划文档,保持仓库整洁\n文件内容含本地绝对路径和\n--no-verify\n示例,移除后避免误导后续开发者" + } + ] + }, + { + "discussionId": "70797960008c488b4b849b1c779ad98b9963f00c", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20588334", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-17T12:56:47.639+08:00", + "body": "🤖\nCI Review · Round 6 · commit\n26276bcc\n基线:origin/main | 模式:incremental since\nefc2e8d5\n(incremental-since-last-review) | 23 files changed, 719 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:移除 sessionSummaryGenerator 中无实际系统 prompt 的冗余\nsystemPromptLen: 0\n字段\n🟢\n低风险\npackages/example-memory/src/core/domains/summaries/sessionSummaryGenerator.ts:151\n| 一致性:topicTranslator.ts 中同样无 system prompt 的调用点仍传\nsystemPromptLen: 0\n(共 4 处),可考虑统一清理\n优点\n改动正确且安全:\nsystemPromptLen\n在\nMemoryLlmCallParams\n接口中为 optional 字段,移除无语义值的\n0\n传入不影响行为\n减少无意义噪声,调用意图更清晰" + } + ] + }, + { + "discussionId": "429c4d00a9e9486465c19d0d8a3eaf7ab892081f", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20602886", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-17T20:54:42.168+08:00", + "body": "🤖\nCI Review · Round 7 · commit\n4c5a0771\n基线:origin/main | 模式:incremental since\n26276bcc\n(incremental-since-last-review) | 23 files changed, 719 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:将 no-op 测试用例中的\nvi.fn()\nmock 替换为真正的空函数,使测试验证的是实际 noop 行为而非 mock 行为。\n🟡\n中风险\n(无)\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:2\n| 文件仍使用\nexpect\n而非项目规范的\nassert.strictEqual\n(历史问题,非本轮引入)\n优点\n命名从\nmockTracker\n改为\nnoopTracker\n,准确反映测试意图\n使用\n() => {}\n替代\nvi.fn()\n是正确做法——验证真正的 no-op 实现不抛异常且返回 undefined,而非仅验证 mock 框架的行为" + } + ] + }, + { + "discussionId": "9882cfb176398205f239dfe1fbf3d89d22a6c300", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20603073", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-17T21:06:34.260+08:00", + "body": "🤖\nCI Review · Round 8 · commit\nc83365c6\n基线:origin/main | 模式:incremental since\n4c5a0771\n(incremental-since-last-review) | 23 files changed, 688 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:移除 memory telemetry tracker 中测试 no-op 行为的冗余用例,保留有意义的委托验证。\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:36\n| 删除的 no-op 测试覆盖了默认 sink 路径,当前仅剩注入后的委托测试;可考虑补一条\"未注入时调用不抛异常\"的单行用例确保 default sink 不被误改\n优点\n移除了对空函数\"不抛异常/返回 undefined\"的 trivial 断言,减少测试维护噪声\n保留的委托测试覆盖了核心行为(setMemoryTracker 后 memoryTracker 正确分发)\nimport 也同步清理,无残留" + } + ] + }, + { + "discussionId": "aa4a09893f2e159c0fc80e8d9e6b83997d18414e", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20603332", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-17T21:22:30.063+08:00", + "body": "🤖\nCI Review · Round 9 · commit\ncc64ea9d\n基线:origin/main | 模式:incremental since\nc83365c6\n(incremental-since-last-review) | 23 files changed, 689 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n6\n结论\n:\n✅\n通过(含 0 条中、0 条低、6 条提示)\n💡\n提示 (6)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:将 tracker 单测的断言从 vitest\nexpect\n迁移至\nnode:assert\n,对齐项目测试规范\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:20\n| 5 处\nas any\n访问 mock 内部属性,可用 vitest\nMock\n类型或\nvi.mocked()\n替代\n优点\n严格对齐项目测试规范(\nassert.deepStrictEqual\n替代\nexpect().toHaveBeenCalledWith()\n)\n断言语义等价,无行为变更风险" + } + ] + }, + { + "discussionId": "38afb603791e2e6d213dcdf50fc5223978dbc9c9", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20627896", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-20T12:19:57.732+08:00", + "body": "🤖\nCI Review · Round 10 · commit\n8fc5f909\n基线:origin/main | 模式:incremental since\ncc64ea9d\n(incremental-since-last-review) | 23 files changed, 701 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n6\n结论\n:\n✅\n通过(含 0 条中、0 条低、6 条提示)\n💡\n提示 (6)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nR01-dangerous-any\n/builds/example-group/example-desktop/packages/example-memory/src/core/foundation/telemetry/\ntests\n/tracker.test.ts — 禁止使用 any 类型;请改用 unknown 或具体类型(CLAUDE.md 强制约束)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:将 tracker 单元测试中的多断言单\nit\n块拆分为独立\nit\n块,提升测试失败定位精度\n🟢\n低风险\ntracker.test.ts:20,25,31,37,46\n| 各\nit\n块内\n(tracker.memorySearch as any).mock.calls\n的\nas any\n是访问 vitest mock 内部的必要手段,可接受\n优点\n每个\nit\n块独立运行\nbeforeEach\n,消除了测试间的隐式顺序依赖\n测试失败时可精确定位到具体方法,无需逐行排查\n改动最小化,仅拆分 + 补充局部\ngetMemoryTracker()\n调用,无逻辑变更" + } + ] + }, + { + "discussionId": "497527248e1f2153cf9a7afe5d5c4b98003ebe83", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20631252", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-20T14:49:33.677+08:00", + "body": "🤖\nCI Review · Round 11 · commit\ndc4c3abd\n基线:origin/main | 模式:incremental since\n8fc5f909\n(incremental-since-last-review) | 23 files changed, 701 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:将测试中\nas any\n类型断言替换为\nvi.mocked()\n以消除\nany\n使用,提升类型安全\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:20\n| commit message 提到\nunknown\n但实际用\nvi.mocked()\n,message 与实现略有出入,无功能影响\n优点\n正确使用\nvi.mocked()\n替代\nas any\n,既消除了 lint 告警又保留了类型推断\n改动范围精确、无副作用,5 处替换手法一致" + } + ] + }, + { + "discussionId": "fcb172a7f214b2b8463f5de21a7b12a2cbd72137", + "resolvable": true, + "resolved": true, + "notes": [ + { + "noteId": "20671038", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-21T16:21:45.362+08:00", + "body": "🤖\nCI Review · Round 12 · commit\ne2790b44\n基线:origin/main | 模式:incremental since\ndc4c3abd\n(incremental-since-last-review) | 23 files changed, 720 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n✅\n建议合入\n0\n🔴\n/ 0\n🟡\n/ 1\n🟢\n改动意图:补充 tracker 无注入场景的防御性测试,确保 noop sink 不抛异常\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/__tests__/tracker.test.ts:50\n| 测试描述为\"uninjected state\"但实际是手动 setMemoryTracker 为 noop,非真正的模块初始默认态;语义轻微不匹配,不影响正确性\n优点\n测试意图清晰,覆盖了 noop sink 不抛异常的边界场景\n遵循项目测试规范(vitest + node:assert,独立 it 块)\n改动极小且聚焦,无副作用" + } + ] + }, + { + "discussionId": "57256565f4957edcd2a99d583faf671f68977e6e", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20695283", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-22T11:29:45.752+08:00", + "body": "ESLint Report\nSeverity\nCount\nError\n0\nWarning\n2726\nTop rules\nRule\nCount\nno-console\n1251\n@typescript-eslint/no-non-null-assertion\n673\n@typescript-eslint/no-explicit-any\n374\n@typescript-eslint/no-unused-vars\n184\nno-empty\n57\nno-restricted-globals\n53\neqeqeq\n51\nreact-hooks/exhaustive-deps\n20\n@typescript-eslint/ban-ts-comment\n15\nno-useless-escape\n14\nTop files\nFile\nErrors\nWarnings\nsrc/app/main.ts\n0\n203\npackages/gateway/src/imTalk/imTalk.ts\n0\n188\nsrc/app/libs/example/sso.ts\n0\n123\npackages/example-infra/src/account/business-sid-manager.ts\n0\n57\nsrc/app/ipc/account.ts\n0\n49\ntests/fixtures/download-url.test.ts\n0\n44\nsrc/app/storage/__tests__/agentSessionStore.test.ts\n0\n40\nsrc/app/notificationBridge/__tests__/notificationBridge.test.ts\n0\n36\nsrc/app/platform/appUpdateInstaller.ts\n0\n28\npackages/example-infra/src/account/legacy-importer.ts\n0\n27" + } + ] + }, + { + "discussionId": "8dbe20a51666feae2d9cb97122023b629ebcfef9", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20695367", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-22T11:31:25.663+08:00", + "body": "🟡\nMedium 架构合规 :全局 singleton reset 在多实例场景下互相干扰\n问题描述\n全局 singleton reset 在多实例场景下互相干扰\n影响范围\n(未提供)\n建议修改\n改为实例级 tracker 或 dispose 时仅置空自身注入的引用\n参考规范\nCLAUDE.md 架构约束" + }, + { + "noteId": "20930147", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-30T17:46:30.247+08:00", + "body": "我尝试自动修复 packages/example-memory/src/core/memoryFacade.ts:913,但未成功。请 Reviewer 补充期望的修改方式或范围,我会再试一次。\n生成于 2026/7/28 13:04:33 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + }, + { + "discussionId": "8347932b60c0b4488d8865330daa283deeda9ced", + "resolvable": true, + "resolved": false, + "notes": [ + { + "noteId": "20695368", + "author": "project_1000_bot_00000000000000000000000000000000", + "authorKind": "bot", + "kind": "comment", + "at": "2026-07-22T11:31:26.087+08:00", + "body": "🤖\nCI Review · Round 13 · commit\n45e67efd\n基线:origin/main | 模式:incremental since\nb633518b\n(incremental-since-last-review) | 23 files changed, 746 insertions(+), 39 deletions(-)\n规则扫描\n类型\n数量\n🔴\n严重\n0\n🟠\n高\n0\n🟡\n中\n0\n🟢\n低\n0\n💡\n提示\n1\n结论\n:\n✅\n通过(含 0 条中、0 条低、1 条提示)\n💡\n提示 (1)\nCORE\nsrc/app/main.ts — 核心保护文件被修改,请确认变更必要性\nAI 分析\n⚠️\n建议修改后合入\n0\n🔴\n/ 1\n🟡\n/ 2\n🟢\n改动意图:为 memory tracker 增加\nresetMemoryTracker()\n重置能力,在 facade dispose 时解除全局 sink 引用防止泄漏;同时收窄\ntrackerTypes\n中仅供内部使用的接口可见性。\n🟡\n中风险\npackages/example-memory/src/core/memoryFacade.ts:913\n| 架构合规 | 全局 singleton reset 在多实例场景下互相干扰 | 改为实例级 tracker 或 dispose 时仅置空自身注入的引用\nsink\n是模块级单例。若存在两个 MemoryFacadeImpl 实例(A、B),A.dispose() 调用\nresetMemoryTracker()\n会将 B 正在使用的 tracker 也重置为 noop,导致 B 静默丢失遥测数据。建议在 reset 前校验\nsink === 本实例注入的 tracker\n再置空,或将 tracker 下沉为实例属性。\n🟢\n低风险\npackages/example-memory/src/core/foundation/telemetry/tracker.ts:34\n| 注释里写\"多实例场景\"但实现是全局 reset,文档与行为有歧义\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:51\n| 接口去 export 是正确收窄,确认无外部消费方即可\n优点\n新增\nresetMemoryTracker\n配套测试覆盖完整,遵循项目 vitest + assert 规范\ntrackerTypes\n接口可见性收窄与注释\"不对外导出\"保持一致,减少公共 API 面积\ndispose 路径主动释放引用,方向正确,防止旧 tracker 持有外部资源" + }, + { + "noteId": "20930150", + "author": "reviewer01", + "authorKind": "human", + "kind": "maintainer-agent", + "at": "2026-07-30T17:46:30.844+08:00", + "body": "✅\n已修复(无需重复修改):\npackages/example-memory/src/core/foundation/telemetry/trackerTypes.ts:51: 第51行:interface ToolCallParams { (无export);第59行:interface LlmCallParams { (无export);第81行:interface UserCallParams { (无export)。\n⏸️\n尝试修复未成功:\npackages/example-memory/src/core/foundation/telemetry/tracker.ts:34 — Worktree commit 失败:\n💡\n提醒:提交前建议执行代码自检\n/review — 架构合规 + 安全 + 代码质量\n/simplify — 检查代码复用、质量和效率\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n🔍\nLint (npm run lint)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nexample@0.0.1 lint\neslint . --ext ts,tsx --report-unused-disable-directives && node scripts/build/check-bare-src-imports.mjs && node scripts/build/check-architecture-boundaries.mjs && node scripts/lint/skill-md-codeblock-lint.cjs && node scripts/lint/check-e2e-ui-contract.cjs\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src_\ntests\n_\\gatewayProtocol.test.ts[24m[0m\n[0m [2m209:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m210:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m211:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src_\ntests\n_\\midGenerator.test.ts[24m[0m\n[0m [2m33:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m34:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src_\ntests\n_\\reconnectManager.test.ts[24m[0m\n[0m [2m121:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m167:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m210:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\api\\gateway.ts[24m[0m\n[0m [2m70:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m73:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m76:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m79:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m82:36[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m85:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m88:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m91:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m182:51[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m185:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m188:58[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\gateway.ts[24m[0m\n[0m [2m68:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m73:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m78:31[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m84:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m91:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m96:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m100:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m106:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m115:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m129:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m284:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m295:53[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m303:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m331:55[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m335:55[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m343:56[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m352:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m368:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m370:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m371:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m372:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m373:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m380:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m399:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\im\\imMediaParser.ts[24m[0m\n[0m [2m109:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m117:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m136:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m155:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m174:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m192:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m210:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m229:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m247:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m262:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk_\ntests\n_\\devicePresenceWatcher.test.ts[24m[0m\n[0m [2m806:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk\\devicePresenceWatcher.ts[24m[0m\n[0m [2m306:47[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk\\imTalkIM.ts[24m[0m\n[0m [2m9:13[22m [33mwarning[39m 'os' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m25:3[22m [33mwarning[39m 'ImTalkDeviceInfo' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m160:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m273:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m276:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m305:34[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m325:3[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m327:8[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m375:3[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m376:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m378:79[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m394:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m405:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m410:19[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m412:19[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m415:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m416:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m425:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m430:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m435:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m443:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m451:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m463:44[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m475:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m489:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m496:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m506:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m512:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m527:39[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m549:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m567:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m573:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m578:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m592:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m595:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m596:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m597:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m614:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m618:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m619:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m620:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m624:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m639:1[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m746:39[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m759:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m760:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m763:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m778:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m795:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m801:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m816:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m823:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m850:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m867:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m868:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m869:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m870:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m871:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m875:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m876:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m876:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m877:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m878:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m932:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m953:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m954:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m978:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m983:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1007:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1049:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1053:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1070:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1078:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1175:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1223:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1241:30[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1242:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1253:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1267:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1274:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1290:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1293:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1308:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1324:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1346:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1380:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1395:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1409:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1412:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1441:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1450:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1473:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1488:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1489:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1490:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1498:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1514:40[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1522:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1560:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1567:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1584:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1619:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1649:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1655:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1683:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1697:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1724:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1741:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1789:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1810:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1814:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1819:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1832:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1856:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1870:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1871:13[22m [33mwarning[39m 'result' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1872:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1873:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1896:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1935:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1936:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1937:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1938:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1943:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1944:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1945:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1964:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1965:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1966:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1967:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1970:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1971:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1992:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2020:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2033:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2034:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2035:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2036:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2043:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2067:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2070:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2071:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2095:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2124:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2137:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2138:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2139:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2142:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2157:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2160:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2161:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2183:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2187:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2193:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2227:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2228:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2229:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2232:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2240:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2243:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2251:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2252:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2253:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2262:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2279:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2280:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2281:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2282:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2285:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2286:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2287:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2288:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2289:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2309:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2310:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2331:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2334:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2335:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2341:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2344:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2345:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2350:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2360:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2362:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2374:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2381:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2383:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2393:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk\\imTalkSdkLoader.ts[24m[0m\n[0m [2m59:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m64:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m66:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m76:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m83:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m88:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m106:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m109:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m112:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m142:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m149:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m155:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m166:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m189:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m190:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m196:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m203:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m211:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m213:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m218:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m223:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m225:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m239:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m277:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk\\imTalkSdkTypes.ts[24m[0m\n[0m [2m117:13[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m121:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m167:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m246:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m333:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m335:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m337:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m339:30[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m354:59[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m369:66[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m441:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m444:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m447:51[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m450:62[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m453:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\imTalk\\imTalkTransport.ts[24m[0m\n[0m [2m100:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m120:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m157:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m174:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m205:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m207:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m210:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m213:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m248:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m273:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m281:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\protocol_\ntests\n_\\rpcCallEventFrame.test.ts[24m[0m\n[0m [2m86:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m87:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m88:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m89:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m96:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m97:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m140:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m141:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m142:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\protocol_\ntests\n_\\syncCallEnvelope.test.ts[24m[0m\n[0m [2m122:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m123:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m175:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m176:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\protocol\\gatewayProtocol.ts[24m[0m\n[0m [2m203:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m205:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m225:13[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m225:67[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m333:60[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m337:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m451:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m452:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m474:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m475:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m544:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m547:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m552:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m552:85[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m558:62[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m579:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m584:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m584:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m653:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\transport\\a2aTransport.ts[24m[0m\n[0m [2m237:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m247:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m330:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m338:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m414:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m483:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m590:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m645:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m671:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m684:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m746:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m862:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\transport\\agentCardResolver.ts[24m[0m\n[0m [2m72:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m115:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\transport\\continuityTransport.ts[24m[0m\n[0m [2m87:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m108:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m178:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m190:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m224:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m257:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m288:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m310:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m401:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m426:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-gateway\\src\\transport\\netCallProfiler.ts[24m[0m\n[0m [2m69:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m103:49[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m107:39[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m120:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m217:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\a2a-notification\\src_\ntests\n_\\notifForwardHandler.test.ts[24m[0m\n[0m [2m56:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m57:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m58:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m59:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m60:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m61:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m62:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m63:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m64:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m85:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m97:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m116:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m125:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m155:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m156:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m157:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m192:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m193:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m194:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\crypt_\ntests\n_\\cryptFacade.stream.test.ts[24m[0m\n[0m [2m54:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\crypt_\ntests\n_\\cryptFacade.test.ts[24m[0m\n[0m [2m52:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\crypt\\binding_\ntests\n_\\activeAccount.test.ts[24m[0m\n[0m [2m3:10[22m [33mwarning[39m 'PlatformKeychain' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\crypt\\binding\\activeAccount.ts[24m[0m\n[0m [2m87:64[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\deviceName.ts[24m[0m\n[0m [2m95:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\deviceid.ts[24m[0m\n[0m [2m53:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m56:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m58:16[22m [33mwarning[39m '\n' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m69:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m72:16[22m [33mwarning[39m '\n' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m82:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m102:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m155:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m163:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m169:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m182:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\ipc\\JsonRpcServer.ts[24m[0m\n[0m [2m9:23[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m312:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\ipc\\endpoint.ts[24m[0m\n[0m [2m17:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\jsonEncoding.ts[24m[0m\n[0m [2m12:40[22m [33mwarning[39m Unexpected control character(s) in regular expression: \\x00 [2mno-control-regex[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\keychain_\ntests\n_\\keychainKeytarStrategy.test.ts[24m[0m\n[0m [2m21:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m107:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m108:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\keychain_\ntests\n_\\keychainSafeStorageStrategy.test.ts[24m[0m\n[0m [2m102:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m104:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m193:11[22m [33mwarning[39m 'freshStrategy' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m221:36[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m226:36[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m227:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\keychain\\credentialStorage.ts[24m[0m\n[0m [2m70:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\keychain\\keychainManager.ts[24m[0m\n[0m [2m27:49[22m [33mwarning[39m 'AccountKeyStorage' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\keychain\\safeStorageProvider.ts[24m[0m\n[0m [2m33:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\log_\ntests\n_\\logCleanup.test.ts[24m[0m\n[0m [2m140:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m146:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m147:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m148:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m149:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m151:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m152:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m153:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m155:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m156:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m157:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m158:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m159:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m160:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m162:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\log_\ntests\n_\\logSanitizer.test.ts[24m[0m\n[0m [2m269:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\base\\src\\internal\\log\\logSanitizer.ts[24m[0m\n[0m [2m74:13[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m81:13[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m214:11[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\build-tools\\src\\signing\\config.ts[24m[0m\n[0m [2m9:24[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\build-tools\\src\\signing\\fileCollector.ts[24m[0m\n[0m [2m71:20[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m75:16[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m94:14[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\build-tools\\src\\signing\\signingClient.ts[24m[0m\n[0m [2m293:15[22m [33mwarning[39m 'redirectData' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m428:15[22m [33mwarning[39m 'redirectData' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\build-tools\\src\\signing\\signingManager.ts[24m[0m\n[0m [2m382:20[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m386:16[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m421:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\build-tools\\src\\signing\\types.ts[24m[0m\n[0m [2m5:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src_\ntests\n_\\a2aFileTransferServiceDownloading.test.ts[24m[0m\n[0m [2m177:25[22m [33mwarning[39m Unexpected use of '\nfilename'. Use import.meta.filename (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src_\ntests\n\\agentCard.test.ts[24m[0m\n[0m [2m45:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m55:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src_\ntests\n\\agentCardPostActionCapability.test.ts[24m[0m\n[0m [2m68:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src_\ntests\n_\\agentCardSetLocalContinuityId.test.ts[24m[0m\n[0m [2m63:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m118:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m138:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src_\ntests\n_\\groupChatHookContract.test.ts[24m[0m\n[0m [2m65:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m66:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n_\\coordinatorHeartbeatBridge.test.ts[24m[0m\n[0m [2m16:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\coordinatorIntentRelayTemplate.test.ts[24m[0m\n[0m [2m19:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\coordinatorMilestoneObserverWiring.test.ts[24m[0m\n[0m [2m25:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\coordinatorThinkingSuppress.test.ts[24m[0m\n[0m [2m18:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m19:32[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\coordinatorUiEventStream.test.ts[24m[0m\n[0m [2m32:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\llmHistoryIsolation.test.ts[24m[0m\n[0m [2m28:36[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination_\ntests\n\\receiverArtifactErrorPhase.test.ts[24m[0m\n[0m [2m14:36[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination\\canonicalDeviceGraph.ts[24m[0m\n[0m [2m266:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination\\coordinator.ts[24m[0m\n[0m [2m429:51[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m806:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1052:57[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination\\decomposer.ts[24m[0m\n[0m [2m23:7[22m [33mwarning[39m 'DEFAULT_DECOMPOSE_TIMEOUT_MS' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\coordination\\receiver.ts[24m[0m\n[0m [2m22:15[22m [33mwarning[39m 'CoordinationDeps' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\file-transfer_\ntests\n\\channelDispatcher.test.ts[24m[0m\n[0m [2m174:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m175:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m176:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m177:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m178:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m179:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m180:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m181:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m227:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\file-transfer_\ntests\n\\postActionRegistryAbort.test.ts[24m[0m\n[0m [2m30:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m31:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m32:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m34:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m52:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m59:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m60:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m78:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m104:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m105:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\file-transfer\\fileReceiveCoordinator.ts[24m[0m\n[0m [2m506:7[22m [33mwarning[39m 'self' is never reassigned. Use 'const' instead [2mprefer-const[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\file-transfer\\outboundUploader.ts[24m[0m\n[0m [2m197:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m198:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\MilestoneObserver.ts[24m[0m\n[0m [2m331:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m361:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat_\ntests\n\\acceptedPool.test.ts[24m[0m\n[0m [2m18:3[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat_\ntests\n\\bubbleWriter.test.ts[24m[0m\n[0m [2m44:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m156:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1513:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1514:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1570:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat_\ntests\n\\fileDeliveryPool.test.ts[24m[0m\n[0m [2m21:30[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat_\ntests\n\\groupChatHookImpl.test.ts[24m[0m\n[0m [2m667:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m908:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m916:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m918:8[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1137:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1138:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1471:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1653:31[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1654:31[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1719:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1758:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\bubbleWriter.ts[24m[0m\n[0m [2m17:35[22m [33mwarning[39m 'ResultToneLlmInput' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m17:55[22m [33mwarning[39m 'ResultToneLlmOutput' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m18:10[22m [33mwarning[39m 'deriveDeviceType' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m603:42[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\template\\TemplateEngine.ts[24m[0m\n[0m [2m365:57[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\template_\ntests\n\\TemplateEngine.test.ts[24m[0m\n[0m [2m11:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\template_\ntests\n\\hasHeadOrTailEcho.test.ts[24m[0m\n[0m [2m28:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\template_\ntests\n\\leaderToneAsset.test.ts[24m[0m\n[0m [2m11:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\template_\ntests\n\\personaIntegration.test.ts[24m[0m\n[0m [2m26:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\groupChat\\uiExpressionLayer_\ntests\n\\UiExpressionSubscriber.test.ts[24m[0m\n[0m [2m132:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m164:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m214:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m260:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m277:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m302:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m338:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m384:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m403:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m431:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m432:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\remoteControl_\ntests\n\\gateway.test.ts[24m[0m\n[0m [2m1:36[22m [33mwarning[39m 'beforeEach' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1:48[22m [33mwarning[39m 'afterEach' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\toolProvider.ts[24m[0m\n[0m [2m427:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\cloudUpload_\ntests\n\\cloudUploadTool.test.ts[24m[0m\n[0m [2m31:65[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m39:65[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m44:65[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\cloudUpload\\cloudUploadTool.ts[24m[0m\n[0m [2m19:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\device_\ntests\n_helpers\\deviceChatSource.ts[24m[0m\n[0m [2m16:33[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\device_\ntests\n\\deviceChatNotifyBack.test.ts[24m[0m\n[0m [2m273:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\device_\ntests\n\\perspectiveInstruction.test.ts[24m[0m\n[0m [2m28:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m29:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m29:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m29:40[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\device\\deviceChatMentions.ts[24m[0m\n[0m [2m87:22[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-a2a\\src\\tools\\device\\deviceChatRunner.ts[24m[0m\n[0m [2m203:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m243:9[22m [33mwarning[39m 'deadlineHandle' is never reassigned. Use 'const' instead [2mprefer-const[22m[0m\n[0m [2m624:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m663:70[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m668:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m669:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m709:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m819:37[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m850:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m981:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\CloudAPI.ts[24m[0m\n[0m [2m66:11[22m [33mwarning[39m 'data' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\FileScanner.ts[24m[0m\n[0m [2m17:45[22m [33mwarning[39m 'LOCAL_STATUS' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m46:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m85:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m161:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m241:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\FileWatcher.ts[24m[0m\n[0m [2m45:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m85:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m92:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\SyncDatabase.ts[24m[0m\n[0m [2m102:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m107:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m109:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m663:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\SyncEngine.ts[24m[0m\n[0m [2m104:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m204:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m382:59[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m383:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m399:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m415:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m478:63[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m489:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m507:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m579:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m704:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m720:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m728:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m795:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m897:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m936:42[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m937:39[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m938:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m982:17[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m1169:27[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m1237:57[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1248:63[22m [33mwarning[39m 'scenario' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1327:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1331:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\SyncScheduler.ts[24m[0m\n[0m [2m91:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\TransportBridge.ts[24m[0m\n[0m [2m53:11[22m [33mwarning[39m 'FilesCommitResponse' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m167:13[22m [33mwarning[39m 'text' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m245:11[22m [33mwarning[39m 'createResponse' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m261:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m318:13[22m [33mwarning[39m 'isExisted' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m506:37[22m [33mwarning[39m 'fileName' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m506:47[22m [33mwarning[39m 'fileSize' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m516:11[22m [33mwarning[39m 'downloadResponse' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit_\ntests\n\\SyncEngine.test.ts[24m[0m\n[0m [2m1:24[22m [33mwarning[39m 'expect' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\cloudkit\\cloudKitFileSync.ts[24m[0m\n[0m [2m131:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m133:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m139:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m156:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m164:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m187:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m195:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m212:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m214:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\push\\PushClient.ts[24m[0m\n[0m [2m85:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m91:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m97:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m133:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m143:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m156:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m208:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m267:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m276:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m284:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m372:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m404:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\push_\ntests\n\\PushClient.test.ts[24m[0m\n[0m [2m6:26[22m [33mwarning[39m 'adler32' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m9:3[22m [33mwarning[39m 'encodeConnBind' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m10:3[22m [33mwarning[39m 'decodeConnBindResp' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m11:3[22m [33mwarning[39m 'decodeKick' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m130:10[22m [33mwarning[39m 'makePushClientWithFakeSocket' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync_\ntests\n\\memorySyncService.test.ts[24m[0m\n[0m [2m110:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m266:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m306:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m320:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m370:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m395:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m414:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync\\crypto_\ntests\n\\adapter.test.ts[24m[0m\n[0m [2m26:10[22m [33mwarning[39m 'collectStream' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync\\crypto\\lazyProvider.ts[24m[0m\n[0m [2m31:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m36:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m45:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m64:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync\\dailyFileNotifier.ts[24m[0m\n[0m [2m29:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m60:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m74:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m78:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m97:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync\\handlers\\fileChangeHandler.ts[24m[0m\n[0m [2m8:13[22m [33mwarning[39m 'path' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m34:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\sync\\memorySyncService.ts[24m[0m\n[0m [2m44:7[22m [33mwarning[39m 'MAX_STARTUP_FAILURES' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m116:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m120:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m129:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m162:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m185:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m191:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m204:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m223:31[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m250:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m261:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m272:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m299:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m315:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m318:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-cloud-fusion\\src\\tools\\search\\webSearchTool.ts[24m[0m\n[0m [2m360:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m367:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m375:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src_\ntests\n\\mcpExtensionProvider.test.ts[24m[0m\n[0m [2m55:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m63:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m76:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m88:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m96:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m98:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m101:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m114:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m126:13[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m141:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m148:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src_\ntests\n\\mcpLoadingPipeline.integration.test.ts[24m[0m\n[0m [2m67:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m68:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m75:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m83:31[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m98:13[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m115:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m122:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m124:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m126:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m133:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src_\ntests\n\\providerDiscoveryCache.test.ts[24m[0m\n[0m [2m34:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m35:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m36:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m83:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src_\ntests\n\\toolAdapter.test.ts[24m[0m\n[0m [2m46:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m47:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m48:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m49:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m50:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m51:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m63:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m136:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m137:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m138:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m159:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m159:8[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m171:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m181:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m200:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m200:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m221:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m221:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m222:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src\\cache\\providerDiscoveryCache.ts[24m[0m\n[0m [2m229:47[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src\\mcpExtensionProvider.ts[24m[0m\n[0m [2m379:14[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-mcp\\src\\user\\connectionPool.ts[24m[0m\n[0m [2m53:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-memory\\src\\core\\domains\\sensitivity\\llmClassifier.ts[24m[0m\n[0m [2m50:7[22m [33mwarning[39m 'logger' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-memory\\src\\core\\foundation\\io\\index.ts[24m[0m\n[0m [2m38:13[22m [33mwarning[39m 'fs' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m39:13[22m [33mwarning[39m 'pathMod' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m46:5[22m [33mwarning[39m 'userDataDir' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-memory\\src\\core\\foundation\\telemetry\\trackerTypes.ts[24m[0m\n[0m [2m51:11[22m [33mwarning[39m 'ToolCallParams' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m59:11[22m [33mwarning[39m 'LlmCallParams' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m81:11[22m [33mwarning[39m 'UserCallParams' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-exampleCloud-note-awareness\\src_\ntests\n\\exampleCloudNoteAwareness.test.ts[24m[0m\n[0m [2m21:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m33:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m46:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m57:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m63:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m69:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m80:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\miJiaAssistantClient.ts[24m[0m\n[0m [2m110:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\miotClientManager.ts[24m[0m\n[0m [2m184:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m200:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m221:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m254:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\miotCrypto.ts[24m[0m\n[0m [2m14:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\miotHttpClient.ts[24m[0m\n[0m [2m70:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m [2m76:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m152:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\miotOAuthManager.ts[24m[0m\n[0m [2m13:31[22m [33mwarning[39m 'MiServiceTokenInfo' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m53:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m83:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m101:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m105:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m109:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m114:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\tools\\miotAskAssistantTool.ts[24m[0m\n[0m [2m61:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m64:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m68:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m73:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m78:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m205:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m211:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m234:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\tools\\miotControlDeviceTool.ts[24m[0m\n[0m [2m115:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m119:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-miot\\src\\tools\\miotListDevicesTool.ts[24m[0m\n[0m [2m67:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core_\ntests\n\\router\\skillRouter.test.ts[24m[0m\n[0m [2m88:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m90:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m91:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m98:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m99:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m107:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m109:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m110:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m112:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m113:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m132:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m133:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m134:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m135:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core_\ntests\n_\\router\\stateManager.test.ts[24m[0m\n[0m [2m32:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m33:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m40:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m47:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m53:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m94:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m95:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core_\ntests\n_\\skillProvider.test.ts[24m[0m\n[0m [2m47:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m55:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m152:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m156:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m200:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m220:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m232:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m235:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m239:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m241:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m242:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\foundation\\manifest.ts[24m[0m\n[0m [2m142:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m199:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m205:39[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\intelligence\\categoryAgent.ts[24m[0m\n[0m [2m11:10[22m [33mwarning[39m 'SkillIndex' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m47:5[22m [33mwarning[39m 'existingSkills' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m75:11[22m [33mwarning[39m 'prompt' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\provision\\bundler.ts[24m[0m\n[0m [2m28:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m32:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m33:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m34:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m37:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m48:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m55:37[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m100:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m127:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m129:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m137:43[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m140:38[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m143:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m149:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m181:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m189:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m364:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m408:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m413:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m421:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\provision\\dependencyManager.ts[24m[0m\n[0m [2m55:58[22m [33mwarning[39m Unnecessary escape character: / [2mno-useless-escape[22m[0m\n[0m [2m117:44[22m [33mwarning[39m Unnecessary escape character: / [2mno-useless-escape[22m[0m\n[0m [2m124:55[22m [33mwarning[39m Unnecessary escape character: / [2mno-useless-escape[22m[0m\n[0m [2m146:42[22m [33mwarning[39m Unnecessary escape character: / [2mno-useless-escape[22m[0m\n[0m [2m148:96[22m [33mwarning[39m Unnecessary escape character: / [2mno-useless-escape[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\provision\\provisionFacade.ts[24m[0m\n[0m [2m32:40[22m [33mwarning[39m 'SkillsConfig' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m35:47[22m [33mwarning[39m 'buildSkillEnv' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\provision\\utils.ts[24m[0m\n[0m [2m299:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m299:41[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\provision\\watcher.ts[24m[0m\n[0m [2m2:8[22m [33mwarning[39m 'path' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m52:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m55:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\repertoire\\availableSkillsService.ts[24m[0m\n[0m [2m27:43[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m28:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m32:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m35:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m37:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m45:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\router\\skillRouter.ts[24m[0m\n[0m [2m98:15[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m246:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m273:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m319:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m326:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m329:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m400:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m404:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m419:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m426:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m506:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m512:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m523:13[22m [33mwarning[39m 'skillMeta' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m530:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m548:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m645:21[22m [33mwarning[39m 'sessionId' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m735:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m739:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m749:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m806:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m837:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\router\\stateManager.ts[24m[0m\n[0m [2m49:6[22m [33mwarning[39m 'SkillDefaultConfig' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m51:7[22m [33mwarning[39m 'SKILL_STATE_KEY' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m119:26[22m [33mwarning[39m 'state' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m147:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m170:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m224:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\services\\usageTracker.ts[24m[0m\n[0m [2m45:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\skillFacade.ts[24m[0m\n[0m [2m32:40[22m [33mwarning[39m 'SkillIndex' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m81:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m89:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m105:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:37[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m169:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m173:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m182:9[22m [33mwarning[39m Unexpected lexical declaration in case block [2mno-case-declarations[22m[0m\n[0m [2m183:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m186:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m189:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m236:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m243:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m251:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m263:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m264:127[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m389:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m397:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m405:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-skills\\src\\core\\tools\\skillsManageTool.ts[24m[0m\n[0m [2m47:15[22m [33mwarning[39m 'SkillMeta' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\agentkitFacade.ts[24m[0m\n[0m [2m57:3[22m [33mwarning[39m 'AgentkitTool' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m89:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m100:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\builtin\\search_\ntests\n_\\localSearchTool.test.ts[24m[0m\n[0m [2m6:13[22m [33mwarning[39m 'path' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m47:7[22m [33mwarning[39m 'actualOpts' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m488:23[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m604:23[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m669:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\builtin\\search\\localSearchTool.ts[24m[0m\n[0m [2m78:3[22m [33mwarning[39m 'searchWithSpotlight' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m81:6[22m [33mwarning[39m 'UnifiedSearchResult' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m82:6[22m [33mwarning[39m 'SearchArgs' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m119:10[22m [33mwarning[39m 'formatFileSize' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m134:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m168:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m231:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m252:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m647:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m666:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m670:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m692:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m716:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\builtin\\types.ts[24m[0m\n[0m [2m38:3[22m [33mwarning[39m 'ToolRegistration' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m39:3[22m [33mwarning[39m 'ToolsConfig' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\interceptors\\dedupInterceptor.ts[24m[0m\n[0m [2m83:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\runtime\\executor.ts[24m[0m\n[0m [2m13:3[22m [33mwarning[39m 'InterceptorResult' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\example-ext-tools\\src\\runtime\\registry.ts[24m[0m\n[0m [2m59:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:87[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m108:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m124:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra-dal\\src\\sqlite\\agentSessionStore.ts[24m[0m\n[0m [2m52:16[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m290:45[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m432:43[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra-dal\\src\\sqlite\\mcpStore.ts[24m[0m\n[0m [2m149:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra-dal\\src\\sqlite\\scheduledTaskStore.ts[24m[0m\n[0m [2m213:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m247:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m294:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m418:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m548:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m611:45[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\account.ts[24m[0m\n[0m [2m49:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m79:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m129:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m189:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m219:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m220:14[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m240:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m290:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m308:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m342:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\business-sid-manager.ts[24m[0m\n[0m [2m47:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m48:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m49:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m52:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m53:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m56:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m58:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m75:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m76:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m77:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m78:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m85:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m86:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m88:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m97:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m113:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m114:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m115:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m116:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m118:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m119:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m120:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m121:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m122:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m124:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m128:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m130:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m134:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m135:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m136:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m137:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m147:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m148:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m149:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m151:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m152:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m153:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m158:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m159:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m162:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m175:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m176:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m177:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m182:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m183:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m185:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m197:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m198:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m199:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m203:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m211:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m212:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m213:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m216:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m220:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m224:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\httpDebugLogger.ts[24m[0m\n[0m [2m71:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m97:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m109:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\legacy-importer.ts[24m[0m\n[0m [2m256:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m274:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m319:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m323:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m359:16[22m [33mwarning[39m 'listDatFiles' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m383:19[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m398:17[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m402:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m443:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m462:43[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m470:15[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m477:12[22m [33mwarning[39m 'e' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m547:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m555:15[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m571:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m575:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m579:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m583:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m596:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m620:39[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m658:15[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m718:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m723:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m764:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m795:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m800:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m815:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\report-manager.ts[24m[0m\n[0m [2m53:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m60:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m71:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m90:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m179:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m233:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\service-token-manager.ts[24m[0m\n[0m [2m50:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m55:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m71:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m117:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m178:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m209:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m226:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m335:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m503:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m523:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\user-info.ts[24m[0m\n[0m [2m23:10[22m [33mwarning[39m 'maskSecret' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m30:10[22m [33mwarning[39m 'maskCookieHeader' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m81:13[22m [33mwarning[39m 'nonce' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m439:5[22m [33mwarning[39m 'userId' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\userAgent\\common\\encode.ts[24m[0m\n[0m [2m29:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\userAgent\\index.ts[24m[0m\n[0m [2m62:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\userAgent\\macos\\computerInfo.ts[24m[0m\n[0m [2m24:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m30:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\account\\userAgent\\windows\\computerInfo.ts[24m[0m\n[0m [2m22:15[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m29:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m45:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m56:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m65:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\network\\serviceTokenFetch.ts[24m[0m\n[0m [2m317:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m362:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m370:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m407:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m456:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\cloud-transport\\downloader.ts[24m[0m\n[0m [2m9:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m35:97[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m35:125[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m67:97[22m [33mwarning[39m 'timeout' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m101:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\cloud-transport\\httpClient.ts[24m[0m\n[0m [2m5:10[22m [33mwarning[39m 'normalizeError' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\cloud-transport\\impl.ts[24m[0m\n[0m [2m38:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m61:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\cloud-transport\\queue\\transferQueue.ts[24m[0m\n[0m [2m33:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m37:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\cloud-transport\\uploader.ts[24m[0m\n[0m [2m9:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m35:109[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m35:137[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m68:49[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m84:90[22m [33mwarning[39m 'timeout' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\platform-files\\thumbnail\\thumbnailService.ts[24m[0m\n[0m [2m328:3[22m [33mwarning[39m 'platform' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\search\\index.ts[24m[0m\n[0m [2m85:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m88:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m96:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m106:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m109:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m114:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m121:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\search\\windows\\aiSearch.ts[24m[0m\n[0m [2m14:15[22m [33mwarning[39m 'UnifiedSearchResult' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m43:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m69:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m71:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\infra\\src\\search\\windows\\fqSearch.ts[24m[0m\n[0m [2m20:7[22m [33mwarning[39m 'TAG' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m21:7[22m [33mwarning[39m 'execAsync' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m31:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m33:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\gallery\\sync_\ntests\n\\thumbnailDownloader.test.ts[24m[0m\n[0m [2m74:25[22m [33mwarning[39m 'localPath' is defined but never used. Allowed unused args must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\gallery\\transfer_\ntests\n\\downloadTaskRepo.test.ts[24m[0m\n[0m [2m101:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m102:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m104:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m105:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\gallery\\transfer_\ntests\n\\uploadTaskRepo.test.ts[24m[0m\n[0m [2m73:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m74:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m75:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m76:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m78:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m79:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\gallery\\transfer\\albumUploadManager.ts[24m[0m\n[0m [2m561:79[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m562:79[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m596:166[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m601:166[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\gallery\\transfer\\uploadFile.ts[24m[0m\n[0m [2m376:87[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m473:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m476:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\note\\sync\\DirtyFlusher.ts[24m[0m\n[0m [2m91:43[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m120:43[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\note\\sync\\NoteAttachmentUploader.ts[24m[0m\n[0m [2m115:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\note\\sync\\NoteWriteService.ts[24m[0m\n[0m [2m114:37[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m202:37[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\note\\sync_\ntests\n\\NoteAttachmentDownloader.test.ts[24m[0m\n[0m [2m104:19[22m [33mwarning[39m A\nrequire()\nstyle import is forbidden [2m@typescript-eslint/no-require-imports[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-sdk\\src\\note\\sync_\ntests\n_\\NoteWriteService.e2ee.test.ts[24m[0m\n[0m [2m118:46[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m126:49[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\core\\api\\track.ts[24m[0m\n[0m [2m7:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\core\\devtools\\JsbProtocolPlugin.tsx[24m[0m\n[0m [2m9:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m22:12[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m24:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\core\\lib\\time.ts[24m[0m\n[0m [2m7:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\core\\stores\\user-slice.ts[24m[0m\n[0m [2m19:11[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\core\\types\\electron.d.ts[24m[0m\n[0m [2m8:3[22m [33mwarning[39m 'GalleryItemTupleFromNative' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m9:3[22m [33mwarning[39m 'GalleryOperationFailed' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m10:3[22m [33mwarning[39m 'MediaDetail' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m11:3[22m [33mwarning[39m 'VideoPlayInfo' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m13:15[22m [33mwarning[39m 'TransferItem' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m13:29[22m [33mwarning[39m 'TransferOperationFailed' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\components\\MediaLightbox\\MediaInfoModal.tsx[24m[0m\n[0m [2m81:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m228:30[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m228:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m245:16[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\components\\MediaLightbox\\index.tsx[24m[0m\n[0m [2m134:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'gallery'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m259:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'gallery'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m364:14[22m [33mwarning[39m '\nerror' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\components\\MediaStream\\MarqueeBox.tsx[24m[0m\n[0m [2m39:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\components\\MediaStream\\index.tsx[24m[0m\n[0m [2m539:6[22m [33mwarning[39m React Hook useEffect has an unnecessary dependency: 'virtualListRef.current'. Either exclude it or remove the dependency array. Mutable values like 'virtualListRef.current' aren't valid dependencies because mutating them doesn't re-render the component [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\components\\MediaStream\\utils.ts[24m[0m\n[0m [2m284:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\stores\\gallery-slice.ts[24m[0m\n[0m [2m33:36[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m216:14[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\stores\\transfer-slice.ts[24m[0m\n[0m [2m22:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\gallery\\types\\gallery.d.ts[24m[0m\n[0m [2m64:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\note\\components\\MindMapEditor.tsx[24m[0m\n[0m [2m435:6[22m [33mwarning[39m React Hook useEffect has missing dependencies: 'createDate' and 'modifyDate'. Either include them or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\exampleCloud-ui\\src\\routes\\gallery_layout\\transfer-records.tsx[24m[0m\n[0m [2m270:14[22m [33mwarning[39m '\nerror' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\adapters\\memoryAdapter.ts[24m[0m\n[0m [2m15:13[22m [33mwarning[39m 'path' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\api_\ntests\n\\deviceChatApiEmptyResult.test.ts[24m[0m\n[0m [2m158:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m219:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m253:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\api_\ntests\n_\\groupTaskApiUserAgentSenderTrio.test.ts[24m[0m\n[0m [2m19:31[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\api\\clipboardApi.ts[24m[0m\n[0m [2m126:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m167:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m195:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\api\\groupTaskApi.ts[24m[0m\n[0m [2m497:48[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\awareness_\ntests\n\\AwarenessServerManager.test.ts[24m[0m\n[0m [2m38:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m57:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m59:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m75:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m82:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m90:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m103:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m105:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m118:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m127:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m129:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m131:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m140:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m141:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m142:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m147:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m159:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m160:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m172:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m192:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m255:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m327:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\bootstrap\\a2aBootstrap.ts[24m[0m\n[0m [2m603:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m [2m1055:39[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1056:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\bootstrap\\cli.ts[24m[0m\n[0m [2m394:9[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\bootstrap\\postActionExecutorAdapter.ts[24m[0m\n[0m [2m268:13[22m [33mwarning[39m 'timeoutHandle' is never reassigned. Use 'const' instead [2mprefer-const[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\config\\serverConfigFetcher.ts[24m[0m\n[0m [2m92:55[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\debug\\httpDebugServer.ts[24m[0m\n[0m [2m53:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\debug\\memoryPlaintextService.ts[24m[0m\n[0m [2m118:29[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n\\fileTransferEventBridgeBubbleWriter.test.ts[24m[0m\n[0m [2m10:32[22m [33mwarning[39m 'FileTransferDomainEvent' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m133:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m134:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m135:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m136:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m137:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m139:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m156:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m157:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m204:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m205:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m206:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\fileTransferEventBridgePostActionResult.test.ts[24m[0m\n[0m [2m109:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m160:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m175:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m190:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m206:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m222:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m243:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m262:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\fileTransferGroupChatBridge.test.ts[24m[0m\n[0m [2m138:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m139:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m162:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m163:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m581:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m614:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m615:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m616:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m617:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\receiverEventBridgeCancelPaths.test.ts[24m[0m\n[0m [2m260:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m266:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m269:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m270:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m363:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m369:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m372:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m373:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m450:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m458:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m462:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m463:45[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m467:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m547:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m551:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m552:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m560:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m561:32[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\receiverEventBridgeTaskReceived.test.ts[24m[0m\n[0m [2m256:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\runLocalSubtaskGroupTaskPassthrough.test.ts[24m[0m\n[0m [2m139:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m162:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\runLocalSubtaskLeaderInjection.test.ts[24m[0m\n[0m [2m179:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m212:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events_\ntests\n_\\runSubtaskLeaderInjection.test.ts[24m[0m\n[0m [2m174:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m204:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\events\\receiverEventBridge.ts[24m[0m\n[0m [2m316:50[22m [33mwarning[39m 'accountAllSessionGetter' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m386:49[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\fileRecords\\fileRecordService.ts[24m[0m\n[0m [2m498:61[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\interconnect\\InterconnectService.ts[24m[0m\n[0m [2m372:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m385:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm_\ntests\n_\\llmClient.test.ts[24m[0m\n[0m [2m51:28[22m [33mwarning[39m 'next' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m213:28[22m [33mwarning[39m 'next' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm_\ntests\n_\\modelRegistry.test.ts[24m[0m\n[0m [2m46:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m47:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m48:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m49:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m147:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m148:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m149:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m150:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m169:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m170:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m171:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm_\ntests\n_\\retryMiddlewareOfflineUpgrade.test.ts[24m[0m\n[0m [2m54:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm_\ntests\n_\\toolSceneFilter.test.ts[24m[0m\n[0m [2m79:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m80:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\llmClient.ts[24m[0m\n[0m [2m141:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m185:13[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m186:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m187:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m260:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m294:10[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\llmErrors.ts[24m[0m\n[0m [2m122:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\middleware\\cacheMonitoringMiddleware.ts[24m[0m\n[0m [2m116:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\middleware\\loggingMiddleware.ts[24m[0m\n[0m [2m17:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\middleware\\retryMiddleware.ts[24m[0m\n[0m [2m187:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\promptOrchestrator\\modules_\ntests\n_\\currentTimeModule.test.ts[24m[0m\n[0m [2m9:53[22m [33mwarning[39m 'now' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m51:53[22m [33mwarning[39m 'now' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\promptOrchestrator\\modules_\ntests\n_\\deviceChatModule.test.ts[24m[0m\n[0m [2m17:59[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\promptOrchestrator\\modules_\ntests\n\\interactionDedupModule.test.ts[24m[0m\n[0m [2m13:26[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\promptOrchestrator\\modules\\evergreenMemoryModule.ts[24m[0m\n[0m [2m31:10[22m [33mwarning[39m 'formatEvergreenContents' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\promptOrchestrator\\modules\\languageModules.ts[24m[0m\n[0m [2m2:29[22m [33mwarning[39m 'PromptContext' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\llm\\transport\\example.ts[24m[0m\n[0m [2m73:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1015:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime_\ntests\n\\decideCanSpawnAgent.test.ts[24m[0m\n[0m [2m147:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m163:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime_\ntests\n\\messageBuilder.exampleTranscript.test.ts[24m[0m\n[0m [2m4:49[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m12:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime_\ntests\n\\runtimeSubmitWiring.test.ts[24m[0m\n[0m [2m5:39[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime_\ntests\n\\exampleTranscriptBridge.test.ts[24m[0m\n[0m [2m100:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m102:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\guard_\ntests\n\\rules\\crossDeviceMention.test.ts[24m[0m\n[0m [2m13:59[22m [33mwarning[39m Unexpected use of '_\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\guard_\ntests\n\\rules\\crossDeviceScheduled.test.ts[24m[0m\n[0m [2m9:59[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\guard_\ntests\n\\rules\\deviceChatNoSynthesis.test.ts[24m[0m\n[0m [2m12:59[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\guard_\ntests\n\\rules\\deviceChatOfflineDrift.test.ts[24m[0m\n[0m [2m8:59[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\guard_\ntests\n\\turnEndGuard.test.ts[24m[0m\n[0m [2m10:59[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\exampleAgentRuntime.ts[24m[0m\n[0m [2m92:9[22m [33mwarning[39m 'buildSystemPrompt' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m99:6[22m [33mwarning[39m 'SDKMessage' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m100:6[22m [33mwarning[39m 'QueryEngineConfig' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m101:6[22m [33mwarning[39m 'AppState' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m763:60[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m772:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m772:65[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m928:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m939:15[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m995:75[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1133:40[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1183:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1190:10[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1264:24[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m1300:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m1484:13[22m [33mwarning[39m 'streamingCompleted' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1572:39[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m1577:41[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m2033:50[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2197:20[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\preflightHandler.ts[24m[0m\n[0m [2m76:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\config.ts[24m[0m\n[0m [2m6:30[22m [33mwarning[39m 'SandboxLevel' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\executor\\bashExecutor.ts[24m[0m\n[0m [2m42:269[22m [33mwarning[39m Unnecessary escape character: ` [2mno-useless-escape[22m[0m\n[0m [2m42:280[22m [33mwarning[39m Unnecessary escape character: ` [2mno-useless-escape[22m[0m\n[0m [2m132:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m133:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\executor\\executorFactory.ts[24m[0m\n[0m [2m31:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m35:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\executor\\linuxExecutor.ts[24m[0m\n[0m [2m70:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m265:21[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m270:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\executor\\macosExecutor.ts[24m[0m\n[0m [2m245:13[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\executor\\windowsExecutor.ts[24m[0m\n[0m [2m3:13[22m [33mwarning[39m 'path' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m10:3[22m [33mwarning[39m 'ContainerConfig' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m60:42[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m116:34[22m [33mwarning[39m 'reject' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m205:65[22m [33mwarning[39m 'limits' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\permission\\capabilityAwareInterceptor.ts[24m[0m\n[0m [2m43:9[22m [33mwarning[39m Unexpected lexical declaration in case block [2mno-case-declarations[22m[0m\n[0m [2m59:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m114:9[22m [33mwarning[39m Unexpected lexical declaration in case block [2mno-case-declarations[22m[0m\n[0m [2m136:5[22m [33mwarning[39m 'restrictions' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\permission\\commandAnalyzer.ts[24m[0m\n[0m [2m20:38[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m [2m40:55[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m [2m79:28[22m [33mwarning[39m 'cwd' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\platform\\macos.ts[24m[0m\n[0m [2m209:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m214:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m223:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m224:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m227:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\runtime\\sandbox\\platform\\windows.ts[24m[0m\n[0m [2m8:11[22m [33mwarning[39m 'JobLimits' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m31:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m57:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m71:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m120:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m150:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m159:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m163:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m167:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m174:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m175:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m177:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m196:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m207:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m213:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services_\ntests\n\\extensionProviderRegistry.supportsPostActionResultV1.test.ts[24m[0m\n[0m [2m122:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m123:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services_\ntests\n\\sessionOrchestrator-task-notification.test.ts[24m[0m\n[0m [2m159:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m160:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m161:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m163:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m165:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m166:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m317:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services_\ntests\n\\sessionOrchestrator.listActiveSessions.test.ts[24m[0m\n[0m [2m55:31[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m56:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m56:71[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services\\extensionProviderRegistry.ts[24m[0m\n[0m [2m395:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m421:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services\\promptComposer.ts[24m[0m\n[0m [2m136:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m137:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m138:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services\\sessionOrchestrator.ts[24m[0m\n[0m [2m62:10[22m [33mwarning[39m 'runSessionCompletionHooks' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m62:37[22m [33mwarning[39m 'runNewTurnHooks' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m63:10[22m [33mwarning[39m 'buildDeviceListXmlFromDevices' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m132:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m269:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m289:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m293:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m613:54[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m685:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m689:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m702:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m717:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1106:5[22m [33mwarning[39m 'includeSkillPrompt' is assigned a value but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1168:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2670:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\service\\src\\services\\sessionRunner.ts[24m[0m\n[0m [2m12:65[22m [33mwarning[39m 'StreamEvent' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\App.tsx[24m[0m\n[0m [2m196:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m201:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m205:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m211:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m238:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m366:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\DeviceList.tsx[24m[0m\n[0m [2m152:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m179:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\MarkdownContent.tsx[24m[0m\n[0m [2m8:1[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m10:1[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m12:1[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m16:1[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m18:1[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m236:33[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m236:52[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m255:34[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m266:34[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\account\\AccountInfo.tsx[24m[0m\n[0m [2m31:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m49:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\account\\AccountLoginModal.tsx[24m[0m\n[0m [2m61:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m65:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m74:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m143:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\account\\AccountPage.tsx[24m[0m\n[0m [2m34:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m39:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m43:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m51:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m53:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m56:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m59:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m70:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m76:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m88:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m95:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m98:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m106:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\adaptiveNotification\\AdaptiveNotificationCard.tsx[24m[0m\n[0m [2m80:6[22m [33mwarning[39m React Hook useLayoutEffect has a missing dependency: 'payload'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\AgentInlinePermissionCard.tsx[24m[0m\n[0m [2m694:6[22m [33mwarning[39m React Hook useMemo has a missing dependency: 'question'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\AgentPromptInput.tsx[24m[0m\n[0m [2m538:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m579:6[22m [33mwarning[39m React Hook useCallback has unnecessary dependencies: 'showFolderSelector' and 'workingDirectory'. Either exclude them or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m982:5[22m [33mwarning[39m React Hook useCallback has a missing dependency: 'conversationMode'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\AgentSessionDetail.helpers.ts[24m[0m\n[0m [2m3:35[22m [33mwarning[39m Unexpected control character(s) in regular expression: \\x00, \\x1f [2mno-control-regex[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\AgentSessionDetail.tsx[24m[0m\n[0m [2m400:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'currentSession'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\AgentSessionItem.tsx[24m[0m\n[0m [2m86:9[22m [33mwarning[39m The 'handleTogglePin' function makes the dependencies of useMemo Hook (at line 199) change on every render. Move it inside the useMemo callback. Alternatively, wrap the definition of 'handleTogglePin' in its own useCallback() Hook [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m92:9[22m [33mwarning[39m The 'handleRenameClick' function makes the dependencies of useMemo Hook (at line 199) change on every render. Move it inside the useMemo callback. Alternatively, wrap the definition of 'handleRenameClick' in its own useCallback() Hook [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m126:9[22m [33mwarning[39m The 'handleDeleteClick' function makes the dependencies of useMemo Hook (at line 199) change on every render. Move it inside the useMemo callback. Alternatively, wrap the definition of 'handleDeleteClick' in its own useCallback() Hook [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\FileCardList.tsx[24m[0m\n[0m [2m36:13[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m70:17[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m85:17[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m595:43[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\GroupTaskDeviceBubble.tsx[24m[0m\n[0m [2m139:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\StreamingText.tsx[24m[0m\n[0m [2m160:43[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent_\ntests\n\\agentSessionDetailNavigation.test.ts[24m[0m\n[0m [2m6:56[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent_\ntests\n\\buildMentionRange.test.ts[24m[0m\n[0m [2m60:35[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m60:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m61:35[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m61:53[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m62:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m62:33[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m63:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m64:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent_\ntests\n\\issue267.uiPipeline.test.ts[24m[0m\n[0m [2m107:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m108:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent_\ntests\n\\exampleModeSwitchSync.test.ts[24m[0m\n[0m [2m6:46[22m [33mwarning[39m Unexpected use of '__dirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m8:13[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation\\AssistantTurnBlock.tsx[24m[0m\n[0m [2m365:24[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m404:28[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m437:26[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\ToolCallGroup.test.tsx[24m[0m\n[0m [2m92:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m95:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m99:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m113:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m115:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m118:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m132:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m134:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m137:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m151:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m153:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m156:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m171:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m187:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\agentSessionDetailUsesSharedConversationSource.test.ts[24m[0m\n[0m [2m6:56[22m [33mwarning[39m Unexpected use of '_\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\assistantTurnBlockCompletionSource.test.ts[24m[0m\n[0m [2m6:56[22m [33mwarning[39m Unexpected use of '__dirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m7:61[22m [33mwarning[39m Unexpected use of '_\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\conversationSemanticBoundary.test.ts[24m[0m\n[0m [2m6:82[22m [33mwarning[39m Unexpected use of '_\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\copilotUsesSharedConversationSource.test.ts[24m[0m\n[0m [2m7:13[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m11:13[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m15:13[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m19:13[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation_\ntests\n\\traceModel.test.ts[24m[0m\n[0m [2m152:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\conversation\\assistantTurnModel.ts[24m[0m\n[0m [2m175:62[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m251:48[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m324:43[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m [2m602:57[22m [33mwarning[39m Expected '===' and instead saw '==' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\agent\\hooks_\ntests\n\\useInViewport.test.tsx[24m[0m\n[0m [2m27:10[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\copilot\\CopilotConversation.tsx[24m[0m\n[0m [2m21:9[22m [33mwarning[39m The 'messages' logical expression could make the dependencies of useMemo Hook (at line 69) change on every render. To fix this, wrap the initialization of 'messages' in its own useMemo() Hook [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m21:9[22m [33mwarning[39m The 'messages' logical expression could make the dependencies of useMemo Hook (at line 113) change on every render. To fix this, wrap the initialization of 'messages' in its own useMemo() Hook [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\copilot\\CopilotPanel.tsx[24m[0m\n[0m [2m335:5[22m [33mwarning[39m React Hook useCallback has a missing dependency: 'currentSession'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\fileInfoWindow\\FileInfoWindow.tsx[24m[0m\n[0m [2m66:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m68:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m74:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m76:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\groupChat_\ntests\n\\chatBubbleQuotePassthrough.test.ts[24m[0m\n[0m [2m22:47[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m23:47[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\im\\IMSettings.tsx[24m[0m\n[0m [2m312:133[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m314:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m316:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m322:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m326:91[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m330:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\mcp\\McpServerFormModal.tsx[24m[0m\n[0m [2m210:43[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\myFiles\\FileDetailPanel.tsx[24m[0m\n[0m [2m123:6[22m [33mwarning[39m React Hook useCallback has an unnecessary dependency: 'filePath'. Either exclude it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\onboarding\\BootstrapSessionModal.tsx[24m[0m\n[0m [2m154:6[22m [33mwarning[39m React Hook React.useMemo has a missing dependency: 'currentSession'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m [2m275:6[22m [33mwarning[39m React Hook useEffect has a missing dependency: 'currentSession'. Either include it or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\onboarding\\LoginWaitingModal.tsx[24m[0m\n[0m [2m174:6[22m [33mwarning[39m React Hook useEffect has missing dependencies: 'handleLoginSuccess' and 'startLoginFlow'. Either include them or remove the dependency array [2mreact-hooks/exhaustive-deps[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\onboarding\\OnboardingFlow.tsx[24m[0m\n[0m [2m48:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\components\\unifiedConversation_\ntests\n\\unifiedConversationOptIn.test.ts[24m[0m\n[0m [2m7:8[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m11:8[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\host\\awareness_\ntests\n\\awarenessClient.test.ts[24m[0m\n[0m [2m111:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m139:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m140:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m182:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m183:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m211:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m212:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m229:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m252:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m304:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m305:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services_\ntests\n\\agentViewServiceExampleSync.test.ts[24m[0m\n[0m [2m6:54[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\agent.ts[24m[0m\n[0m [2m148:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m510:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m518:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m542:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m549:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m557:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m674:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\agentViewService.ts[24m[0m\n[0m [2m599:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\debugConfig.ts[24m[0m\n[0m [2m62:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\encryption.ts[24m[0m\n[0m [2m37:12[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m50:14[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m83:12[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m95:12[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\i18n\\index.ts[24m[0m\n[0m [2m37:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m49:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\im.ts[24m[0m\n[0m [2m49:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m60:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m66:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\logger.ts[24m[0m\n[0m [2m40:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m64:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\skill.ts[24m[0m\n[0m [2m167:19[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m169:20[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\theme.ts[24m[0m\n[0m [2m65:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m70:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m97:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\exampleConversationDiagnostics.ts[24m[0m\n[0m [2m32:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\exampleConversationOrchestrator.ts[24m[0m\n[0m [2m276:57[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m276:111[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m424:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m509:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m584:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m604:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m672:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m711:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m730:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m794:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m894:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m999:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1028:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1058:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m1167:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\exampleConversationService.ts[24m[0m\n[0m [2m150:14[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m272:35[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m339:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m460:18[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m600:27[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m679:27[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\services\\exampleVoiceService.ts[24m[0m\n[0m [2m103:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\store\\slices_\ntests\n\\issue267.integration.test.ts[24m[0m\n[0m [2m106:75[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m125:75[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m147:79[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\store\\slices\\agentSlice.ts[24m[0m\n[0m [2m444:27[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\utils\\fileOperations.ts[24m[0m\n[0m [2m21:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m39:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m128:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m177:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\packages\\ui\\src\\utils\\exampleDeviceControlExecutor.ts[24m[0m\n[0m [2m420:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main_\ntests\n_\nmocks\n\\electron.ts[24m[0m\n[0m [2m11:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main_\ntests\n\\awareness-shape.test.ts[24m[0m\n[0m [2m58:28[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main_\ntests\n\\initApp-python-runtime-order.test.ts[24m[0m\n[0m [2m16:27[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main_\ntests\n\\preload-channels.test.ts[24m[0m\n[0m [2m26:46[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m95:15[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\adapters\\orchestratorDepsBuilder.ts[24m[0m\n[0m [2m33:37[22m [33mwarning[39m 'isAISearchAvailable' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m33:58[22m [33mwarning[39m 'isFqSearchAvailable' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m33:79[22m [33mwarning[39m 'searchWithAISearch' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m33:99[22m [33mwarning[39m 'searchWithFqSearch' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m152:3[22m [33mwarning[39m Unnecessary try/catch wrapper [2mno-useless-catch[22m[0m\n[0m [2m191:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m223:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m457:37[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\adapters\\secureStorageAdapter.ts[24m[0m\n[0m [2m90:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m94:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m107:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m163:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m190:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m210:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m214:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\adapters\\skillElectronDelegates.ts[24m[0m\n[0m [2m70:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m73:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\core\\ipc_\ntests\n\\overflowHandler.test.ts[24m[0m\n[0m [2m342:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m368:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\core\\ota\\ExampleOTAProvider.ts[24m[0m\n[0m [2m24:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m31:13[22m [33mwarning[39m 'updateProvider' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m300:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\core\\ota\\autoUpdater.ts[24m[0m\n[0m [2m31:15[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m37:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m93:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\core\\sdk_\ntests\n\\agentSettings.test.ts[24m[0m\n[0m [2m41:15[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m73:15[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\disDeviceAgent\\adapters_\ntests\n\\milestoneObserverBridge.test.ts[24m[0m\n[0m [2m65:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m108:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m181:5[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\handlers\\CrossDeviceTaskNotificationHandler.ts[24m[0m\n[0m [2m102:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m124:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m130:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\deviceHistory.ts[24m[0m\n[0m [2m81:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\interconnect-worker.ts[24m[0m\n[0m [2m52:3[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m70:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m75:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m82:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m151:1[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\interconnectManager.ts[24m[0m\n[0m [2m151:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m180:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m194:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m200:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m206:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m209:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m518:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m535:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m612:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m648:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m696:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m700:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m750:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m752:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m759:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m761:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m769:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m812:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m973:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m977:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1048:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1074:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1083:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\nativeHostLauncher.ts[24m[0m\n[0m [2m87:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m113:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m122:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m205:10[22m [33mwarning[39m 'parseManifest' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m210:10[22m [33mwarning[39m 'fileSha256' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m227:9[22m [33mwarning[39m 'manifestPath' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\sdkAddonBridge.ts[24m[0m\n[0m [2m156:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\sdkWorkerThreadBridge.ts[24m[0m\n[0m [2m93:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m99:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m128:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\windows_\ntests\n\\registryLauncher.test.ts[24m[0m\n[0m [2m6:8[22m [33mwarning[39m 'fs' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\interconnect\\windows\\registryLauncher.ts[24m[0m\n[0m [2m18:16[22m [33mwarning[39m 'verifyDigitalSignature' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc_\ntests\n\\account.test.ts[24m[0m\n[0m [2m128:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\account.ts[24m[0m\n[0m [2m13:9[22m [33mwarning[39m 'BusinessService' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m157:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m161:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m303:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m340:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m349:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m357:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m387:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m388:33[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m430:54[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m469:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m481:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m486:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m498:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m499:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m506:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m518:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m519:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m539:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m551:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m552:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m560:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m572:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m576:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m579:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m586:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m589:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m595:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m618:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m620:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m636:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m640:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m655:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m672:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m684:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m703:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m716:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m722:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m729:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m730:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m754:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m760:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m767:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m808:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m839:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m848:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m862:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m871:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m875:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\agentEventForwarder.ts[24m[0m\n[0m [2m96:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m96:66[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m134:58[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m134:64[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m212:65[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m215:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m409:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\apiProxy.ts[24m[0m\n[0m [2m110:20[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\dialogs.ts[24m[0m\n[0m [2m24:35[22m [33mwarning[39m Unexpected control character(s) in regular expression: \\x00, \\x1f [2mno-control-regex[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\fileDownload.ts[24m[0m\n[0m [2m702:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\fileInfoWindow.ts[24m[0m\n[0m [2m41:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m49:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m55:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m110:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m124:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m130:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m140:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m143:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m148:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m152:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\find.ts[24m[0m\n[0m [2m308:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m408:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m425:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\imageExport.ts[24m[0m\n[0m [2m32:46[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\labs.ts[24m[0m\n[0m [2m330:55[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\mcp.ts[24m[0m\n[0m [2m190:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\exampleCloud.ts[24m[0m\n[0m [2m29:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m32:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m132:48[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\oauth.ts[24m[0m\n[0m [2m76:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\otaIpc.ts[24m[0m\n[0m [2m10:3[22m [33mwarning[39m 'OTAState' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m29:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m86:51[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m [2m118:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m283:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\scheduledTasks.ts[24m[0m\n[0m [2m62:64[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m84:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\sessionFocusTracker.ts[24m[0m\n[0m [2m55:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\ipc\\shell.ts[24m[0m\n[0m [2m37:53[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\libs\\example\\cookie-listener.ts[24m[0m\n[0m [2m26:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m101:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m138:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\libs\\example\\sso.ts[24m[0m\n[0m [2m69:24[22m [33mwarning[39m Promise executor functions should not be async [2mno-async-promise-executor[22m[0m\n[0m [2m84:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m96:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m113:21[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m151:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m159:21[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m168:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m207:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m208:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m209:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m210:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m211:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m214:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m215:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m220:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m221:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m222:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m242:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m243:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m247:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m248:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m253:36[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m253:56[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m254:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m259:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m264:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m265:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m274:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m275:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m276:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m277:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m278:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m281:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m282:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m294:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m295:15[22m [33mwarning[39m 'validationCompleted' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m299:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m304:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m310:23[22m [33mwarning[39m 'token' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m312:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m313:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m330:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m332:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m333:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m334:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m335:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m336:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m337:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m362:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m366:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m368:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m369:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m375:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m377:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m378:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m382:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m407:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m410:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m414:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m418:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m421:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m423:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m428:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m431:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m436:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m440:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m441:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m442:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m470:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m475:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m478:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m481:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m482:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m487:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m495:38[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m495:58[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m497:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m502:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m504:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m508:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m513:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m519:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m523:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m531:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m532:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m542:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m604:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m607:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m661:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m664:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m665:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m670:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m671:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m683:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m687:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m694:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m695:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m727:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m735:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m794:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m817:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m821:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m826:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m830:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m840:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m885:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m894:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m909:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m938:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m946:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m950:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m952:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m955:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m957:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m960:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m963:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m969:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m971:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m984:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m990:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m994:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\libs\\example\\validation-window.ts[24m[0m\n[0m [2m25:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m62:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m63:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m76:77[22m [33mwarning[39m 'line' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m76:83[22m [33mwarning[39m 'sourceId' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m77:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m88:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m107:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m113:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m121:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m126:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m131:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m149:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m159:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m163:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m195:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m240:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m244:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m294:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m355:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m367:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\libs\\example\\webview-window.ts[24m[0m\n[0m [2m133:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m156:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m162:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m187:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m190:18[22m [33mwarning[39m 'err' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m195:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m220:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m301:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m329:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m354:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m364:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m369:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m371:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\main.ts[24m[0m\n[0m [2m10:3[22m [33mwarning[39m 'systemPreferences' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m227:6[22m [33mwarning[39m 'HttpClient' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m228:6[22m [33mwarning[39m 'CryptoUtil' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m276:3[22m [33mwarning[39m 'REMOTE_CONTROL_FILE_TRANSFER' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m303:6[22m [33mwarning[39m 'AgentExampleStateSnapshot' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m304:8[22m [33mwarning[39m 'zlib' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m422:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m422:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m423:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m466:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m557:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m567:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m662:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m663:14[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m819:24[22m [33mwarning[39m 'getPerfLogPath' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m820:10[22m [33mwarning[39m 'EXAMPLE_CLOUD_CHANNELS' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m836:3[22m [33mwarning[39m 'getModelCapabilities' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m881:3[22m [33mwarning[39m 'getEngineDebugLogPath' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m948:15[22m [33mwarning[39m 'IpcOverflowRef' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m949:16[22m [33mwarning[39m 'uuidv4' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m1024:35[22m [33mwarning[39m Unexpected control character(s) in regular expression: \\x00, \\x1f [2mno-control-regex[22m[0m\n[0m [2m1086:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1158:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1175:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1187:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1199:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1408:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1568:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1574:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1663:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1718:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1733:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1863:58[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2268:85[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m2297:10[22m [33mwarning[39m 'registerToolProviders' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m2313:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2455:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2455:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2456:49[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2467:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2474:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2508:32[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m2509:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m2559:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m2956:48[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m2993:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3110:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3191:7[22m [33mwarning[39m 'memoryPlaintextEnabled' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m3238:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3249:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3254:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3259:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3361:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3372:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3376:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3399:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3404:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3409:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3423:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3444:82[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m3480:84[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m3480:94[22m [33mwarning[39m 'source' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m3506:99[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m3524:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3540:103[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m3542:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3550:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3563:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3565:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3573:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3578:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3601:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3603:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3615:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3617:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3620:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3625:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3756:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3933:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m3976:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4071:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4622:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4626:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4733:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4768:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m4779:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5089:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m5127:21[22m [33mwarning[39m 'stdout' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m5149:30[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m5154:21[22m [33mwarning[39m 'stdout' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m5180:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m5293:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5294:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5295:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5305:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5306:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5309:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5315:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5321:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5324:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5334:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5425:20[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m [2m5537:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5574:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5580:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5601:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5605:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5788:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5813:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5841:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5939:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5943:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5947:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5954:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5965:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5969:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5975:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m5996:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6027:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6030:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6042:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6057:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6081:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6108:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6126:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6130:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6157:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6168:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6178:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6191:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6200:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6210:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6217:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6222:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6246:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6254:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6256:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6269:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6271:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6273:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6349:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6351:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6363:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6383:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6495:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6497:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6503:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6508:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6510:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6532:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6571:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6573:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6579:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6596:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6599:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6602:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6605:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6612:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6642:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6656:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6749:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6762:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6784:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6814:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6822:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6851:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6859:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m6877:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7000:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7007:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7009:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7013:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7015:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7023:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7033:17[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7051:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7072:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7093:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7095:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7099:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7114:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7132:42[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m7199:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7203:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7214:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7247:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7297:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7371:21[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m7440:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m7570:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m7571:32[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m7604:44[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m7621:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m7692:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7730:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7853:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7863:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7872:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7881:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7946:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7958:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7962:15[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m7968:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\exampleCloudBridge\\index.ts[24m[0m\n[0m [2m48:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m87:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m141:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m148:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m197:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m222:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\exampleCloudBridge\\exampleCloudInit.ts[24m[0m\n[0m [2m192:28[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\native\\continuity-addon_\ntests\n\\nativeContinuityIM.a2aWire.test.ts[24m[0m\n[0m [2m48:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\native\\continuity-addon_\ntests\n\\nativeContinuityIM.ipc.test.ts[24m[0m\n[0m [2m24:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\native\\continuity-addon\\nativeContinuityIM.ipc.ts[24m[0m\n[0m [2m191:12[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\native\\continuity-addon\\nativeContinuityIM.ts[24m[0m\n[0m [2m132:18[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m134:18[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m136:18[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\notificationBridge_\ntests\n\\notificationBridge.test.ts[24m[0m\n[0m [2m87:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m88:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m89:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m90:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m91:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m92:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m93:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m94:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m105:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m106:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m108:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m109:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m110:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m111:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m126:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m127:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m141:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m156:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m175:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m189:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m203:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m224:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m229:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m229:85[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m230:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m231:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m253:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m273:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m277:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m277:79[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m278:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m279:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m280:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m303:33[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m304:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m304:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform_\ntests\n\\notificationCoordinator.crossDevice.test.ts[24m[0m\n[0m [2m13:62[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m32:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform_\ntests\n\\shellRuntime.test.ts[24m[0m\n[0m [2m142:27[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform_\ntests\n\\systemNotificationManager.crossplatform.test.ts[24m[0m\n[0m [2m86:7[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform_\ntests\n\\systemNotificationManager.test.ts[24m[0m\n[0m [2m7:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m14:37[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m16:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m26:34[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m30:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m34:36[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m108:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m109:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m124:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m125:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m139:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m140:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m161:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m264:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m272:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\agentNotificationDispatcher.ts[24m[0m\n[0m [2m61:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\appUpdateInstaller.ts[24m[0m\n[0m [2m19:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m58:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m74:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m75:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m103:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m115:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m138:58[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m171:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m182:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m220:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m221:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m226:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m251:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m265:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m275:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m288:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m292:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m297:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m300:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m310:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m339:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m342:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m361:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m362:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m363:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m379:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m423:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m431:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\bufferedLogger.ts[24m[0m\n[0m [2m165:27[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m179:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\calendarPermission.ts[24m[0m\n[0m [2m22:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m24:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m30:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m47:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m50:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\harborBashExecutor.ts[24m[0m\n[0m [2m41:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m42:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m54:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\internalApiServer.ts[24m[0m\n[0m [2m68:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m146:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m148:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m162:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m179:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m196:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m252:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m254:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m276:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m278:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m289:14[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m309:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m311:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m391:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\logExport.ts[24m[0m\n[0m [2m44:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m45:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m49:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m70:16[22m [33mwarning[39m 'error' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m75:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m86:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m95:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m100:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m102:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m105:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m107:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m112:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m115:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\logManager.ts[24m[0m\n[0m [2m45:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\logger.ts[24m[0m\n[0m [2m33:31[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m53:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m89:23[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m93:25[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m104:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m117:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m122:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m127:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m139:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m139:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\exampleFileProtocol.ts[24m[0m\n[0m [2m273:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\notificationCoordinator.ts[24m[0m\n[0m [2m2:9[22m [33mwarning[39m 'NotificationPreferencesStore' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m166:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m455:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m536:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m550:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m654:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m677:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m710:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m719:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m725:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m754:34[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m768:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\notificationHistory.ts[24m[0m\n[0m [2m13:11[22m [33mwarning[39m 'NotificationHistoryStore' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m137:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\pythonRuntime.ts[24m[0m\n[0m [2m356:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m374:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m393:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m461:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\scheduler.ts[24m[0m\n[0m [2m5:9[22m [33mwarning[39m 'ScheduledTaskStore' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m8:6[22m [33mwarning[39m 'Schedule' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m56:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m71:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m108:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m125:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m150:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m188:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m197:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m250:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m258:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m295:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m340:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m362:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m408:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m410:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m544:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m611:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\shellRuntime.ts[24m[0m\n[0m [2m68:5[22m [33mwarning[39m 'cachedGitBashResolutionError' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\systemNotificationManager.ts[24m[0m\n[0m [2m404:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m872:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m882:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m913:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m977:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1191:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\systemProxy.ts[24m[0m\n[0m [2m38:78[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m [2m41:79[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\platform\\windowsNativeNotification.ts[24m[0m\n[0m [2m155:9[22m [33mwarning[39m 'timeout' is never reassigned. Use 'const' instead [2mprefer-const[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\services\\serviceInitializer.ts[24m[0m\n[0m [2m31:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m35:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m54:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m60:13[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m69:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m84:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m97:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\storage_\ntests\n\\agentSessionStore.test.ts[24m[0m\n[0m [2m93:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m94:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m163:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m164:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m186:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m220:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m224:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m236:13[22m [33mwarning[39m 'msg2' is assigned a value but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m247:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m248:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m249:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m264:19[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m281:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m311:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m344:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m385:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m386:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m403:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m422:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m459:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m460:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m461:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m539:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m540:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m568:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m571:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m694:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m695:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m696:30[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m710:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m714:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m724:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m734:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m744:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m747:9[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m751:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m752:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m781:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m785:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m794:26[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\storage_\ntests\n\\notificationPreferencesStore.test.ts[24m[0m\n[0m [2m6:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m7:28[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m13:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\storage_\ntests\n\\sqliteStore.test.ts[24m[0m\n[0m [2m20:31[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\telemetry\\memoryTelemetrySink.ts[24m[0m\n[0m [2m31:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\telemetry\\reapplyOtlp.ts[24m[0m\n[0m [2m57:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\types\\jest-globals.d.ts[24m[0m\n[0m [2m2:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m2:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m11:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m11:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m11:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m28:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m29:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m30:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m31:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\utils\\iconResolver.ts[24m[0m\n[0m [2m42:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example_\ntests\n\\contextSyncWiring.test.ts[24m[0m\n[0m [2m22:38[22m [33mwarning[39m Unexpected use of '_\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example_\ntests\n\\conversationOrchestrationSourceGuard.test.ts[24m[0m\n[0m [2m6:24[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m [2m7:24[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example_\ntests\n\\conversationOrchestrationWiring.test.ts[24m[0m\n[0m [2m54:38[22m [33mwarning[39m Unexpected use of '\ndirname'. Use import.meta.dirname (ESM). For tests: use import.meta.dirname or add eslint-disable [2mno-restricted-globals[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example_\ntests\n\\exampleOrchestrator.test.ts[24m[0m\n[0m [2m86:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m86:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example\\exampleHostResolver.ts[24m[0m\n[0m [2m41:27[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m [2m42:27[22m [33mwarning[39m Unnecessary escape character: - [2mno-useless-escape[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example\\exampleManager.ts[24m[0m\n[0m [2m140:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\main\\example\\exampleOrchestrator.ts[24m[0m\n[0m [2m249:11[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m250:38[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m338:54[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m345:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m360:56[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m389:29[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m458:54[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m462:20[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m485:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m492:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m570:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m577:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m589:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m593:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m658:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m662:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\src\\renderer\\main.tsx[24m[0m\n[0m [2m94:1[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m95:1[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m108:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync_\ntests\n\\syncEngine.pushpull.cipher.e2e.test.ts[24m[0m\n[0m [2m17:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m24:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m24:44[22m [33mwarning[39m 'data' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m24:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m25:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m31:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m34:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m35:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m78:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m79:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m80:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m84:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m85:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m95:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m112:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m113:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m117:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m123:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m128:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m129:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\deleteConflict.recentfixes.test.ts[24m[0m\n[0m [2m19:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m29:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m32:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m33:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m75:11[22m [33mwarning[39m 'cloudFile' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m76:75[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m79:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m81:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m82:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m83:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m86:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m86:35[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m96:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m97:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\exampleCrypto.fileScanner.test.ts[24m[0m\n[0m [2m73:72[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m74:75[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\exampleCrypto.syncEngine.test.ts[24m[0m\n[0m [2m54:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m61:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m61:44[22m [33mwarning[39m 'data' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m61:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m62:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m68:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m71:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m72:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m114:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m115:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m115:67[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m119:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m120:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m130:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m148:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m149:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m152:22[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m160:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m161:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\fileScanner.cipher.test.ts[24m[0m\n[0m [2m43:72[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m44:75[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\fileScanner.test.ts[24m[0m\n[0m [2m54:72[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m55:75[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\syncEngine.conflict.test.ts[24m[0m\n[0m [2m21:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m28:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m35:10[22m [33mwarning[39m 'baseRecord' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m63:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m66:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m69:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m70:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m110:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m123:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m124:52[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m128:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m134:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m135:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\syncEngine.pushpull.cipher.test.ts[24m[0m\n[0m [2m11:31[22m [33mwarning[39m 'SyncFileInfo' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m11:45[22m [33mwarning[39m 'SyncCloudFileInfo' is defined but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m17:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m24:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m24:44[22m [33mwarning[39m 'data' is defined but never used. Allowed unused args must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m24:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m25:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m31:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m34:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m35:76[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m77:21[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m78:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m79:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m83:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m84:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m90:11[22m [33mwarning[39m 'absFile' is assigned a value but never used. Allowed unused vars must match /^\n/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m96:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m118:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m [2m119:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m123:15[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m129:17[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m134:70[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m135:73[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\transportBridge.downloadToBuffer.test.ts[24m[0m\n[0m [2m13:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m21:8[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m25:40[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m26:53[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m29:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m30:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m35:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m39:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m43:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m48:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m53:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m61:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m61:87[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m73:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m79:54[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m87:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m91:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m95:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m96:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\transportBridge.test.ts[24m[0m\n[0m [2m8:51[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m12:5[22m [33mwarning[39m Use \"@ts-expect-error\" instead of \"@ts-ignore\", as \"@ts-ignore\" will do nothing if the following line is error-free [2m@typescript-eslint/ban-ts-comment[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\cloudkit-filesync\\watcher.skipPaths.test.ts[24m[0m\n[0m [2m5:10[22m [33mwarning[39m 'EventEmitter' is defined but never used. Allowed unused vars must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m28:25[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m35:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m56:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m56:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m73:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m78:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m78:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m79:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m80:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m89:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m90:17[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m97:72[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m [2m98:75[22m [33mwarning[39m Empty block statement [2mno-empty[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\e2e-pid-tracker.ts[24m[0m\n[0m [2m98:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m105:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m117:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m124:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m134:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m142:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval_\ntests\n\\agent-event-forwarder.test.ts[24m[0m\n[0m [2m44:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m53:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m80:52[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval_\ntests\n\\network-retry-feedback.test.ts[24m[0m\n[0m [2m77:16[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m115:16[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m136:12[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m145:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m146:61[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m187:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m188:61[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m192:36[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m287:10[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval_\ntests\n\\transcript.safeEvaluate.test.ts[24m[0m\n[0m [2m14:21[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m45:26[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\errorLogCollector.ts[24m[0m\n[0m [2m216:14[22m [33mwarning[39m 'idx' is defined but never used. Allowed unused args must match /^_/u [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m [2m220:18[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m221:16[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\llmJudge.ts[24m[0m\n[0m [2m48:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\loader.ts[24m[0m\n[0m [2m87:42[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m89:54[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\passK.ts[24m[0m\n[0m [2m15:33[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m21:68[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\runner.ts[24m[0m\n[0m [2m297:51[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m300:24[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m404:62[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m590:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m591:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m649:36[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m654:22[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m664:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m747:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m757:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m789:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m807:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m879:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m1347:14[22m [33mwarning[39m 'err' is defined but never used [2m@typescript-eslint/no-unused-vars[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\scoring.ts[24m[0m\n[0m [2m756:36[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\spec-utils.ts[24m[0m\n[0m [2m218:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m229:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m237:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m244:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m343:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m354:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m361:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m398:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m453:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m458:36[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m459:36[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m510:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m517:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m521:18[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\eval\\transcript.ts[24m[0m\n[0m [2m117:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m130:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m135:55[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\fixtures\\electron-app.ts[24m[0m\n[0m [2m145:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m145:69[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m164:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m173:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m180:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m197:26[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m197:73[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m211:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m216:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m244:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m260:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m267:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m278:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m372:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m381:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m404:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m429:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m436:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m456:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m458:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m500:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m532:11[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m593:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\fixtures\\mcp-helpers.ts[24m[0m\n[0m [2m114:23[22m [33mwarning[39m Expected '!==' and instead saw '!=' [2meqeqeq[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\global-setup.ts[24m[0m\n[0m [2m90:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m100:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m131:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m137:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m141:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m145:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m156:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m175:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\global-teardown.ts[24m[0m\n[0m [2m26:9[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m40:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m53:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\engine-full-debug.spec.ts[24m[0m\n[0m [2m58:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m74:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m82:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\eval-behavior.spec.ts[24m[0m\n[0m [2m41:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m45:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m73:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m80:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\eval.spec.ts[24m[0m\n[0m [2m44:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m48:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m98:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m105:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\llm-error-visual-regression.spec.ts[24m[0m\n[0m [2m67:65[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m81:34[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m81:54[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m104:72[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m126:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m135:72[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m197:72[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m222:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m231:72[22m [33mwarning[39m The\nFunction\ntype accepts any function-like value.[0m\n[0mPrefer explicitly defining any function parameters and return type [2m@typescript-eslint/no-unsafe-function-type[22m[0m\n[0m [2m254:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m256:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m290:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m291:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\prevent-sleep-toggle.spec.ts[24m[0m\n[0m [2m103:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m112:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m127:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m151:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m163:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\specs\\trace-view.spec.ts[24m[0m\n[0m [2m61:10[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\utils\\cleanSessionResidue.ts[24m[0m\n[0m [2m137:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\utils\\loginStateSync.ts[24m[0m\n[0m [2m276:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m286:7[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m308:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\e2e\\utils\\memorySnapshot.ts[24m[0m\n[0m [2m46:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m72:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\integration\\engine\\helpers\\assertions.ts[24m[0m\n[0m [2m129:55[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\integration\\engine\\helpers\\engineTestHarness.ts[24m[0m\n[0m [2m99:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m100:18[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m108:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m150:59[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m159:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m180:21[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m180:55[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m221:16[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m248:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m260:41[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m270:12[22m [33mwarning[39m Unexpected constant condition [2mno-constant-condition[22m[0m\n[0m [2m275:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m323:29[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m323:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\integration\\engine\\smoke.test.ts[24m[0m\n[0m [2m43:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m57:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m62:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m72:34[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m85:107[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m86:32[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m88:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m95:23[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m96:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m98:20[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m104:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m104:57[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m105:25[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m105:57[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m122:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m131:38[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m148:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m158:35[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m171:37[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m190:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m209:33[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m218:38[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m260:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m316:47[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m331:23[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m332:24[22m [33mwarning[39m Forbidden non-null assertion [2m@typescript-eslint/no-non-null-assertion[22m[0m\n[0m [2m353:19[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m[0m\n[0m[4m/workspace/example-worktree\\0000000000000000\\tests\\test-download-url.ts[24m[0m\n[0m [2m68:27[22m [33mwarning[39m Unexpected any. Specify a different type [2m@typescript-eslint/no-explicit-any[22m[0m\n[0m [2m76:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m122:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m129:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m149:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m155:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m182:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m189:3[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m222:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m223:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m224:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m225:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m226:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m227:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m228:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m229:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m232:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m234:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m235:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m236:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m239:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m241:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m242:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m245:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m247:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m250:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m251:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m252:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m253:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m254:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m255:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m256:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m257:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m258:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m259:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m260:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m261:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m262:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m263:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m264:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m265:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m266:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m267:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m [2m268:5[22m [33mwarning[39m Unexpected console statement [2mno-console[22m[0m\n[0m[0m\n[0m[33m[1m\n✖️\n2726 problems (0 errors, 2726 warnings)[22m[39m[0m\n[0m[33m[1m[22m[39m[0m\n✔️\nNo bare src/ imports in any package.\nOK Example implementation package boundaries are clean.\n✔️\nskill-md-lint: no SKILL.md to check (mode=diff)\n[e2e-ui-contract] OK: new-chat selector main-menu-super-example\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n🧪\nCore tests (npm run test:core)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nexample@0.0.1 pretest:core\nnode scripts/platform/swap-native-abi.mjs node\n[swap-native-abi] Swapped to win node ABI (from cache)\nexample@0.0.1 test:core\nnode scripts/platform/swap-native-abi.mjs node && vitest run src/ui src/app/storage --passWithNoTests && node scripts/platform/swap-native-abi.mjs electron\n[swap-native-abi] Already on win node ABI, no swap needed\n[1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/workspace/example/.codekeeper-worktree/0000000000000000[39m\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mmerges 4 rows → canonical (earliest created_at), reassigns messages, deletes obsolete\n[22m[39m[AccountAllMigration] detected 4 ACCOUNT_ALL session rows, canonical=canon, obsolete=[dup-2,dup-3,dup-4], affectedMessages=6\n[AccountAllMigration] reassigned=4 messages, terminalDedup=0, metaPatched=0, reseq=6, deletedSessions=3\n[AccountAllMigration] completed in 0ms\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mterminal phase dedup: same (taskId,subtaskId,phase) keeps earliest created_at\n[22m[39m[AccountAllMigration] detected 2 ACCOUNT_ALL session rows, canonical=canon, obsolete=[dup], affectedMessages=4\n[AccountAllMigration] reassigned=3 messages, terminalDedup=2, metaPatched=0, reseq=2, deletedSessions=1\n[AccountAllMigration] completed in 0ms\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mreplaces obsolete session ids in metadata (groupChatSessionId / originSessionId)\n[22m[39m[AccountAllMigration] detected 2 ACCOUNT_ALL session rows, canonical=canon, obsolete=[old-stale], affectedMessages=2\n[AccountAllMigration] reassigned=0 messages, terminalDedup=0, metaPatched=2, reseq=2, deletedSessions=1\n[AccountAllMigration] completed in 0ms\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mdry-run mode: rolls back, DB unchanged\n[22m[39m[AccountAllMigration] detected 2 ACCOUNT_ALL session rows, canonical=canon, obsolete=[dup], affectedMessages=2 (DRY-RUN)\n[AccountAllMigration] reassigned=1 messages, terminalDedup=0, metaPatched=0, reseq=2, deletedSessions=1\n[AccountAllMigration] DRY-RUN: rollback without commit\n[AccountAllMigration] dry-run rollback complete in 0ms; DB unchanged\n[90mstderr[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mdry-run mode: rolls back, DB unchanged\n[22m[39m[AccountAllMigration] ensureAccountAllUniqueIndex failed: SqliteError: UNIQUE constraint failed: agent_sessions.device_id\nat Database.exec [90m(/workspace/example-worktree\\0000000000000000\\[39mnode_modules\\[4mbetter-sqlite3[24m\\lib\\methods\\wrappers.js:9:14[90m)[39m\nat ensureAccountAllUniqueIndex (/workspace/example/.codekeeper-worktree/0000000000000000/packages/example-infra-dal/src/sqlite/migrations.ts:166:8)\nat SqliteStore.initialize (/workspace/example/.codekeeper-worktree/0000000000000000/packages/example-infra-dal/src/sqlite/sqliteStore.ts:68:5)\nat SqliteStore.create (/workspace/example/.codekeeper-worktree/0000000000000000/packages/example-infra-dal/src/sqlite/sqliteStore.ts:60:11)\nat /workspace/example/.codekeeper-worktree/0000000000000000/src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts:346:17\nat [90\nmfile:///workspace/example/.codekeeper-worktree/0000000000000000/[39mnode_modules/[4m@vitest/runner[24m/dist/chunk-artifact.js:302:11\nat [90\nmfile:///workspace/example/.codekeeper-worktree/0000000000000000/[39mnode_modules/[4m@vitest/runner[24m/dist/chunk-artifact.js:1903:26\nat [90\nmfile:///workspace/example/.codekeeper-worktree/0000000000000000/[39mnode_modules/[4m@vitest/runner[24m/dist/chunk-artifact.js:2326:20\nat new Promise ()\nat runWithCancel [90m(\nfile:///workspace/example/.codekeeper-worktree/0000000000000000/[39mnode_modules/[4m@vitest/runner[24m/dist/chunk-artifact.js:2323:10[90m)[39m\n{\ncode: [32m'SQLITE_CONSTRAINT_UNIQUE'[39m\n}\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2midempotent: second startup is a no-op (after first run only 1 row)\n[22m[39m[AccountAllMigration] detected 2 ACCOUNT_ALL session rows, canonical=canon, obsolete=[dup], affectedMessages=0\n[AccountAllMigration] reassigned=0 messages, terminalDedup=0, metaPatched=0, reseq=0, deletedSessions=1\n[AccountAllMigration] completed in 0ms\n[90mstdout[2m | src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts[2m > [22m[2mSqliteStore ACCOUNT_ALL migration[2m > [22m[2mpartial unique index prevents inserting second ACCOUNT_ALL row after migration\n[22m[39m[AccountAllMigration] detected 2 ACCOUNT_ALL session rows, canonical=canon, obsolete=[dup], affectedMessages=0\n[AccountAllMigration] reassigned=0 messages, terminalDedup=0, metaPatched=0, reseq=0, deletedSessions=1\n[AccountAllMigration] completed in 0ms\n[32m✓[39m src/app/storage/\ntests\n/sqliteStoreAccountAllMigration.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 161[2mms[22m[39m\n[32m✓[39m src/app/storage/\ntests\n/agentSessionStore.test.ts [2m([22m[2m83 tests[22m[2m)[22m[32m 46[2mms[22m[39m\n[32m✓[39m src/app/storage/\ntests\n/sqliteStore.toolTrust.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 21[2mms[22m[39m\n[32m✓[39m src/app/storage/\ntests\n/sqliteStore.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 10[2mms[22m[39m\n[32m✓[39m src/ui/\ntests\n/electronUiHostClient.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 3[2mms[22m[39m\n[32m✓[39m src/app/storage/\ntests\n/notificationPreferencesStore.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 3[2mms[22m[39m\n[32m✓[39m src/ui/services/\ntests\n/activeSessionReporter.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 2[2mms[22m[39m\n[2m Test Files [22m [1m[32m7 passed[39m[22m[90m (7)[39m\n[2m Tests [22m [1m[32m126 passed[39m[22m[90m (126)[39m\n[2m Start at [22m 14:50:02\n[2m Duration [22m 2.67s[2m (transform 401ms, setup 0ms, import 1.07s, tests 246ms, environment 0ms)[22m\nJUNIT report written to /workspace/example/.codekeeper-worktree/0000000000000000/junit.xml\n[swap-native-abi] Swapped to win electron ABI (from cache)\nexample@0.0.1 posttest:core\nnode scripts/platform/swap-native-abi.mjs electron\n[swap-native-abi] Already on win electron ABI, no swap needed\n❌\nCommit message 不符合 Conventional Commits 规范。\n格式: (): \ntypes: feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert\n当前: 批量修复 1 个 Reviewer 问题\n❓\n需要 Reviewer 澄清:\npackages/example-memory/src/core/memoryFacade.ts:913: 请提供 packages/example-memory/src/core/foundation/telemetry/tracker.ts 文件的内容,以便分析全局 tracker 的当前实现,以及评估三种修复方案对 telemetry 模块的影响。\n生成于 2026/7/28 14:51:09 · CodeKeeper Advance MR 维护 Agent · 维护助手" + } + ] + } +]