Skip to content

fix(build): track startup advisory and reflection sources#132

Open
qq919927036-glitch wants to merge 1 commit intolinuxhsj:mainfrom
qq919927036-glitch:codex/openclaw-build-tracked-sources
Open

fix(build): track startup advisory and reflection sources#132
qq919927036-glitch wants to merge 1 commit intolinuxhsj:mainfrom
qq919927036-glitch:codex/openclaw-build-tracked-sources

Conversation

@qq919927036-glitch
Copy link

@qq919927036-glitch qq919927036-glitch commented Mar 26, 2026

Summary

This PR restores clean-checkout source integrity for the startup-advisory and runtime-reflection path.

It tracks the source modules that were already being imported by command, status, and cron surfaces, but were not yet checked in as source files on the landing branch.

Why this PR is the right landing PR

This stack has three logical layers:

  1. source integrity
  2. failover telemetry
  3. CLI JSON purity

This PR is the first layer. It restores the baseline repository contract that a clean checkout should build from tracked source only.

Without this, later runtime and operator-facing changes can look green in a dirty tree while still failing in clean verification.

Follow-up stack

The follow-up PRs remain in the fork stack for review sequencing:

Problem

The branch could appear to work in a dirty worktree, but clean-checkout builds failed because imports were resolving to files that only existed as untracked local changes.

That breaks the most basic repository contract:

  • a clean checkout should build
  • a tracked import should resolve from tracked source
  • status/context/cron surfaces should not depend on local untracked files

What changed

  • tracks src/agents/runtime-reflection.ts
  • tracks src/agents/startup-advisory.ts
  • tracks src/auto-reply/reply/commands-context-recommend.ts
  • extends src/config/sessions/types.ts with the startup-advisory/task-text contracts those modules require
  • tracks the corresponding tests for the above modules

Validation

Validated in a clean worktree:

pnpm exec vitest run \
  src/agents/runtime-reflection.test.ts \
  src/agents/startup-advisory.test.ts \
  src/auto-reply/reply/commands-context-recommend.test.ts
pnpm exec vitest run src/commands/status.e2e.test.ts
pnpm build

Non-goals

This PR does not:

  • change model failover semantics
  • change CLI JSON stdout routing
  • introduce live self-modification
  • bundle unrelated /memory or operator workflow work

Summary by CodeRabbit

发布说明

  • 新增功能

    • 添加运行时反射系统,用于持久化和检索操作工件,增强可追踪性
    • 实现启动顾问功能,自动分类任务并提供智能上下文建议
    • 支持自动附加策略,根据顾问状态有条件地注入推荐文件
    • 新增上下文推荐命令,以文本或JSON格式返回相关文件建议
  • 测试

    • 新增运行时反射、启动顾问和上下文推荐的完整测试覆盖

@qq919927036-glitch
Copy link
Author

Review note: this is the landing PR for the stack and should be reviewed first. The follow-up stack remains in the fork for sequencing only: PR B qq919927036-glitch#2, then PR C qq919927036-glitch#1. In order: source integrity first, failover telemetry second, JSON purity last.

@coderabbitai
Copy link

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

走查

本提交引入运行时反射持久化、启动建议生成和上下文推荐功能。新增了运行时反射工件的文件系统存储和检索、启动任务分类及路由合约解析、外部推荐执行和缓存管理、后台刷新调度、自动附加策略应用,以及支持的类型定义。总计添加七个新文件和类型扩展。

变更

群组 / 文件 摘要
运行时反射基础设施
src/agents/runtime-reflection.ts, src/agents/runtime-reflection.test.ts
实现反射工件的文件系统持久化和检索,包括日期/表面分层目录结构、去重和验证逻辑、近期记录过滤和排序。导出关键类型(如 RuntimeReflectionRecordRuntimeReflectionSurface)和函数(writeRuntimeReflectionloadRecentRuntimeReflections)。
启动建议生成
src/agents/startup-advisory.ts, src/agents/startup-advisory.test.ts
实现端到端启动建议生成和应用,包括任务文本解析、任务形状分类、外部推荐脚本执行、JSON 验证、磁盘缓存管理和后台刷新调度。支持运行时反射事件发射。导出任务解析、分类、路由合约、推荐获取和建议构建函数。
上下文推荐命令
src/auto-reply/reply/commands-context-recommend.ts, src/auto-reply/reply/commands-context-recommend.test.ts
构建和格式化上下文推荐回复文本或 JSON。包含分数格式化、建议文本生成和错误处理。重新导出 fetchStartupContextRecommendations
会话类型扩展
src/config/sessions/types.ts
新增启动推荐和建议相关的导出类型(如 SessionStartupAdvisorySessionStartupRecommendationFileSessionTaskTextSource)。扩展 SessionSystemPromptReport 以携带建议数据和任务文本特征。

序列图

sequenceDiagram
    participant Client
    participant StartupAdvisory as 启动建议模块
    participant Cache as 磁盘缓存
    participant RecommendScript as 推荐脚本
    participant RuntimeReflection as 运行时反射

    Client->>StartupAdvisory: buildStartupContextAdvisory(taskText)
    
    alt 缓存存在且有效
        StartupAdvisory->>Cache: 读取缓存建议
        Cache-->>StartupAdvisory: 返回缓存建议
        StartupAdvisory->>StartupAdvisory: 标记缓存(ineligibleAutoAttach)
        StartupAdvisory->>StartupAdvisory: 调度后台刷新(异步)
    else 缓存不存在或无效
        StartupAdvisory->>RecommendScript: execFileUtf8(推荐脚本)
        RecommendScript-->>StartupAdvisory: JSON 推荐载荷
        StartupAdvisory->>StartupAdvisory: 验证并解析 JSON
        StartupAdvisory->>Cache: 写入新建议至缓存
        Cache-->>StartupAdvisory: 缓存完成
    end
    
    StartupAdvisory->>RuntimeReflection: writeRuntimeReflection(反射记录)
    RuntimeReflection-->>StartupAdvisory: 反射工件已写入
    
    StartupAdvisory-->>Client: SessionStartupAdvisory(ready/unavailable)
Loading
sequenceDiagram
    participant Client
    participant AutoAttachPolicy as 自动附加策略
    participant Cache as 磁盘缓存
    participant RuntimeReflection as 运行时反射

    Client->>AutoAttachPolicy: applyStartupAutoAttachPolicy(advisory, contextFiles)
    
    alt 建议就绪 & 满足附加条件
        AutoAttachPolicy->>Cache: 读取推荐文件内容
        Cache-->>AutoAttachPolicy: 文件内容
        AutoAttachPolicy->>AutoAttachPolicy: 根据分数/路径过滤文件
        AutoAttachPolicy->>AutoAttachPolicy: 注入至 contextFiles
        AutoAttachPolicy->>AutoAttachPolicy: 更新 autoAttachStatus = 'attached'
    else 缓存建议或源发现
        AutoAttachPolicy->>AutoAttachPolicy: 跳过附加(ineligible)
        AutoAttachPolicy->>AutoAttachPolicy: 更新 autoAttachStatus = 'skipped'
    else 建议不可用
        AutoAttachPolicy->>AutoAttachPolicy: autoAttachStatus = 'unavailable'
    end
    
    AutoAttachPolicy->>RuntimeReflection: writeRuntimeReflection(反射结果)
    RuntimeReflection-->>AutoAttachPolicy: 反射工件已写入
    
    AutoAttachPolicy-->>Client: { advisory, contextFiles }
Loading

代码审查工作量估算

🎯 4 (复杂) | ⏱️ ~75 分钟

🐰 新的反思在磁盘上闪耀,
启动建议智慧绽放,
推荐脚本轻声低唱,
缓存刷新后台翩翩起舞,
兔子庆祝代码的盛宴! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive PR描述提供了清晰的问题陈述、解决方案、验证步骤和非目标说明,但与模板相比缺少多个标准部分。 建议补充:变更类型、作用域、链接问题、用户可见的变更、安全影响、重现和验证、证据、人工验证和向后兼容性信息。
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确地反映了PR的主要变更,即跟踪启动咨询和运行时反射源代码文件以恢复构建完整性。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/agents/startup-advisory.ts (3)

100-129: Fire-and-forget 反射写入会静默吞掉错误。

void writeRuntimeReflection(...).catch(() => {}) 会静默忽略所有写入错误,这可能导致难以诊断的问题。

建议至少记录错误:

🛠️ 建议改进错误处理
   void writeRuntimeReflection({
     surface: "startup_advisory",
     // ...
-  }).catch(() => {});
+  }).catch((error) => {
+    console.warn("[startup-advisory] Failed to emit reflection:", error);
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/startup-advisory.ts` around lines 100 - 129, The fire-and-forget
writeRuntimeReflection call currently swallows all errors via .catch(() => {});
change this to surface and log the error instead so failures are visible — e.g.,
replace .catch(() => {}) with .catch(err =>
processLogger?.error?.("writeRuntimeReflection failed", { surface:
"startup_advisory", entityId, sessionKey: params.sessionKey, err }) ??
console.error("writeRuntimeReflection failed", { surface: "startup_advisory",
entityId, sessionKey: params.sessionKey, err })); ensure you use the existing
writeRuntimeReflection invocation and include entityId/sessionKey/context in the
log.

584-588: Python 回退重试逻辑的条件较为复杂,建议添加注释说明。

当原始执行失败后,重试逻辑会在多种情况下选择使用重试结果。当前条件判断逻辑不够直观:

if (retried.code === 0 || (!retried.stderr && !retried.stdout)) {
  finalResult = retried;
} else if (!result.stderr && !result.stdout) {
  finalResult = retried;
}

建议添加注释说明这些条件的意图,以提高代码可读性。

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

In `@src/agents/startup-advisory.ts` around lines 584 - 588, The conditional
deciding whether to use the retried command result is non-obvious; add concise
inline comments directly above the if/else block referencing retried, result,
and finalResult that explain each branch: state that the first branch chooses
retried when the retry exited successfully (retried.code === 0) or when the
retry produced no stdout/stderr (treat as empty-success edge case), and the
else-if chooses retried when the original result had no stdout/stderr (i.e.,
prefer the retry if the original returned empty output despite non-zero code);
keep comments short and focused so future readers understand the intent of these
specific checks.

1-1287: 文件过大,建议拆分以提高可维护性。

此文件约 1287 行,显著超过编码指南建议的 ~500 LOC(src 目录)或 ~700 LOC(通用)限制。

建议按职责拆分:

  • startup-advisory-types.ts - 类型定义和常量
  • startup-advisory-cache.ts - 缓存读写逻辑
  • startup-advisory-classify.ts - 任务分类和路由合约
  • startup-advisory-auto-attach.ts - 自动附加策略
  • startup-advisory.ts - 主入口和协调逻辑

As per coding guidelines: src/**/*.{ts,tsx}: Aim to keep files under ~500 LOC when feasible (split/refactor as needed)

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

In `@src/agents/startup-advisory.ts` around lines 1 - 1287, This file is too
large—split by responsibility: extract all type definitions and constants (e.g.,
StartupAdvisoryCacheEntry, StartupContextRecommendationPayload,
STARTUP_ADVISORY_CACHE_FILENAME, AUTO_ATTACH_* constants,
STARTUP_TASK_TEXT_MAX_CHARS) into startup-advisory-types.ts; move cache logic
(resolveStartupAdvisoryCachePath, validateStartupAdvisoryCacheEntry,
readStartupAdvisoryCache, persistStartupAdvisoryCache,
scheduleStartupAdvisoryRefresh, startupAdvisoryBackgroundRefreshes,
resetStartupAdvisoryBackgroundRefreshesForTest) into startup-advisory-cache.ts;
move classification/routing logic (classifyStartupTaskShape,
isSourceDiscoveryTask, isSkillRoutingPolicyTask, resolveStartupRouteContract)
into startup-advisory-classify.ts; move auto-attach utilities and policy
(isEligibleAutoAttachPath, isEligiblePolicyAutoAttachPath,
topRecommendationScore, loadAutoAttachCandidate, applyStartupAutoAttachPolicy
and related helpers) into startup-advisory-auto-attach.ts; leave orchestration
and external integration (fetchStartupContextRecommendations,
buildFreshStartupContextAdvisory, buildStartupContextAdvisory,
emitStartupAdvisoryReflection, normalizeTaskTextCandidate,
resolveStartupTaskText, extractLatestUserMessageText) in startup-advisory.ts;
update imports/exports accordingly and ensure shared helpers (e.g.,
buildBootstrapContextFiles, writeRuntimeReflection, execFileUtf8) are imported
from their original modules so tests and callers keep the same public API.
src/agents/runtime-reflection.ts (1)

96-106: 无界循环存在潜在风险。

while (true) 循环依赖 fs.access 抛出异常来退出。虽然实际运行中不太可能出现问题,但建议添加迭代上限作为安全保护:

🛡️ 建议添加迭代上限
+const MAX_UNIQUE_SUFFIX = 1000;
+
 async function resolveUniqueRuntimeReflectionArtifact(record: RuntimeReflectionRecord): Promise<{
   record: RuntimeReflectionRecord;
   path: string;
 }> {
   let nextRecord = record;
   let filePath = resolveRuntimeReflectionPath(nextRecord);
   let suffix = 2;
-  while (true) {
+  while (suffix <= MAX_UNIQUE_SUFFIX) {
     try {
       await fs.access(filePath);
       nextRecord = { ...record, id: `${record.id}-${suffix}` };
       filePath = resolveRuntimeReflectionPath(nextRecord);
       suffix += 1;
     } catch {
       return { record: nextRecord, path: filePath };
     }
   }
+  throw new Error(`Failed to resolve unique path after ${MAX_UNIQUE_SUFFIX} attempts`);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/runtime-reflection.ts` around lines 96 - 106, The infinite loop
using while (true) that relies on fs.access throwing to exit (around the block
that builds nextRecord, filePath, suffix and calls resolveRuntimeReflectionPath)
needs a safety iteration limit: introduce a maxAttempts constant (e.g. 1000),
add a counter that increments each loop, and if counter >= maxAttempts return an
error or throw a clear exception (or return a failure result) instead of looping
forever; keep the existing behavior of returning { record: nextRecord, path:
filePath } when fs.access fails, but ensure the loop also breaks when the
attempt limit is reached.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/agents/runtime-reflection.ts`:
- Around line 4-5: DEFAULT_RUNTIME_REFLECTIONS_ROOT is hard-coded to a
user-specific absolute path which breaks on other machines; change it to derive
from a configurable or project-relative location (e.g., use process.env, a
config value, or path.resolve(__dirname, '..', '..', 'artifacts',
'self-improve')) and update the export so DEFAULT_RUNTIME_REFLECTIONS_ROOT falls
back to a sensible project-relative default when the env/config is not set;
modify the constant definition in runtime-reflection.ts to read from the chosen
config/env and construct the path with Node's path.join/path.resolve instead of
the literal "/Users/lixun/..." string.

In `@src/agents/startup-advisory.ts`:
- Around line 17-18: DEFAULT_RECOMMEND_BIN is a hardcoded, user-specific
absolute path that will break on other machines; change it to load from
configuration or an environment variable (e.g., process.env.RECOMMEND_BIN) with
a sensible relative default resolved at runtime (using path.resolve relative to
__dirname or project root) and fall back with a clear error if missing; update
the reference to DEFAULT_RECOMMEND_BIN in startup-advisory.ts so callers use the
resolved value instead of the literal string.
- Around line 918-930: The function loadAutoAttachCandidate currently does
unnecessary dynamic imports of node:fs/promises and node:path; replace the await
import calls inside loadAutoAttachCandidate with the already statically imported
modules (use the top-level fs/promises import binding and the path binding) so
the function reads the file and derives basename via those existing symbols and
returns the WorkspaceBootstrapFile as before, removing the await
import("node:fs/promises") and await import("node:path") lines.

---

Nitpick comments:
In `@src/agents/runtime-reflection.ts`:
- Around line 96-106: The infinite loop using while (true) that relies on
fs.access throwing to exit (around the block that builds nextRecord, filePath,
suffix and calls resolveRuntimeReflectionPath) needs a safety iteration limit:
introduce a maxAttempts constant (e.g. 1000), add a counter that increments each
loop, and if counter >= maxAttempts return an error or throw a clear exception
(or return a failure result) instead of looping forever; keep the existing
behavior of returning { record: nextRecord, path: filePath } when fs.access
fails, but ensure the loop also breaks when the attempt limit is reached.

In `@src/agents/startup-advisory.ts`:
- Around line 100-129: The fire-and-forget writeRuntimeReflection call currently
swallows all errors via .catch(() => {}); change this to surface and log the
error instead so failures are visible — e.g., replace .catch(() => {}) with
.catch(err => processLogger?.error?.("writeRuntimeReflection failed", { surface:
"startup_advisory", entityId, sessionKey: params.sessionKey, err }) ??
console.error("writeRuntimeReflection failed", { surface: "startup_advisory",
entityId, sessionKey: params.sessionKey, err })); ensure you use the existing
writeRuntimeReflection invocation and include entityId/sessionKey/context in the
log.
- Around line 584-588: The conditional deciding whether to use the retried
command result is non-obvious; add concise inline comments directly above the
if/else block referencing retried, result, and finalResult that explain each
branch: state that the first branch chooses retried when the retry exited
successfully (retried.code === 0) or when the retry produced no stdout/stderr
(treat as empty-success edge case), and the else-if chooses retried when the
original result had no stdout/stderr (i.e., prefer the retry if the original
returned empty output despite non-zero code); keep comments short and focused so
future readers understand the intent of these specific checks.
- Around line 1-1287: This file is too large—split by responsibility: extract
all type definitions and constants (e.g., StartupAdvisoryCacheEntry,
StartupContextRecommendationPayload, STARTUP_ADVISORY_CACHE_FILENAME,
AUTO_ATTACH_* constants, STARTUP_TASK_TEXT_MAX_CHARS) into
startup-advisory-types.ts; move cache logic (resolveStartupAdvisoryCachePath,
validateStartupAdvisoryCacheEntry, readStartupAdvisoryCache,
persistStartupAdvisoryCache, scheduleStartupAdvisoryRefresh,
startupAdvisoryBackgroundRefreshes,
resetStartupAdvisoryBackgroundRefreshesForTest) into startup-advisory-cache.ts;
move classification/routing logic (classifyStartupTaskShape,
isSourceDiscoveryTask, isSkillRoutingPolicyTask, resolveStartupRouteContract)
into startup-advisory-classify.ts; move auto-attach utilities and policy
(isEligibleAutoAttachPath, isEligiblePolicyAutoAttachPath,
topRecommendationScore, loadAutoAttachCandidate, applyStartupAutoAttachPolicy
and related helpers) into startup-advisory-auto-attach.ts; leave orchestration
and external integration (fetchStartupContextRecommendations,
buildFreshStartupContextAdvisory, buildStartupContextAdvisory,
emitStartupAdvisoryReflection, normalizeTaskTextCandidate,
resolveStartupTaskText, extractLatestUserMessageText) in startup-advisory.ts;
update imports/exports accordingly and ensure shared helpers (e.g.,
buildBootstrapContextFiles, writeRuntimeReflection, execFileUtf8) are imported
from their original modules so tests and callers keep the same public API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3bae5f1b-9aaa-4612-9372-f96cea38a809

📥 Commits

Reviewing files that changed from the base of the PR and between c5d85c9 and b9b145e.

📒 Files selected for processing (7)
  • src/agents/runtime-reflection.test.ts
  • src/agents/runtime-reflection.ts
  • src/agents/startup-advisory.test.ts
  • src/agents/startup-advisory.ts
  • src/auto-reply/reply/commands-context-recommend.test.ts
  • src/auto-reply/reply/commands-context-recommend.ts
  • src/config/sessions/types.ts

Comment on lines +4 to +5
export const DEFAULT_RUNTIME_REFLECTIONS_ROOT =
"/Users/lixun/.openclaw/workspace/artifacts/self-improve";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

硬编码的本地路径会导致其他环境构建/运行失败。

DEFAULT_RUNTIME_REFLECTIONS_ROOT 包含用户特定的本地路径 /Users/lixun/.openclaw/workspace/artifacts/self-improve,这在其他开发者机器或 CI 环境中将无法正常工作。

建议使用相对于项目根目录或通过配置解析的路径,例如:

🛠️ 建议修复
-export const DEFAULT_RUNTIME_REFLECTIONS_ROOT =
-  "/Users/lixun/.openclaw/workspace/artifacts/self-improve";
+import { resolveStateDir } from "../config/paths.js";
+
+export const DEFAULT_RUNTIME_REFLECTIONS_ROOT =
+  path.join(resolveStateDir(), "artifacts", "self-improve");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/runtime-reflection.ts` around lines 4 - 5,
DEFAULT_RUNTIME_REFLECTIONS_ROOT is hard-coded to a user-specific absolute path
which breaks on other machines; change it to derive from a configurable or
project-relative location (e.g., use process.env, a config value, or
path.resolve(__dirname, '..', '..', 'artifacts', 'self-improve')) and update the
export so DEFAULT_RUNTIME_REFLECTIONS_ROOT falls back to a sensible
project-relative default when the env/config is not set; modify the constant
definition in runtime-reflection.ts to read from the chosen config/env and
construct the path with Node's path.join/path.resolve instead of the literal
"/Users/lixun/..." string.

Comment on lines +17 to +18
const DEFAULT_RECOMMEND_BIN =
"/Users/lixun/.openclaw/workspace/scripts/pageindex/recommend-startup-context";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

硬编码的本地路径会导致其他环境运行失败。

DEFAULT_RECOMMEND_BIN 包含用户特定路径 /Users/lixun/.openclaw/workspace/scripts/pageindex/recommend-startup-context,这在其他机器上将无法工作。

建议通过配置或相对路径解析:

🛠️ 建议修复
+import { resolveWorkspaceDir } from "./workspace.js";
+
 const DEFAULT_RECOMMEND_BIN =
-  "/Users/lixun/.openclaw/workspace/scripts/pageindex/recommend-startup-context";
+  path.join(resolveWorkspaceDir(), "scripts", "pageindex", "recommend-startup-context");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/startup-advisory.ts` around lines 17 - 18, DEFAULT_RECOMMEND_BIN
is a hardcoded, user-specific absolute path that will break on other machines;
change it to load from configuration or an environment variable (e.g.,
process.env.RECOMMEND_BIN) with a sensible relative default resolved at runtime
(using path.resolve relative to __dirname or project root) and fall back with a
clear error if missing; update the reference to DEFAULT_RECOMMEND_BIN in
startup-advisory.ts so callers use the resolved value instead of the literal
string.

Comment on lines +918 to +930
async function loadAutoAttachCandidate(
file: SessionStartupRecommendationFile,
): Promise<WorkspaceBootstrapFile> {
const fs = await import("node:fs/promises");
const path = await import("node:path");
const content = await fs.readFile(file.path, "utf8");
return {
name: path.basename(file.path),
path: file.path,
content,
missing: false,
};
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

loadAutoAttachCandidate 中的动态导入是不必要的。

文件顶部已经静态导入了 node:fs/promisesnode:path,此处再次动态导入是冗余的:

♻️ 建议使用已导入的模块
 async function loadAutoAttachCandidate(
   file: SessionStartupRecommendationFile,
 ): Promise<WorkspaceBootstrapFile> {
-  const fs = await import("node:fs/promises");
-  const path = await import("node:path");
-  const content = await fs.readFile(file.path, "utf8");
+  const content = await readFile(file.path, "utf8");
   return {
     name: path.basename(file.path),
     path: file.path,
     content,
     missing: false,
   };
 }

As per coding guidelines: Do not mix await import("x") and static import ... from "x" for the same module in production code paths.

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

In `@src/agents/startup-advisory.ts` around lines 918 - 930, The function
loadAutoAttachCandidate currently does unnecessary dynamic imports of
node:fs/promises and node:path; replace the await import calls inside
loadAutoAttachCandidate with the already statically imported modules (use the
top-level fs/promises import binding and the path binding) so the function reads
the file and derives basename via those existing symbols and returns the
WorkspaceBootstrapFile as before, removing the await import("node:fs/promises")
and await import("node:path") lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant