@qxbyte/muse 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -37
- package/dist/cli.js +6610 -1283
- package/dist/cli.js.map +1 -1
- package/dist/index.js +2232 -280
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/llm/providers/openai-compatible.ts","../src/log/index.ts","../src/types/index.ts","../src/llm/client.ts","../src/tools/registry.ts","../src/tools/types.ts","../src/tools/builtin/read.ts","../src/tools/_sensitive.ts","../src/tools/builtin/write.ts","../src/tools/_diff.ts","../src/tools/builtin/edit.ts","../src/tools/builtin/bash.ts","../src/tools/builtin/grep.ts","../src/tools/builtin/glob.ts","../src/tools/builtin/todo.ts","../src/tools/builtin/webfetch.ts","../src/tools/builtin/memory.ts","../src/loop/memory.ts","../src/tools/builtin/ask-user-question.ts","../src/tools/builtin/index.ts","../src/permission/index.ts","../src/session/jsonl.ts","../src/loop/todos.ts","../src/loop/agent.ts","../src/loop/system-prompt.ts","../src/config/loader.ts","../src/config/types.ts","../src/config/_env.ts"],"sourcesContent":["/**\n * OpenAI 兼容协议 provider。\n * 覆盖:OpenAI 官方、DeepSeek、Qwen、Moonshot (Kimi)、智谱、OpenRouter、Ollama (其 /v1 endpoint)、自建 vLLM/LocalAI 等。\n *\n * Why 自己包一层而不是直接用 @ai-sdk/openai-compatible:\n * - 抹平 stream 事件差异,统一为本仓库的 LLMEvent 类型\n * - 在 stream 中拼装 tool_call.arguments(OpenAI 流式 tool_call 是分片增量的 JSON 字符串)\n * - 留口子未来插入降级、重试、token 计数估算\n */\n\nimport { createOpenAICompatible } from \"@ai-sdk/openai-compatible\";\nimport { streamText, jsonSchema, tool, type CoreMessage, type ToolSet } from \"ai\";\nimport type {\n LLMClient,\n LLMEvent,\n ModelCapabilities,\n ProviderConfig,\n StreamOptions,\n} from \"../types.js\";\nimport type { Message, AssistantMessage, ToolDefinition } from \"../../types/index.js\";\nimport { log, redactApiKey } from \"../../log/index.js\";\n\ninterface OpenAICompatibleProviderOpts {\n providerName: string;\n baseUrl: string;\n apiKey: string;\n model: string;\n capabilities?: Partial<ModelCapabilities>;\n}\n\nconst DEFAULT_CAPABILITIES: ModelCapabilities = {\n toolCalling: true,\n parallelToolCalls: true,\n vision: false,\n jsonMode: true,\n maxContextWindow: 32_000,\n};\n\nexport class OpenAICompatibleClient implements LLMClient {\n readonly providerName: string;\n readonly model: string;\n readonly capabilities: ModelCapabilities;\n private modelProvider: ReturnType<ReturnType<typeof createOpenAICompatible>>;\n\n constructor(opts: OpenAICompatibleProviderOpts) {\n this.providerName = opts.providerName;\n this.model = opts.model;\n this.capabilities = { ...DEFAULT_CAPABILITIES, ...opts.capabilities };\n\n const provider = createOpenAICompatible({\n name: opts.providerName,\n baseURL: opts.baseUrl,\n apiKey: opts.apiKey,\n });\n this.modelProvider = provider(opts.model);\n\n log.debug(\"LLM provider initialized\", {\n provider: opts.providerName,\n model: opts.model,\n baseUrl: opts.baseUrl,\n apiKey: redactApiKey(opts.apiKey),\n });\n }\n\n async *stream(opts: StreamOptions): AsyncIterable<LLMEvent> {\n const { messages, tools, systemPrompt, temperature, maxTokens, abortSignal } = opts;\n\n const aiMessages = convertMessages(messages, systemPrompt);\n const aiTools = tools ? convertTools(tools) : undefined;\n\n // 重试:仅在还没收到任何 chunk 时(连接级错误)退避重试,最多 3 次\n let attempt = 0;\n const maxAttempts = 3;\n let result: ReturnType<typeof streamText> | undefined;\n while (true) {\n try {\n result = streamText({\n model: this.modelProvider,\n messages: aiMessages,\n tools: aiTools,\n temperature,\n maxTokens,\n abortSignal,\n });\n break;\n } catch (err) {\n if (abortSignal?.aborted) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n return;\n }\n if (!isRetryable(err) || attempt >= maxAttempts - 1) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n return;\n }\n const delay = 1000 * Math.pow(2, attempt);\n log.warn(`LLM connect failed (attempt ${attempt + 1}/${maxAttempts}); retrying in ${delay}ms`, {\n msg: err instanceof Error ? err.message : String(err),\n });\n await sleep(delay, abortSignal);\n attempt += 1;\n }\n }\n\n if (!result) {\n yield { type: \"error\", error: new Error(\"Internal: stream result is undefined after retry loop.\") };\n return;\n }\n const stream = result.fullStream;\n\n try {\n const seenToolCalls = new Set<string>();\n\n for await (const part of stream) {\n switch (part.type) {\n case \"text-delta\":\n yield { type: \"text\", delta: part.textDelta };\n break;\n\n case \"tool-call\":\n if (!seenToolCalls.has(part.toolCallId)) {\n seenToolCalls.add(part.toolCallId);\n yield { type: \"tool_call_start\", id: part.toolCallId, name: part.toolName };\n }\n yield {\n type: \"tool_call_complete\",\n id: part.toolCallId,\n name: part.toolName,\n args: part.args,\n };\n break;\n\n case \"finish\":\n yield {\n type: \"finish\",\n reason: mapFinishReason(part.finishReason),\n usage: part.usage\n ? {\n inputTokens: part.usage.promptTokens ?? 0,\n outputTokens: part.usage.completionTokens ?? 0,\n totalTokens: part.usage.totalTokens ?? 0,\n }\n : undefined,\n };\n break;\n\n case \"error\":\n yield { type: \"error\", error: part.error instanceof Error ? part.error : new Error(String(part.error)) };\n break;\n\n default:\n // 忽略其它(如 step-start / step-finish / tool-call-streaming-start 等)\n break;\n }\n }\n } catch (err) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n }\n }\n}\n\n// ---------- helpers ----------\n\nfunction convertMessages(messages: Message[], systemPrompt?: string): CoreMessage[] {\n const result: CoreMessage[] = [];\n if (systemPrompt) {\n result.push({ role: \"system\", content: systemPrompt });\n }\n for (const msg of messages) {\n switch (msg.role) {\n case \"system\":\n result.push({ role: \"system\", content: msg.content });\n break;\n case \"user\":\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else {\n const text = msg.content\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\"\\n\");\n result.push({ role: \"user\", content: text });\n }\n break;\n case \"assistant\":\n result.push({ role: \"assistant\", content: convertAssistantContent(msg) });\n break;\n case \"tool\":\n result.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: msg.toolUseId,\n toolName: \"_tool\",\n result: msg.content,\n isError: msg.isError ?? false,\n },\n ],\n });\n break;\n }\n }\n return result;\n}\n\ntype AssistantContent = Extract<CoreMessage, { role: \"assistant\" }>[\"content\"];\n\nfunction convertAssistantContent(msg: AssistantMessage): AssistantContent {\n const parts: Array<\n { type: \"text\"; text: string } | { type: \"tool-call\"; toolCallId: string; toolName: string; args: unknown }\n > = [];\n for (const part of msg.content) {\n if (part.type === \"text\") {\n parts.push({ type: \"text\", text: part.text });\n } else if (part.type === \"tool_use\") {\n parts.push({\n type: \"tool-call\",\n toolCallId: part.id,\n toolName: part.name,\n args: part.args,\n });\n }\n }\n // 至少要有一个内容;空数组 SDK 会报错\n if (parts.length === 0) return \"\";\n return parts as AssistantContent;\n}\n\nfunction convertTools(tools: ToolDefinition[]): ToolSet {\n const result: ToolSet = {};\n for (const t of tools) {\n result[t.name] = tool({\n description: t.description,\n parameters: jsonSchema(t.parameters as Parameters<typeof jsonSchema>[0]),\n });\n }\n return result;\n}\n\nfunction isRetryable(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n const code = (err as Error & { code?: string }).code ?? \"\";\n if (\n code === \"ECONNRESET\" ||\n code === \"ETIMEDOUT\" ||\n code === \"ENOTFOUND\" ||\n code === \"ECONNREFUSED\" ||\n code === \"EAI_AGAIN\"\n ) {\n return true;\n }\n if (\n msg.includes(\"fetch failed\") ||\n msg.includes(\"network\") ||\n msg.includes(\"socket hang up\") ||\n msg.includes(\"under maintenance\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"429\") ||\n msg.includes(\"502\") ||\n msg.includes(\"503\") ||\n msg.includes(\"504\")\n ) {\n return true;\n }\n return false;\n}\n\nasync function sleep(ms: number, abortSignal?: AbortSignal): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n if (abortSignal?.aborted) return reject(new Error(\"aborted\"));\n const t = setTimeout(() => {\n abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"aborted\"));\n };\n abortSignal?.addEventListener(\"abort\", onAbort);\n });\n}\n\nfunction mapFinishReason(reason: string | undefined): \"stop\" | \"tool_calls\" | \"length\" | \"content_filter\" | \"error\" | \"unknown\" {\n switch (reason) {\n case \"stop\":\n case \"stop-sequence\":\n return \"stop\";\n case \"tool-calls\":\n case \"tool_calls\":\n return \"tool_calls\";\n case \"length\":\n return \"length\";\n case \"content-filter\":\n case \"content_filter\":\n return \"content_filter\";\n case \"error\":\n return \"error\";\n default:\n return \"unknown\";\n }\n}\n\n// ---------- 预设 provider 工厂 ----------\n\nexport interface PresetConfig {\n baseUrl: string;\n defaultModel: string;\n capabilities?: Partial<ModelCapabilities>;\n}\n\nexport const PRESETS: Record<string, PresetConfig> = {\n openai: {\n baseUrl: \"https://api.openai.com/v1\",\n defaultModel: \"gpt-4o-mini\",\n },\n deepseek: {\n baseUrl: \"https://api.deepseek.com/v1\",\n defaultModel: \"deepseek-chat\",\n capabilities: { maxContextWindow: 128_000 },\n },\n qwen: {\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n defaultModel: \"qwen-plus\",\n capabilities: { maxContextWindow: 128_000 },\n },\n moonshot: {\n baseUrl: \"https://api.moonshot.cn/v1\",\n defaultModel: \"moonshot-v1-32k\",\n capabilities: { maxContextWindow: 32_000 },\n },\n zhipu: {\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n defaultModel: \"glm-4-flash\",\n capabilities: { maxContextWindow: 128_000 },\n },\n ollama: {\n baseUrl: \"http://localhost:11434/v1\",\n defaultModel: \"llama3.1\",\n capabilities: { maxContextWindow: 8_000 },\n },\n openrouter: {\n baseUrl: \"https://openrouter.ai/api/v1\",\n defaultModel: \"openai/gpt-4o-mini\",\n },\n};\n\nexport function createPresetClient(\n providerName: string,\n config: ProviderConfig,\n model?: string,\n): OpenAICompatibleClient {\n const preset = PRESETS[providerName];\n if (!preset) {\n throw new Error(`Unknown provider preset: ${providerName}. Available: ${Object.keys(PRESETS).join(\", \")}`);\n }\n return new OpenAICompatibleClient({\n providerName,\n baseUrl: (config.baseUrl as string | undefined) ?? preset.baseUrl,\n apiKey: (config.apiKey as string | undefined) ?? \"\",\n model: model ?? preset.defaultModel,\n capabilities: preset.capabilities,\n });\n}\n","/**\n * Logger 包装。第一版用最朴素的 console + 文件追加;后期可替换 pino。\n * Why 不直接用 pino: 简化首版依赖图,等可观测性章节再上 pino。\n */\n\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LEVELS: Record<LogLevel, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n};\n\ninterface LogEntry {\n time: string;\n level: LogLevel;\n msg: string;\n [key: string]: unknown;\n}\n\nclass Logger {\n private level: LogLevel = \"info\";\n private logPath: string;\n private fileEnabled = true;\n\n constructor() {\n const date = new Date().toISOString().slice(0, 10);\n this.logPath = join(homedir(), \".muse\", \"logs\", `${date}.jsonl`);\n try {\n mkdirSync(dirname(this.logPath), { recursive: true });\n } catch {\n this.fileEnabled = false;\n }\n }\n\n setLevel(level: LogLevel) {\n this.level = level;\n }\n\n private write(level: LogLevel, msg: string, extra?: Record<string, unknown>) {\n if (LEVELS[level] < LEVELS[this.level]) return;\n const entry: LogEntry = {\n time: new Date().toISOString(),\n level,\n msg,\n ...extra,\n };\n if (this.fileEnabled) {\n try {\n appendFileSync(this.logPath, JSON.stringify(entry) + \"\\n\");\n } catch {\n // 落盘失败不阻断主流程\n }\n }\n // 仅 warn/error 默认输出到 stderr,避免污染 stdout\n if (level === \"warn\" || level === \"error\") {\n const prefix = level === \"error\" ? \"[error]\" : \"[warn]\";\n process.stderr.write(`${prefix} ${msg}\\n`);\n }\n }\n\n trace(msg: string, extra?: Record<string, unknown>) { this.write(\"trace\", msg, extra); }\n debug(msg: string, extra?: Record<string, unknown>) { this.write(\"debug\", msg, extra); }\n info(msg: string, extra?: Record<string, unknown>) { this.write(\"info\", msg, extra); }\n warn(msg: string, extra?: Record<string, unknown>) { this.write(\"warn\", msg, extra); }\n error(msg: string, extra?: Record<string, unknown>) { this.write(\"error\", msg, extra); }\n}\n\nexport const log = new Logger();\n\n/** API key 脱敏:前 4 后 4,中间打码。 */\nexport function redactApiKey(key: string | undefined): string {\n if (!key) return \"<unset>\";\n if (key.length <= 12) return \"***\";\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","/**\n * 全局共享类型。其它模块按需 re-export 子集。\n * Why 集中:避免类型循环依赖。\n */\n\n// ---------- 消息(与 LLM 交互的最小单元)----------\n\nexport type MessageRole = \"system\" | \"user\" | \"assistant\" | \"tool\";\n\nexport interface TextPart {\n type: \"text\";\n text: string;\n}\n\nexport interface ToolUsePart {\n type: \"tool_use\";\n id: string;\n name: string;\n args: unknown;\n}\n\nexport interface ToolResultPart {\n type: \"tool_result\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n}\n\nexport type ContentPart = TextPart | ToolUsePart | ToolResultPart;\n\nexport interface SystemMessage {\n role: \"system\";\n content: string;\n}\n\nexport interface UserMessage {\n role: \"user\";\n content: string | ContentPart[];\n}\n\nexport interface AssistantMessage {\n role: \"assistant\";\n content: ContentPart[];\n}\n\nexport interface ToolMessage {\n role: \"tool\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n /** Unified diff for UI display only (Write/Edit). Not sent to LLM. */\n diff?: string;\n /** UI-only one-line summary; if absent, UI falls back to content first line. */\n summary?: string;\n /** UI-only status dot color: success(green) / error(red) / warn(yellow). Default derived from isError. */\n kind?: \"success\" | \"error\" | \"warn\";\n /** 产生该结果的工具名;UI 据此做工具专属渲染(如 TodoWrite 隐藏结果行)。 */\n toolName?: string;\n}\n\nexport type Message = SystemMessage | UserMessage | AssistantMessage | ToolMessage;\n\n// ---------- LLM 工具定义(暴露给模型)----------\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>; // JSON Schema\n}\n\n// ---------- Token 用量 ----------\n\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n}\n\nexport type FinishReason = \"stop\" | \"tool_calls\" | \"length\" | \"content_filter\" | \"error\" | \"unknown\";\n\n// ---------- 错误 ----------\n\nexport class MuseError extends Error {\n constructor(message: string, public readonly code?: string, public readonly cause?: unknown) {\n super(message);\n this.name = \"MuseError\";\n }\n}\n\nexport class ToolError extends MuseError {\n constructor(message: string, public readonly toolName: string, cause?: unknown) {\n super(message, \"TOOL_ERROR\", cause);\n this.name = \"ToolError\";\n }\n}\n\nexport class PermissionDeniedError extends MuseError {\n constructor(public readonly toolName: string, public readonly reason: string) {\n super(`Permission denied for ${toolName}: ${reason}`, \"PERMISSION_DENIED\");\n this.name = \"PermissionDeniedError\";\n }\n}\n","/**\n * LLMClient 工厂:根据配置创建对应 provider 的客户端。\n *\n * 当前只实现 openai-compatible 协议族(覆盖 95% 国产模型 + OpenAI 本身)。\n * Anthropic 走自己的协议,留待 v0.3 加。\n */\n\nimport { createPresetClient, PRESETS, OpenAICompatibleClient } from \"./providers/index.js\";\nimport type { LLMClient, ModelCapabilities, ProviderConfig } from \"./types.js\";\nimport { MuseError } from \"../types/index.js\";\nimport type { ModelEntry } from \"../config/models.js\";\n\nexport interface CreateClientOpts {\n provider: string;\n model: string;\n providers: Record<string, ProviderConfig>;\n}\n\n/**\n * 当前 active model 的 apiKey 注入到此进程 env 字段下。\n *\n * 业务代码(LLM client)只看到 env name,不直接持有 key 副本。\n * /models 切换或启动加载时由 setActiveModelEnv() 写入;从这里读出来给 client。\n */\nexport const ACTIVE_API_KEY_ENV = \"MUSE_ACTIVE_API_KEY\";\n\n/** 把 entry 的 apiKey 注入 process.env,供 createLLMClientFromModelEntry 读取。 */\nexport function setActiveModelEnv(entry: ModelEntry): void {\n if (entry.apiKey) {\n process.env[ACTIVE_API_KEY_ENV] = entry.apiKey;\n } else {\n delete process.env[ACTIVE_API_KEY_ENV];\n }\n}\n\n/**\n * 从用户在 models.local.json 里定义的 ModelEntry 构造 LLMClient。\n *\n * apiKey 不直接传值——而是从 process.env[ACTIVE_API_KEY_ENV] 读,调用前必须先\n * setActiveModelEnv(entry) 写入。这样业务代码只看到 env name,不直接持有 key。\n *\n * vendor 字段仅用于显示(providerName 显示在 banner / /status)。\n * 当前所有 entry 走 openai-compatible 协议;未来引入其他协议时按 entry.protocol 分流。\n */\nexport function createLLMClientFromModelEntry(entry: ModelEntry): LLMClient {\n const apiKey = process.env[ACTIVE_API_KEY_ENV] ?? \"\";\n if (!apiKey && !entry.baseUrl.includes(\"localhost\")) {\n throw new MuseError(buildMissingKeyMessage(entry), \"MISSING_API_KEY\");\n }\n const capabilities: Partial<ModelCapabilities> = {};\n if (entry.supportsToolCall !== undefined) capabilities.toolCalling = entry.supportsToolCall;\n if (entry.supportsImages !== undefined) capabilities.vision = entry.supportsImages;\n if (entry.contextWindow !== undefined) capabilities.maxContextWindow = entry.contextWindow;\n\n return new OpenAICompatibleClient({\n providerName: entry.vendor ?? \"custom\",\n baseUrl: entry.baseUrl,\n apiKey,\n model: entry.id,\n capabilities,\n });\n}\n\n/**\n * 用户向报错:当 apiKey 是 ${VAR} 占位符但 VAR 没设时,告诉用户具体缺哪个 env var\n * 和三种修复方式;不是占位符 / 直接缺字段时退化为通用提示。\n */\nfunction buildMissingKeyMessage(entry: ModelEntry): string {\n const envVars = ((entry as { _apiKeyEnvVars?: string[] })._apiKeyEnvVars ?? []).filter(\n (v) => !process.env[v],\n );\n const head = `Model \"${entry.id}\" needs an API key but none was found.`;\n\n if (envVars.length > 0) {\n const list = envVars.map((v) => `$${v}`).join(\", \");\n const fixVar = envVars[0];\n return [\n head,\n ``,\n `Cause: ~/.muse/models.local.json sets apiKey to a placeholder referencing ${list},`,\n ` but the shell environment does not have ${envVars.length > 1 ? \"those variables\" : \"that variable\"} set.`,\n ``,\n `Fix (pick one):`,\n ` 1. Replace the \\${${fixVar}} placeholder in ~/.muse/models.local.json with the literal key`,\n ` (recommended — the file is local-only and never enters git).`,\n ` 2. Export the variable in your shell:`,\n ` export ${fixVar}=<your-key>`,\n ].join(\"\\n\");\n }\n\n return [\n head,\n ``,\n `Edit ~/.muse/models.local.json and set \"apiKey\" on the \"${entry.id}\" entry`,\n `(plain text is fine — the file stays local-only).`,\n ].join(\"\\n\");\n}\n\nexport function createLLMClient(opts: CreateClientOpts): LLMClient {\n const { provider, model, providers } = opts;\n const config = providers[provider];\n\n if (!config) {\n throw new MuseError(\n `Provider \"${provider}\" is not configured. Add a \"providers.${provider}\" entry to your settings.json.`,\n \"PROVIDER_NOT_CONFIGURED\",\n );\n }\n\n // 预设 provider(含国产模型)\n if (PRESETS[provider]) {\n if (!config.apiKey && provider !== \"ollama\") {\n throw new MuseError(\n `Provider \"${provider}\" requires apiKey. Set it in settings.json or via the corresponding env var.`,\n \"MISSING_API_KEY\",\n );\n }\n return createPresetClient(provider, config, model);\n }\n\n // 自定义 openai-compatible 端点\n if (config.baseUrl) {\n return new OpenAICompatibleClient({\n providerName: provider,\n baseUrl: config.baseUrl as string,\n apiKey: (config.apiKey as string | undefined) ?? \"\",\n model,\n });\n }\n\n throw new MuseError(\n `Unknown provider \"${provider}\". Either use a preset (${Object.keys(PRESETS).join(\", \")}) or set \"baseUrl\" in providers.${provider}.`,\n \"UNKNOWN_PROVIDER\",\n );\n}\n","/**\n * 工具注册中心:管理所有可用工具,提供查询、调用、转 LLM-tool-definition 的能力。\n */\n\nimport { z } from \"zod\";\nimport type { AnyTool, ToolContext, ToolExecuteResult } from \"./types.js\";\nimport type { ToolDefinition as LLMToolDefinition } from \"../types/index.js\";\nimport { ToolError } from \"../types/index.js\";\n\n/** zod schema → JSON Schema (subset)。仅覆盖 v0.1 需要的类型。 */\nfunction zodToJsonSchema(schema: z.ZodType<unknown>): Record<string, unknown> {\n const def = (schema as unknown as { _def: { typeName: string } })._def;\n\n if (def.typeName === \"ZodObject\") {\n const shape = (schema as unknown as z.ZodObject<Record<string, z.ZodTypeAny>>).shape;\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = zodToJsonSchema(value as z.ZodType<unknown>);\n if (!(value as unknown as { isOptional?: () => boolean }).isOptional?.()) {\n required.push(key);\n }\n }\n return {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n additionalProperties: false,\n };\n }\n\n if (def.typeName === \"ZodString\") {\n const d = def as unknown as { description?: string };\n return { type: \"string\", ...(d.description ? { description: d.description } : {}) };\n }\n\n if (def.typeName === \"ZodNumber\") {\n return { type: \"number\" };\n }\n\n if (def.typeName === \"ZodBoolean\") {\n return { type: \"boolean\" };\n }\n\n if (def.typeName === \"ZodArray\") {\n const inner = (def as unknown as { type: z.ZodType<unknown> }).type;\n return { type: \"array\", items: zodToJsonSchema(inner) };\n }\n\n if (def.typeName === \"ZodOptional\" || def.typeName === \"ZodDefault\") {\n const inner = (def as unknown as { innerType: z.ZodType<unknown> }).innerType;\n return zodToJsonSchema(inner);\n }\n\n if (def.typeName === \"ZodEnum\") {\n const values = (def as unknown as { values: string[] }).values;\n return { type: \"string\", enum: values };\n }\n\n if (def.typeName === \"ZodUnion\") {\n const opts = (def as unknown as { options: z.ZodType<unknown>[] }).options;\n return { anyOf: opts.map(zodToJsonSchema) };\n }\n\n // Fallback: 任意类型\n return {};\n}\n\nfunction getDescription(schema: z.ZodType<unknown>): string | undefined {\n return (schema as unknown as { description?: string }).description;\n}\n\nexport class ToolRegistry {\n private tools = new Map<string, AnyTool>();\n\n register(tool: AnyTool): void {\n if (this.tools.has(tool.name)) {\n throw new Error(`Tool \"${tool.name}\" already registered.`);\n }\n this.tools.set(tool.name, tool);\n }\n\n registerAll(tools: AnyTool[]): void {\n for (const tool of tools) this.register(tool);\n }\n\n get(name: string): AnyTool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): AnyTool[] {\n return Array.from(this.tools.values());\n }\n\n /** 转为 LLM 可读的 tool definition 数组。可选 filter(如 plan 模式过滤只读工具)。 */\n toLLMDefinitions(filter?: (tool: AnyTool) => boolean): LLMToolDefinition[] {\n let tools = this.list();\n if (filter) tools = tools.filter(filter);\n return tools.map((t) => {\n const schema = zodToJsonSchema(t.parameters);\n // 顶层描述:从 zod schema 的 .describe 拿\n const desc = getDescription(t.parameters);\n if (desc && typeof schema === \"object\" && schema !== null) {\n (schema as Record<string, unknown>).description = desc;\n }\n return {\n name: t.name,\n description: t.description,\n parameters: schema,\n };\n });\n }\n\n /** 调用工具:校验参数 → 执行。 */\n async execute(name: string, rawArgs: unknown, ctx: ToolContext): Promise<ToolExecuteResult> {\n const tool = this.tools.get(name);\n if (!tool) {\n throw new ToolError(`Tool \"${name}\" not found.`, name);\n }\n const parseResult = tool.parameters.safeParse(rawArgs);\n if (!parseResult.success) {\n return {\n content: `Invalid arguments for ${name}: ${parseResult.error.message}`,\n isError: true,\n };\n }\n try {\n return await tool.execute(parseResult.data, ctx);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { content: `Tool ${name} threw: ${msg}`, isError: true };\n }\n }\n}\n","/**\n * 工具系统类型。\n * 内置工具与 MCP 工具都遵循同一接口。\n */\n\nimport type { z } from \"zod\";\nimport type { TodoStore } from \"../loop/todos.js\";\nimport type { AskQuestion, AskQuestionResponse } from \"./builtin/ask-user-question.js\";\n\nexport type PermissionLevel = \"read\" | \"write\" | \"execute\" | \"network\";\n\nexport interface ToolContext {\n cwd: string;\n abortSignal?: AbortSignal;\n /** 询问用户对该工具调用的批准。返回 true=允许,false=拒绝。 */\n askPermission: (toolName: string, args: unknown, summary: string) => Promise<boolean>;\n /** 主代理可能想在工具内部发起子任务,预留口子。 */\n invokeSubagent?: (prompt: string) => Promise<string>;\n /** Session 内 todo 清单(TodoWrite 写入;system prompt 读取注入下一轮)。 */\n todos?: TodoStore;\n /**\n * AskUserQuestion 工具用:一次性弹出整批选择题(链式 tab UI)。\n * 返回数组与入参 questions 等长;Esc 取消时所有项 cancelled=true。\n */\n askQuestions?: (questions: AskQuestion[]) => Promise<AskQuestionResponse[]>;\n}\n\nexport interface ToolExecuteResult {\n /** 给 LLM 看的文本结果。 */\n content: string;\n /** 标记为错误:让 LLM 知道需要修复。 */\n isError?: boolean;\n /** 给 TUI 展示的摘要(一行)。 */\n summary?: string;\n /** Unified diff(Write/Edit 等改文件工具填),交给 UI 渲染绿/红行;不进 LLM 上下文。 */\n diff?: string;\n /** 状态点颜色(仅 UI):success 绿 / error 红 / warn 黄。不填则由 isError 推断。 */\n kind?: \"success\" | \"error\" | \"warn\";\n}\n\nexport interface ToolDefinition<TArgs = unknown> {\n name: string;\n description: string;\n /** zod schema 用于参数校验 + 自动转 JSON Schema。 */\n parameters: z.ZodType<TArgs>;\n /** 权限级别:UI 与 permission 模块据此决定 ask/allow/deny。 */\n permission: PermissionLevel;\n /** 一行摘要,给 TUI 在 \"→ ToolName(...)\" 之后显示。 */\n summarize?: (args: TArgs) => string;\n /** 实际执行函数。 */\n execute: (args: TArgs, ctx: ToolContext) => Promise<ToolExecuteResult>;\n}\n\n/** 类型擦除后的工具,用于 registry 存储 / 调用。 */\nexport interface AnyTool {\n name: string;\n description: string;\n parameters: z.ZodType<unknown>;\n permission: PermissionLevel;\n summarize?: (args: unknown) => string;\n execute: (args: unknown, ctx: ToolContext) => Promise<ToolExecuteResult>;\n}\n\nexport function defineTool<TArgs>(def: ToolDefinition<TArgs>): AnyTool {\n return {\n name: def.name,\n description: def.description,\n parameters: def.parameters as z.ZodType<unknown>,\n permission: def.permission,\n summarize: def.summarize as ((args: unknown) => string) | undefined,\n execute: def.execute as (args: unknown, ctx: ToolContext) => Promise<ToolExecuteResult>,\n };\n}\n","/**\n * Read 工具:读取本地文件,支持 offset/limit 分页。\n * 返回带行号的 `cat -n` 格式,方便 LLM 引用具体行做编辑。\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { ToolError } from \"../../types/index.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst ReadArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n offset: z.number().int().min(0).optional().describe(\"Line offset (0-based).\"),\n limit: z.number().int().positive().optional().describe(\"Max lines to read. Default 2000.\"),\n});\n\nconst DEFAULT_LIMIT = 2000;\nconst MAX_LINE_LENGTH = 2000; // 单行超长时截断\n\nexport const ReadTool = defineTool({\n name: \"Read\",\n description: \"Read a file from the local filesystem. Returns content with 1-indexed line numbers (cat -n format). Use offset/limit for large files.\",\n parameters: ReadArgs,\n permission: \"read\",\n summarize: (args) => `Read(${args.file_path}${args.offset != null ? `, offset=${args.offset}` : \"\"}${args.limit != null ? `, limit=${args.limit}` : \"\"})`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let info;\n try {\n info = await stat(path);\n } catch (err) {\n throw new ToolError(`File not found: ${path}`, \"Read\", err);\n }\n\n if (!info.isFile()) {\n throw new ToolError(`Not a regular file: ${path}`, \"Read\");\n }\n\n const content = await readFile(path, \"utf-8\");\n const lines = content.split(/\\r?\\n/);\n const offset = args.offset ?? 0;\n const limit = args.limit ?? DEFAULT_LIMIT;\n const slice = lines.slice(offset, offset + limit);\n\n const numbered = slice.map((line, i) => {\n const lineNo = offset + i + 1;\n const truncated = line.length > MAX_LINE_LENGTH ? line.slice(0, MAX_LINE_LENGTH) + \"... [truncated]\" : line;\n return `${String(lineNo).padStart(5, \" \")}\\t${truncated}`;\n });\n\n let result = numbered.join(\"\\n\");\n if (offset + limit < lines.length) {\n result += `\\n... [${lines.length - offset - limit} more lines, use offset=${offset + limit} to read next]`;\n }\n\n return {\n content: result || \"(empty file)\",\n summary: `Read ${slice.length} lines from ${args.file_path}`,\n };\n },\n});\n","/**\n * 敏感文件路径默认 deny。设计文档 §12.3。\n *\n * 工具层做硬拦截(不通过 PermissionGate)。即使 settings.permissions.allow 加了 Read/Write,\n * 这层也兜底;用户要绕过必须在 PermissionGate 之外显式同意(v1.0 才考虑)。\n *\n * 规则:\n * - ~/.ssh (SSH 私钥 / known_hosts)\n * - ~/.aws (AWS 凭证)\n * - ~/.gnupg (GPG 私钥)\n * - ~/.kube/config (集群 token)\n * - .env / .env.* (任何位置的环境文件)\n * - id_rsa / id_ed25519 等私钥文件名\n */\n\nimport { homedir } from \"node:os\";\nimport { basename, resolve } from \"node:path\";\n\nconst HOME = homedir();\nconst SENSITIVE_DIRS = [\n resolve(HOME, \".ssh\"),\n resolve(HOME, \".aws\"),\n resolve(HOME, \".gnupg\"),\n resolve(HOME, \".config\", \"gh\"),\n];\nconst SENSITIVE_FILES = [\n resolve(HOME, \".kube\", \"config\"),\n resolve(HOME, \".netrc\"),\n resolve(HOME, \".pypirc\"),\n];\nconst SENSITIVE_BASENAMES = new Set([\n \"id_rsa\",\n \"id_ed25519\",\n \"id_ecdsa\",\n \"id_dsa\",\n]);\nconst ENV_PATTERN = /(?:^|\\/)\\.env(\\..+)?$/;\n\nexport interface SensitiveCheck {\n blocked: boolean;\n reason?: string;\n}\n\nexport function checkSensitivePath(path: string): SensitiveCheck {\n const abs = resolve(path);\n for (const dir of SENSITIVE_DIRS) {\n if (abs === dir || abs.startsWith(dir + \"/\")) {\n return { blocked: true, reason: `sensitive directory ${dir.replace(HOME, \"~\")}` };\n }\n }\n for (const f of SENSITIVE_FILES) {\n if (abs === f) return { blocked: true, reason: `sensitive file ${f.replace(HOME, \"~\")}` };\n }\n const base = basename(abs);\n if (SENSITIVE_BASENAMES.has(base)) {\n return { blocked: true, reason: `private key filename ${base}` };\n }\n if (ENV_PATTERN.test(abs)) {\n return { blocked: true, reason: `.env file (may contain secrets)` };\n }\n return { blocked: false };\n}\n","/**\n * Write 工具:写入文件(创建或覆盖)。\n *\n * 为防误覆盖,约定调用前必须先 Read 过同一路径(除非文件不存在)。\n * 这个约束实际由 LLM 遵守 (prompt 引导);本工具不强制,但记录到日志。\n */\n\nimport { readFile, writeFile, mkdir, stat } from \"node:fs/promises\";\nimport { resolve, isAbsolute, dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { makeUnifiedDiff } from \"../_diff.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst WriteArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n content: z.string().describe(\"Full content of the file.\"),\n});\n\nexport const WriteTool = defineTool({\n name: \"Write\",\n description: \"Write a complete file to the local filesystem. Creates parent directories if needed. Overwrites existing files — prefer Edit for partial updates.\",\n parameters: WriteArgs,\n permission: \"write\",\n summarize: (args) => `Write(${args.file_path}, ${args.content.length} chars)`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let existed = false;\n let oldContent = \"\";\n try {\n const info = await stat(path);\n existed = info.isFile();\n if (existed) oldContent = await readFile(path, \"utf-8\");\n } catch {\n // 文件不存在,正常情况\n }\n\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, args.content, \"utf-8\");\n\n const diff = makeUnifiedDiff(args.file_path, oldContent, args.content);\n\n return {\n content: existed\n ? `Overwrote ${path} (${args.content.length} bytes).`\n : `Created ${path} (${args.content.length} bytes).`,\n summary: `${existed ? \"Overwrote\" : \"Created\"} ${args.file_path}`,\n diff: diff || undefined,\n };\n },\n});\n","/**\n * 文件改动 → unified diff(jsdiff),仅给 UI 渲染用,不进 LLM 上下文。\n *\n * 上下文行数 3(GNU diff 默认);新文件 / 整体覆盖时呈现为全 + 行。\n */\n\nimport { createPatch } from \"diff\";\n\nconst MAX_DIFF_LINES = 200;\n\nexport function makeUnifiedDiff(filePath: string, oldContent: string, newContent: string): string {\n if (oldContent === newContent) return \"\";\n const patch = createPatch(filePath, oldContent, newContent, \"before\", \"after\", { context: 3 });\n return truncate(patch);\n}\n\nfunction truncate(diff: string): string {\n const lines = diff.split(\"\\n\");\n if (lines.length <= MAX_DIFF_LINES) return diff;\n return lines.slice(0, MAX_DIFF_LINES).join(\"\\n\") + `\\n... [${lines.length - MAX_DIFF_LINES} more diff lines truncated]`;\n}\n","/**\n * Edit 工具:在文件中做精确字符串替换。\n *\n * 必须先 Read 过文件(由调用方/LLM 遵守,不强制校验)。\n * old_string 必须在文件中唯一出现;replace_all=true 时不要求唯一。\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { ToolError } from \"../../types/index.js\";\nimport { makeUnifiedDiff } from \"../_diff.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst EditArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n old_string: z.string().describe(\"Exact substring to replace. Must be unique unless replace_all=true.\"),\n new_string: z.string().describe(\"Replacement string.\"),\n replace_all: z.boolean().optional().describe(\"Replace every occurrence. Default false.\"),\n});\n\nexport const EditTool = defineTool({\n name: \"Edit\",\n description: \"Perform an exact string replacement in a file. Old string must be unique unless replace_all=true. Cheaper than Write when only a small part needs to change.\",\n parameters: EditArgs,\n permission: \"write\",\n summarize: (args) => `Edit(${args.file_path})`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let content: string;\n try {\n content = await readFile(path, \"utf-8\");\n } catch (err) {\n throw new ToolError(`Cannot read ${path}: ${err instanceof Error ? err.message : String(err)}`, \"Edit\", err);\n }\n\n if (args.old_string === args.new_string) {\n return { content: \"old_string is identical to new_string; nothing to do.\", isError: true };\n }\n\n const occurrences = countOccurrences(content, args.old_string);\n if (occurrences === 0) {\n return {\n content: `old_string not found in ${args.file_path}. Did you read the file first? Check whitespace and indentation.`,\n isError: true,\n };\n }\n if (occurrences > 1 && !args.replace_all) {\n return {\n content: `old_string occurs ${occurrences} times in ${args.file_path}. Either expand context to make it unique, or set replace_all=true.`,\n isError: true,\n };\n }\n\n const newContent = args.replace_all\n ? content.split(args.old_string).join(args.new_string)\n : content.replace(args.old_string, args.new_string);\n\n await writeFile(path, newContent, \"utf-8\");\n\n const diff = makeUnifiedDiff(args.file_path, content, newContent);\n\n return {\n content: `Edited ${path}: replaced ${args.replace_all ? occurrences : 1} occurrence(s).`,\n summary: `Edited ${args.file_path}`,\n diff: diff || undefined,\n };\n },\n});\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (needle.length === 0) return 0;\n let count = 0;\n let pos = 0;\n while ((pos = haystack.indexOf(needle, pos)) !== -1) {\n count += 1;\n pos += needle.length;\n }\n return count;\n}\n","/**\n * Bash 工具:执行 shell 命令。\n *\n * 安全:内置 deny 列表(无法 allow 绕过)。\n * 上限:超时 + stdout 截断。\n */\n\nimport { execa } from \"execa\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst BashArgs = z.object({\n command: z.string().describe(\"Shell command to run. Will be executed via sh -c.\"),\n timeout: z.number().int().positive().optional().describe(\"Timeout in milliseconds. Default 120000 (2 min). Max 600000.\"),\n description: z.string().optional().describe(\"Brief description (3-10 words) for the UI.\"),\n});\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MAX_TIMEOUT_MS = 600_000;\nconst MAX_OUTPUT_BYTES = 100_000;\n\n/** 即使在 allow 列表里也强制阻断的危险命令模式。 */\nconst HARD_DENY_PATTERNS: RegExp[] = [\n /\\brm\\s+-rf\\s+\\/(?:\\s|$)/, // rm -rf /\n /\\brm\\s+-rf\\s+~(?:\\/|\\s|$)/, // rm -rf ~ or ~/...\n /\\brm\\s+-rf\\s+\\*/, // rm -rf *\n /\\bdd\\s+.*of=\\/dev\\//, // dd of=/dev/*\n /\\bmkfs\\b/, // mkfs\n /:\\(\\)\\s*\\{\\s*:\\|:&\\s*\\}\\s*;\\s*:/, // fork bomb\n /\\bsudo\\b/, // sudo(v0.1 简单粗暴禁掉)\n /\\bcurl\\s+[^|]*\\|\\s*(?:sh|bash|zsh)/, // curl ... | sh\n /\\bwget\\s+[^|]*\\|\\s*(?:sh|bash|zsh)/, // wget ... | sh\n];\n\nfunction checkDangerous(command: string): { dangerous: true; reason: string } | { dangerous: false } {\n for (const pattern of HARD_DENY_PATTERNS) {\n if (pattern.test(command)) {\n return { dangerous: true, reason: `matches pattern ${pattern}` };\n }\n }\n return { dangerous: false };\n}\n\nexport const BashTool = defineTool({\n name: \"Bash\",\n description: \"Execute a shell command via sh -c. Use for git, file system listings, builds, tests, etc. Avoid interactive commands (prefer non-interactive flags). For file edits use Edit/Write, not sed/echo.\",\n parameters: BashArgs,\n permission: \"execute\",\n summarize: (args) => args.description ?? `Bash: ${args.command.length > 60 ? args.command.slice(0, 60) + \"...\" : args.command}`,\n async execute(args, ctx) {\n const danger = checkDangerous(args.command);\n if (danger.dangerous) {\n return {\n content: `Refused: command blocked by hard deny list (${danger.reason}). If you really need this, ask the user to run it manually.`,\n isError: true,\n };\n }\n\n const timeout = Math.min(args.timeout ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);\n\n try {\n const result = await execa(args.command, {\n shell: \"/bin/sh\",\n cwd: ctx.cwd,\n timeout,\n reject: false,\n stripFinalNewline: false,\n maxBuffer: MAX_OUTPUT_BYTES * 2,\n cancelSignal: ctx.abortSignal,\n });\n\n const stdout = truncate(result.stdout ?? \"\", MAX_OUTPUT_BYTES, \"stdout\");\n const stderr = truncate(result.stderr ?? \"\", MAX_OUTPUT_BYTES, \"stderr\");\n\n const parts: string[] = [];\n if (stdout) parts.push(`<stdout>\\n${stdout}\\n</stdout>`);\n if (stderr) parts.push(`<stderr>\\n${stderr}\\n</stderr>`);\n if (result.timedOut) parts.push(`<timeout>Command exceeded ${timeout}ms.</timeout>`);\n if (result.failed && !result.timedOut) parts.push(`<exit_code>${result.exitCode ?? \"unknown\"}</exit_code>`);\n\n const body = parts.length > 0 ? parts.join(\"\\n\") : \"(no output)\";\n return {\n content: body,\n isError: result.failed,\n summary: result.failed ? `Bash exited ${result.exitCode ?? \"?\"}` : `Bash ok`,\n };\n } catch (err) {\n return {\n content: `Bash threw: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n});\n\nfunction truncate(text: string, max: number, label: string): string {\n if (text.length <= max) return text;\n return text.slice(0, max) + `\\n... [${label} truncated, original ${text.length} bytes]`;\n}\n","/**\n * Grep 工具:基于 ripgrep 包装(若可用),fallback 到 bash grep。\n * v0.1 简单实现:直接调 system rg / grep。\n */\n\nimport { execa } from \"execa\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst GrepArgs = z.object({\n pattern: z.string().describe(\"Regex pattern to search for.\"),\n path: z.string().optional().describe(\"File or directory to search in. Default: cwd.\"),\n glob: z.string().optional().describe('Glob filter, e.g. \"*.ts\" or \"src/**/*.tsx\".'),\n output_mode: z.enum([\"content\", \"files_with_matches\", \"count\"]).optional().describe(\"Default: files_with_matches.\"),\n context: z.number().int().min(0).max(50).optional().describe(\"Context lines around each match (use only with output_mode=content).\"),\n case_insensitive: z.boolean().optional(),\n});\n\nlet rgChecked = false;\nlet rgAvailable = false;\n\nasync function checkRipgrep(): Promise<boolean> {\n if (rgChecked) return rgAvailable;\n try {\n await execa(\"rg\", [\"--version\"], { reject: false });\n rgAvailable = true;\n } catch {\n rgAvailable = false;\n }\n rgChecked = true;\n return rgAvailable;\n}\n\nexport const GrepTool = defineTool({\n name: \"Grep\",\n description: \"Search file contents using regex. Prefer this over Bash(grep|find) — handles ignore files & is much faster on large trees.\",\n parameters: GrepArgs,\n permission: \"read\",\n summarize: (args) => `Grep(${args.pattern}${args.path ? `, ${args.path}` : \"\"})`,\n async execute(args, ctx) {\n const hasRg = await checkRipgrep();\n const mode = args.output_mode ?? \"files_with_matches\";\n\n if (hasRg) {\n const cliArgs: string[] = [];\n if (args.case_insensitive) cliArgs.push(\"-i\");\n if (mode === \"files_with_matches\") cliArgs.push(\"-l\");\n else if (mode === \"count\") cliArgs.push(\"-c\");\n else if (args.context != null) cliArgs.push(\"-C\", String(args.context));\n if (args.glob) cliArgs.push(\"--glob\", args.glob);\n cliArgs.push(\"--\", args.pattern, args.path ?? \".\");\n\n const result = await execa(\"rg\", cliArgs, { cwd: ctx.cwd, reject: false, cancelSignal: ctx.abortSignal });\n const out = (result.stdout ?? \"\").trim();\n if (result.exitCode === 0 || result.exitCode === 1) {\n return { content: out || \"(no matches)\", summary: `Grep ${args.pattern}` };\n }\n return { content: `rg failed: ${result.stderr}`, isError: true };\n }\n\n // Fallback: bash grep -r\n const cliArgs = [\"-r\", \"-n\"];\n if (args.case_insensitive) cliArgs.push(\"-i\");\n if (mode === \"files_with_matches\") cliArgs.push(\"-l\");\n else if (mode === \"count\") cliArgs.push(\"-c\");\n cliArgs.push(\"-E\", args.pattern, args.path ?? \".\");\n\n const result = await execa(\"grep\", cliArgs, { cwd: ctx.cwd, reject: false, cancelSignal: ctx.abortSignal });\n const out = (result.stdout ?? \"\").trim();\n if (result.exitCode === 0 || result.exitCode === 1) {\n return { content: out || \"(no matches)\", summary: `Grep ${args.pattern}` };\n }\n return { content: `grep failed: ${result.stderr}`, isError: true };\n },\n});\n","/**\n * Glob 工具:用 fast-glob 列出匹配文件。\n */\n\nimport fg from \"fast-glob\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst GlobArgs = z.object({\n pattern: z.string().describe('Glob pattern, e.g. \"src/**/*.ts\" or \"**/*.{md,json}\".'),\n path: z.string().optional().describe(\"Base directory to search from. Default: cwd.\"),\n limit: z.number().int().positive().max(1000).optional().describe(\"Max results. Default 100.\"),\n});\n\nconst DEFAULT_LIMIT = 100;\n\nexport const GlobTool = defineTool({\n name: \"Glob\",\n description: \"Find files by glob pattern. Returns relative paths sorted by modification time (newest first).\",\n parameters: GlobArgs,\n permission: \"read\",\n summarize: (args) => `Glob(${args.pattern}${args.path ? `, ${args.path}` : \"\"})`,\n async execute(args, ctx) {\n const cwd = args.path ?? ctx.cwd;\n const limit = args.limit ?? DEFAULT_LIMIT;\n\n const entries = await fg(args.pattern, {\n cwd,\n onlyFiles: true,\n stats: true,\n dot: false,\n ignore: [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \"**/.muse/**\"],\n });\n\n // 按 mtime 倒序\n entries.sort((a, b) => {\n const ta = a.stats?.mtime?.getTime() ?? 0;\n const tb = b.stats?.mtime?.getTime() ?? 0;\n return tb - ta;\n });\n\n const truncated = entries.length > limit;\n const paths = entries.slice(0, limit).map((e) => e.path);\n\n let result = paths.join(\"\\n\") || \"(no matches)\";\n if (truncated) {\n result += `\\n... [${entries.length - limit} more, increase limit to see]`;\n }\n return { content: result, summary: `Glob found ${entries.length} file(s)` };\n },\n});\n","/**\n * TodoWrite 工具:维护 session 内任务清单。\n *\n * 把完整 todos 数组替换进 ctx.todos。约定:一次只一个 in_progress;完成立即标 completed\n * 不要批;任务尽量原子。MessageView 会读 args.todos 渲染 checkbox 清单。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface TodoItem {\n content: string;\n status: TodoStatus;\n activeForm?: string;\n}\n\nconst TodoSchema = z.object({\n content: z.string().describe(\"Imperative one-line task description (e.g. 'Run the test suite').\"),\n status: z.enum([\"pending\", \"in_progress\", \"completed\"]).describe(\"Current status.\"),\n activeForm: z.string().optional().describe(\"Present-continuous form for the spinner (e.g. 'Running the test suite').\"),\n});\n\nconst TodoWriteArgs = z.object({\n todos: z.array(TodoSchema).describe(\"Full list. Replaces the current store.\"),\n});\n\nexport const TodoWriteTool = defineTool({\n name: \"TodoWrite\",\n description:\n \"Maintain a structured task list for the current session. Pass the FULL list every call (it replaces the store). \" +\n \"Mark exactly one task in_progress at a time; mark completed immediately when done; do not batch completions. \" +\n \"Use when the task has 3+ distinct steps or is non-trivial. Skip for single trivial actions.\",\n parameters: TodoWriteArgs,\n permission: \"read\",\n summarize: (args) => `TodoWrite(${args.todos.length} items)`,\n async execute(args, ctx) {\n if (!ctx.todos) {\n return {\n content: \"TodoWrite is unavailable: this agent run has no todo store. (Internal bug; tell the user.)\",\n isError: true,\n };\n }\n ctx.todos.set(args.todos);\n const summary = args.todos\n .map((t, i) => `${i + 1}. ${t.status === \"completed\" ? \"[x]\" : t.status === \"in_progress\" ? \"[~]\" : \"[ ]\"} ${t.content}`)\n .join(\"\\n\");\n return {\n content: `Updated todos (${args.todos.length} items):\\n${summary}`,\n summary: `Todos: ${args.todos.filter((t) => t.status === \"completed\").length}/${args.todos.length} done`,\n };\n },\n});\n","/**\n * WebFetch 工具:抓 URL → 文本 / 简易 markdown。\n *\n * 安全:\n * - 拒绝本机回环 / 链接本地 / 私有网段(SSRF 防护)\n * - http → https 自动升级\n * - 30s 超时;最大 1MB 响应体\n *\n * 输出:以 HTML 解析时 strip 标签后近似 markdown;非 HTML 直接返回文本(截断)。\n *\n * 不引入 turndown:v0.1 用 minimal regex 转换,够 LLM 阅读;\n * 后续如需精细 markdown(保留 link / list 嵌套),再换专门库。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst WebFetchArgs = z.object({\n url: z.string().describe(\"Fully-qualified URL. http will be upgraded to https.\"),\n prompt: z\n .string()\n .optional()\n .describe(\n \"What information to look for. The host returns the page content; the LLM should then read it to answer the prompt.\",\n ),\n});\n\nconst MAX_RESPONSE_BYTES = 1_000_000;\nconst FETCH_TIMEOUT_MS = 30_000;\n\nconst PRIVATE_HOST_PATTERNS: RegExp[] = [\n /^localhost$/i,\n /^127\\./,\n /^0\\.0\\.0\\.0$/,\n /^169\\.254\\./,\n /^10\\./,\n /^192\\.168\\./,\n /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./,\n /^::1$/,\n /^fc[0-9a-f]{2}:/i,\n /^fe80:/i,\n];\n\nfunction isPrivateHost(hostname: string): boolean {\n return PRIVATE_HOST_PATTERNS.some((p) => p.test(hostname));\n}\n\nexport const WebFetchTool = defineTool({\n name: \"WebFetch\",\n description:\n \"Fetch a URL and return its textual content (HTML stripped to a markdown-ish form). \" +\n \"Use for reading documentation, blog posts, or API specs. Private/loopback hosts are blocked. \" +\n \"If the URL redirects to a different host, the redirect target is returned for you to re-fetch.\",\n parameters: WebFetchArgs,\n permission: \"network\",\n summarize: (args) => `WebFetch(${args.url})`,\n async execute(args, ctx) {\n let target: URL;\n try {\n target = new URL(args.url);\n } catch {\n return { content: `Invalid URL: ${args.url}`, isError: true };\n }\n if (target.protocol === \"http:\") {\n target.protocol = \"https:\";\n }\n if (target.protocol !== \"https:\") {\n return { content: `Refused: only http(s) URLs are allowed.`, isError: true };\n }\n if (isPrivateHost(target.hostname)) {\n return { content: `Refused: ${target.hostname} is a private/loopback host (SSRF guard).`, isError: true };\n }\n\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n ctx.abortSignal?.addEventListener(\"abort\", onAbort);\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const resp = await fetch(target.toString(), {\n redirect: \"manual\",\n signal: controller.signal,\n headers: { \"user-agent\": \"muse-cli/0.1\" },\n });\n\n // 跨主机 redirect → 提示重试,不自动跟随\n if (resp.status >= 300 && resp.status < 400) {\n const loc = resp.headers.get(\"location\");\n if (loc) {\n try {\n const redirectURL = new URL(loc, target);\n if (redirectURL.hostname !== target.hostname) {\n return {\n content: `Redirect to a different host: ${redirectURL.toString()}\\nRe-fetch the new URL explicitly if you trust it.`,\n summary: `Redirect to a different host: ${redirectURL.toString()}`,\n kind: \"warn\",\n };\n }\n // 同 host redirect 也提示一下,让 LLM 决定是否跟\n return {\n content: `Redirect (same host): ${redirectURL.toString()}\\nRe-fetch the new URL to continue.`,\n summary: `Redirect → ${redirectURL.pathname}`,\n kind: \"warn\",\n };\n } catch {\n return { content: `Redirect with unparseable location: ${loc}`, isError: true };\n }\n }\n }\n\n if (!resp.ok) {\n return { content: `HTTP ${resp.status} ${resp.statusText} for ${target.toString()}`, isError: true };\n }\n\n const contentType = resp.headers.get(\"content-type\") ?? \"\";\n const reader = resp.body?.getReader();\n if (!reader) return { content: `Empty response body.`, isError: true };\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n if (value) {\n total += value.byteLength;\n if (total > MAX_RESPONSE_BYTES) {\n await reader.cancel();\n chunks.push(value.slice(0, value.byteLength - (total - MAX_RESPONSE_BYTES)));\n break;\n }\n chunks.push(value);\n }\n }\n const body = new TextDecoder(\"utf-8\", { fatal: false }).decode(Buffer.concat(chunks.map((c) => Buffer.from(c))));\n\n let processed = body;\n if (/^text\\/html|application\\/xhtml/i.test(contentType)) {\n processed = htmlToText(body);\n }\n\n const summary = args.prompt\n ? `# WebFetch result for: ${args.prompt}`\n : `Fetched ${target.hostname} (${total} bytes${total >= MAX_RESPONSE_BYTES ? \", truncated\" : \"\"})`;\n const truncated = processed.length > 200_000 ? processed.slice(0, 200_000) + \"\\n\\n... [truncated]\" : processed;\n const preface = args.prompt ? `# WebFetch result for: ${args.prompt}\\n\\nSource: ${target.toString()}\\n\\n` : `Source: ${target.toString()}\\n\\n`;\n return { content: preface + truncated, summary };\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n return { content: `WebFetch aborted (timeout or user cancel).`, isError: true };\n }\n return { content: `WebFetch failed: ${err instanceof Error ? err.message : String(err)}`, isError: true };\n } finally {\n clearTimeout(timer);\n ctx.abortSignal?.removeEventListener(\"abort\", onAbort);\n }\n },\n});\n\n/**\n * 极简 HTML → 文本:删 script/style,保留段落 / 列表 / 标题 / 链接。\n * 不追求精确——给 LLM 看的近似版本即可。\n */\nexport function htmlToText(html: string): string {\n let s = html;\n // 删 script / style / svg / noscript\n s = s.replace(/<(script|style|svg|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi, \"\");\n // 注释\n s = s.replace(/<!--[\\s\\S]*?-->/g, \"\");\n // 标题\n s = s.replace(/<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>/gi, (_m, lvl: string, txt: string) => {\n return `\\n\\n${\"#\".repeat(parseInt(lvl, 10))} ${stripTags(txt).trim()}\\n\\n`;\n });\n // a 链接\n s = s.replace(/<a\\b[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, (_m, href: string, txt: string) => {\n const label = stripTags(txt).trim();\n return label ? `[${label}](${href})` : href;\n });\n // 列表项\n s = s.replace(/<li\\b[^>]*>([\\s\\S]*?)<\\/li>/gi, (_m, txt: string) => `\\n- ${stripTags(txt).trim()}`);\n // 段落 / 块级\n s = s.replace(/<(p|div|section|article|header|footer|main|aside|nav|pre|blockquote|br|hr)\\b[^>]*>/gi, \"\\n\");\n s = s.replace(/<\\/(p|div|section|article|header|footer|main|aside|nav|pre|blockquote)>/gi, \"\\n\");\n // code 行内\n s = s.replace(/<code\\b[^>]*>([\\s\\S]*?)<\\/code>/gi, (_m, txt: string) => `\\`${stripTags(txt)}\\``);\n // 删剩余标签\n s = stripTags(s);\n // entity 简版\n s = s\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n // 合并多空行\n s = s.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n return s;\n}\n\nfunction stripTags(s: string): string {\n return s.replace(/<[^>]+>/g, \"\");\n}\n","/**\n * MemoryWrite / MemoryRead 工具:长期 memory 操作。\n *\n * Memory 设计与 Claude Code 对齐:四种类型(user / feedback / project / reference),\n * 文件路径在 ~/.muse/projects/<hash>/memory/,MEMORY.md 索引注入到 system prompt。\n *\n * 由 ctx.cwd 决定项目身份;切目录后 memory 自动隔离。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { readMemoryFile, writeMemory, type MemoryType } from \"../../loop/memory.js\";\n\nconst TYPES: [MemoryType, ...MemoryType[]] = [\"user\", \"feedback\", \"project\", \"reference\"];\n\nconst MemoryWriteArgs = z.object({\n name: z\n .string()\n .regex(/^[a-z0-9][a-z0-9-_]*$/i, \"must be a kebab- or snake-style slug\")\n .describe(\"Short kebab/snake slug; used as filename (<name>.md) and index key.\"),\n description: z\n .string()\n .describe(\"One-line summary used in MEMORY.md index (decides future relevance).\"),\n type: z.enum(TYPES).describe(\"user | feedback | project | reference\"),\n body: z.string().describe(\"Memory content (markdown). For feedback/project, lead with the rule/fact then **Why:** and **How to apply:** lines.\"),\n});\n\nexport const MemoryWriteTool = defineTool({\n name: \"MemoryWrite\",\n description:\n \"Save a long-term memory file under ~/.muse/projects/<hash>/memory/<name>.md and update MEMORY.md index. \" +\n \"Use for: user role/preferences, validated approach decisions (feedback), project facts (auto-convert relative dates), external system references. \" +\n \"Do NOT save: code patterns derivable from the repo, git history, fix recipes, ephemeral task state.\",\n parameters: MemoryWriteArgs,\n permission: \"write\",\n summarize: (args) => `MemoryWrite(${args.name}, type=${args.type})`,\n async execute(args, ctx) {\n const { filePath, indexUpdated } = await writeMemory(ctx.cwd, {\n name: args.name,\n description: args.description,\n type: args.type as MemoryType,\n body: args.body,\n });\n return {\n content: `Saved memory \"${args.name}\" (${args.type}) → ${filePath}${indexUpdated ? \"\\nMEMORY.md updated.\" : \"\"}`,\n summary: `MemoryWrite ${args.name}`,\n };\n },\n});\n\nconst MemoryReadArgs = z.object({\n name: z.string().describe(\"Memory slug to read (no .md extension).\"),\n});\n\nexport const MemoryReadTool = defineTool({\n name: \"MemoryRead\",\n description:\n \"Read a specific long-term memory file by name. Use after seeing it referenced in MEMORY.md (which is auto-injected into the system prompt).\",\n parameters: MemoryReadArgs,\n permission: \"read\",\n summarize: (args) => `MemoryRead(${args.name})`,\n async execute(args, ctx) {\n try {\n const content = await readMemoryFile(ctx.cwd, args.name);\n return { content, summary: `MemoryRead ${args.name}` };\n } catch (err) {\n return { content: err instanceof Error ? err.message : String(err), isError: true };\n }\n },\n});\n","/**\n * 长期 Memory:跨 session 持久化的小段知识。\n *\n * 路径约定:~/.muse/projects/<projectHash>/memory/\n * - MEMORY.md index(每行 `- [Title](file.md) — one-line hook`)\n * - <name>.md 具体记忆,带 frontmatter\n *\n * MEMORY.md 前 200 行自动注入 system prompt,让 LLM 每轮都看到。\n *\n * 类型:user / feedback / project / reference(对齐 Claude Code)。\n */\n\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createHash } from \"node:crypto\";\n\nexport type MemoryType = \"user\" | \"feedback\" | \"project\" | \"reference\";\n\nfunction projectHash(cwd: string): string {\n return createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n}\n\nexport function memoryDir(cwd: string): string {\n return join(homedir(), \".muse\", \"projects\", projectHash(cwd), \"memory\");\n}\n\nexport function memoryIndexPath(cwd: string): string {\n return join(memoryDir(cwd), \"MEMORY.md\");\n}\n\nexport function memoryFilePath(cwd: string, name: string): string {\n return join(memoryDir(cwd), `${name}.md`);\n}\n\n/** 加载 MEMORY.md 前 N 行供 system prompt 注入。 */\nexport async function loadMemoryIndex(cwd: string, maxLines = 200): Promise<string> {\n const path = memoryIndexPath(cwd);\n if (!existsSync(path)) return \"\";\n try {\n const raw = await readFile(path, \"utf-8\");\n const lines = raw.split(\"\\n\");\n if (lines.length <= maxLines) return raw.trim();\n return lines.slice(0, maxLines).join(\"\\n\").trim() + `\\n... [truncated; ${lines.length - maxLines} more lines]`;\n } catch {\n return \"\";\n }\n}\n\nexport async function readMemoryFile(cwd: string, name: string): Promise<string> {\n const path = memoryFilePath(cwd, name);\n if (!existsSync(path)) {\n throw new Error(`Memory \"${name}\" does not exist at ${path}.`);\n }\n return readFile(path, \"utf-8\");\n}\n\nexport interface WriteMemoryOpts {\n name: string;\n description: string;\n type: MemoryType;\n body: string;\n}\n\n/**\n * 写一条 memory + 更新 MEMORY.md 索引。\n * - 若文件已存在,整体覆盖\n * - MEMORY.md 行匹配 `- [name](name.md) ` 前缀;存在则替换该行,否则追加\n */\nexport async function writeMemory(cwd: string, opts: WriteMemoryOpts): Promise<{ filePath: string; indexUpdated: boolean }> {\n const dir = memoryDir(cwd);\n await mkdir(dir, { recursive: true });\n\n const filePath = memoryFilePath(cwd, opts.name);\n const frontmatter = [\n \"---\",\n `name: ${opts.name}`,\n `description: ${opts.description.replace(/\\n/g, \" \").trim()}`,\n `metadata:`,\n ` type: ${opts.type}`,\n \"---\",\n ].join(\"\\n\");\n const content = `${frontmatter}\\n\\n${opts.body.trim()}\\n`;\n await writeFile(filePath, content, \"utf-8\");\n\n // 索引更新\n const indexPath = memoryIndexPath(cwd);\n let index = \"\";\n if (existsSync(indexPath)) index = await readFile(indexPath, \"utf-8\");\n const lines = index ? index.split(\"\\n\") : [];\n const linePrefix = `- [${opts.name}](${opts.name}.md)`;\n const newLine = `${linePrefix} — ${opts.description.replace(/\\n/g, \" \").trim()}`;\n const existing = lines.findIndex((l) => l.startsWith(linePrefix));\n let indexUpdated = false;\n if (existing >= 0) {\n if (lines[existing] !== newLine) {\n lines[existing] = newLine;\n indexUpdated = true;\n }\n } else {\n lines.push(newLine);\n indexUpdated = true;\n }\n if (indexUpdated) {\n const out = lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trimEnd() + \"\\n\";\n await writeFile(indexPath, out, \"utf-8\");\n }\n\n return { filePath, indexUpdated };\n}\n","/**\n * AskUserQuestion 工具:在 agent loop 内同步弹出选择题让用户作答。\n *\n * 流程:tool.execute → ctx.askQuestion(req) → App 渲染 QuestionPicker → 用户 ↑↓ 选 + Enter\n * → resolve 把结果传回 → tool 把答案拼成文本喂给 LLM。Esc 取消会返回 cancelled=true。\n *\n * 一次调用可塞多个 questions(仿 Claude Code),逐题展示,任一题 Esc 视为整批取消。\n *\n * 注意:tool 本身不调任何外部资源,permission 用 read(不弹权限确认)。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nexport const AskQuestionOptionSchema = z.object({\n label: z.string().min(1).describe(\"Option text shown to the user. Concise (1-5 words).\"),\n description: z\n .string()\n .optional()\n .describe(\"Optional one-line explanation of what this option means.\"),\n preview: z\n .string()\n .optional()\n .describe(\n \"Optional rich preview rendered in a right-side panel when this option is focused. \" +\n \"Use for code/diagram/config snippets that help compare options visually. \" +\n \"Multi-line text supported.\",\n ),\n});\n\nexport const AskQuestionSchema = z.object({\n question: z.string().min(1).describe(\"Full question text (end with ?).\"),\n header: z\n .string()\n .min(1)\n .max(16)\n .describe(\"Very short label (chip), max 12 chars. E.g. 'Auth method'.\"),\n options: z\n .array(AskQuestionOptionSchema)\n .min(2)\n .max(4)\n .describe(\"2-4 options. Mutually exclusive unless multiSelect=true.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"Allow multiple selections. Default false.\"),\n});\n\nexport type AskQuestion = z.infer<typeof AskQuestionSchema>;\nexport type AskQuestionOption = z.infer<typeof AskQuestionOptionSchema>;\n\nexport interface AskQuestionResponse {\n cancelled: boolean;\n /** 单选:单元素数组;多选:所选 label 列表。cancelled=true 时为空。 */\n selections: string[];\n /** 用户对该题用 'n' 添加的自由备注。空字符串表示未填。 */\n notes?: string;\n}\n\nconst AskUserQuestionArgs = z.object({\n questions: z\n .array(AskQuestionSchema)\n .min(1)\n .max(4)\n .describe(\"1-4 questions to ask the user sequentially.\"),\n});\n\nexport const AskUserQuestionTool = defineTool({\n name: \"AskUserQuestion\",\n description:\n \"Ask the user one or more multiple-choice questions when their input is needed to proceed. \" +\n \"Each question has 2-4 options. Use multiSelect=true for non-mutually-exclusive choices. \" +\n \"Prefer this over plain-text questions when the answer space is bounded. \" +\n \"If the user presses Esc, the entire batch is treated as cancelled.\",\n parameters: AskUserQuestionArgs,\n permission: \"read\",\n summarize: (args) =>\n `AskUserQuestion(${args.questions.length} question${args.questions.length === 1 ? \"\" : \"s\"})`,\n async execute(args, ctx) {\n if (!ctx.askQuestions) {\n return {\n content:\n \"AskUserQuestion is unavailable: this agent run has no question handler. \" +\n \"(Internal bug; tell the user.)\",\n isError: true,\n };\n }\n\n const responses = await ctx.askQuestions(args.questions);\n // Esc 取消时所有项 cancelled=true(UI 一次性返回整批)\n if (responses.length > 0 && responses[0].cancelled) {\n return {\n content: \"User cancelled (Esc). No answers were collected.\",\n isError: false,\n };\n }\n\n const blocks = args.questions.map((q, qi) => {\n const r = responses[qi];\n const sel = r?.selections ?? [];\n const ans = sel.length === 0 ? \"(no answer)\" : sel.join(\", \");\n const notes = r?.notes?.trim();\n return notes ? `Q: ${q.question}\\nA: ${ans}\\nNotes: ${notes}` : `Q: ${q.question}\\nA: ${ans}`;\n });\n\n return {\n content: blocks.join(\"\\n\\n\"),\n summary: `Asked ${args.questions.length} question${args.questions.length === 1 ? \"\" : \"s\"}`,\n };\n },\n});\n","import type { AnyTool } from \"../types.js\";\nimport { ReadTool } from \"./read.js\";\nimport { WriteTool } from \"./write.js\";\nimport { EditTool } from \"./edit.js\";\nimport { BashTool } from \"./bash.js\";\nimport { GrepTool } from \"./grep.js\";\nimport { GlobTool } from \"./glob.js\";\nimport { TodoWriteTool } from \"./todo.js\";\nimport { WebFetchTool } from \"./webfetch.js\";\nimport { MemoryReadTool, MemoryWriteTool } from \"./memory.js\";\nimport { AskUserQuestionTool } from \"./ask-user-question.js\";\n\nexport {\n ReadTool,\n WriteTool,\n EditTool,\n BashTool,\n GrepTool,\n GlobTool,\n TodoWriteTool,\n WebFetchTool,\n MemoryReadTool,\n MemoryWriteTool,\n AskUserQuestionTool,\n};\n\nexport const BUILTIN_TOOLS: AnyTool[] = [\n ReadTool,\n WriteTool,\n EditTool,\n BashTool,\n GrepTool,\n GlobTool,\n TodoWriteTool,\n WebFetchTool,\n MemoryReadTool,\n MemoryWriteTool,\n AskUserQuestionTool,\n];\n","/**\n * 权限模型:三态 allow / ask / deny,叠加 4 档 PermissionMode。\n *\n * 模式匹配(pattern):\n * - \"ToolName\" 精确匹配\n * - \"Bash(<prefix>)\" 匹配 Bash 工具 + 命令前缀\n * - \"Bash(<prefix>:*)\" 通配\n *\n * PermissionMode(详见文档库 permission-modes.md):\n * - default:完全走 settings.permissions 规则\n * - acceptEdits:Edit/Write 自动 allow,其他走 default\n * - plan:只允许 read 类工具,其他全 deny\n * - bypassPermissions:除显式 deny 与 Bash 硬 deny 外全 allow\n *\n * 危险操作(rm -rf / sudo 等)由 Bash 工具内部 HARD_DENY_PATTERNS 兜底,所有模式都不可绕过。\n */\n\nimport type { Permissions } from \"../config/types.js\";\nimport type { PermissionLevel } from \"../tools/types.js\";\n\nexport type Decision = \"allow\" | \"ask\" | \"deny\";\n\n/** 用户对 PermissionPrompt 三档选择。 */\nexport type PermissionDecision = \"yes\" | \"session_allow\" | \"no\";\n\nexport type PermissionMode = \"default\" | \"acceptEdits\" | \"plan\" | \"bypassPermissions\";\n\nexport const MODE_CYCLE: readonly PermissionMode[] = [\n \"default\",\n \"acceptEdits\",\n \"plan\",\n \"bypassPermissions\",\n] as const;\n\nexport const MODE_LABEL: Record<PermissionMode, string> = {\n default: \"default permissions on\",\n acceptEdits: \"accept edits on\",\n plan: \"plan mode on\",\n bypassPermissions: \"bypass permissions on\",\n};\n\nexport const MODE_COLOR: Record<PermissionMode, string> = {\n default: \"gray\",\n acceptEdits: \"#EAB308\",\n plan: \"#06B6D4\",\n bypassPermissions: \"#EF4444\",\n};\n\nexport interface PermissionInput {\n toolName: string;\n args: unknown;\n /** Tool 的权限级别;由 Agent loop 从 ToolRegistry 注入。Plan 模式用此区分 read/write。 */\n permission?: PermissionLevel;\n}\n\nexport class PermissionGate {\n private rules: Required<Permissions>;\n private mode: PermissionMode = \"default\";\n /** Session 级 allow:用户在 PermissionPrompt 选 \"yes, for session\" 后填充。 */\n private sessionAllow = new Set<string>();\n\n constructor(rules: Permissions = {}) {\n this.rules = {\n allow: rules.allow ?? [],\n ask: rules.ask ?? [],\n deny: rules.deny ?? [],\n defaultMode: rules.defaultMode ?? \"ask\",\n };\n }\n\n setMode(mode: PermissionMode): void {\n this.mode = mode;\n }\n\n getMode(): PermissionMode {\n return this.mode;\n }\n\n cycleMode(): PermissionMode {\n const i = MODE_CYCLE.indexOf(this.mode);\n this.mode = MODE_CYCLE[(i + 1) % MODE_CYCLE.length];\n return this.mode;\n }\n\n /** 用户在 PermissionPrompt 选 \"yes, allow for session\" 时记下。 */\n allowForSession(toolName: string): void {\n this.sessionAllow.add(toolName);\n }\n\n isSessionAllowed(toolName: string): boolean {\n return this.sessionAllow.has(toolName);\n }\n\n decide(input: PermissionInput): Decision {\n // 用户显式 deny 永远生效,所有模式不可绕过\n if (this.matches(this.rules.deny, input)) return \"deny\";\n // session 级 allow 在 deny 之后、mode 分支之前生效\n if (this.sessionAllow.has(input.toolName)) return \"allow\";\n\n switch (this.mode) {\n case \"bypassPermissions\":\n return \"allow\";\n\n case \"plan\":\n // 只允许只读工具;写/执行/网络类直接 deny\n return input.permission === \"read\" ? \"allow\" : \"deny\";\n\n case \"acceptEdits\":\n if (input.toolName === \"Edit\" || input.toolName === \"Write\") return \"allow\";\n return this.defaultDecide(input);\n\n case \"default\":\n default:\n return this.defaultDecide(input);\n }\n }\n\n private defaultDecide(input: PermissionInput): Decision {\n if (this.matches(this.rules.allow, input)) return \"allow\";\n if (this.matches(this.rules.ask, input)) return \"ask\";\n switch (this.rules.defaultMode) {\n case \"strict\":\n return \"ask\";\n case \"relaxed\":\n return \"allow\";\n case \"ask\":\n default:\n return \"ask\";\n }\n }\n\n private matches(patterns: string[], input: PermissionInput): boolean {\n for (const pattern of patterns) {\n if (this.matchOne(pattern, input)) return true;\n }\n return false;\n }\n\n private matchOne(pattern: string, input: PermissionInput): boolean {\n // \"ToolName\" 精确匹配\n if (!pattern.includes(\"(\")) {\n return pattern === input.toolName;\n }\n // \"Bash(<prefix>:*)\" 形式\n const m = pattern.match(/^([A-Za-z_][A-Za-z0-9_]*)\\(([^)]*)\\)$/);\n if (!m) return false;\n const [, toolName, sub] = m;\n if (toolName !== input.toolName) return false;\n if (input.toolName === \"Bash\" && typeof input.args === \"object\" && input.args !== null) {\n const cmd = (input.args as { command?: string }).command ?? \"\";\n if (sub.endsWith(\":*\")) {\n const prefix = sub.slice(0, -2);\n return cmd.startsWith(prefix);\n }\n return cmd === sub || cmd.startsWith(sub + \" \");\n }\n return false;\n }\n}\n","/**\n * Session 持久化:append-only JSONL。\n * 路径:~/.muse/projects/<project-hash>/sessions/<uuid>.jsonl\n *\n * 每行一个事件:消息 / 工具调用 / 工具结果 / 使用统计 / ...\n */\n\nimport { appendFile, mkdir, readdir, readFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport type { Message, TokenUsage } from \"../types/index.js\";\nimport { log } from \"../log/index.js\";\n\nexport type SessionEvent =\n | { type: \"session_start\"; time: string; cwd: string; provider: string; model: string }\n | { type: \"message\"; time: string; message: Message }\n | { type: \"usage\"; time: string; usage: TokenUsage; provider: string; model: string }\n | { type: \"session_end\"; time: string; reason: \"user_exit\" | \"error\" };\n\nexport interface SessionMeta {\n id: string;\n cwd: string;\n createdAt: string;\n path: string;\n}\n\nexport interface SessionSummary extends SessionMeta {\n /** 首个 user 消息前 60 字符。 */\n preview?: string;\n messageCount: number;\n}\n\nfunction projectHash(cwd: string): string {\n return createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n}\n\nfunction sessionsDir(cwd: string): string {\n return join(homedir(), \".muse\", \"projects\", projectHash(cwd), \"sessions\");\n}\n\nexport class Session {\n readonly meta: SessionMeta;\n private writeQueue: Promise<void> = Promise.resolve();\n\n private constructor(meta: SessionMeta) {\n this.meta = meta;\n }\n\n static async create(cwd: string): Promise<Session> {\n const id = randomUUID();\n const dir = sessionsDir(cwd);\n await mkdir(dir, { recursive: true });\n const path = join(dir, `${id}.jsonl`);\n const meta: SessionMeta = {\n id,\n cwd,\n createdAt: new Date().toISOString(),\n path,\n };\n log.debug(\"session created\", { id, path });\n return new Session(meta);\n }\n\n static async findLatest(cwd: string): Promise<SessionMeta | undefined> {\n const list = await Session.listAll(cwd, 1);\n return list[0];\n }\n\n static async resolve(cwd: string, idOrPrefix: string): Promise<SessionMeta | undefined> {\n const dir = sessionsDir(cwd);\n if (!existsSync(dir)) return undefined;\n const entries = await readdir(dir);\n const matches = entries.filter((e) => e.endsWith(\".jsonl\") && e.startsWith(idOrPrefix));\n if (matches.length === 0) return undefined;\n if (matches.length > 1) {\n throw new Error(`Ambiguous session id \"${idOrPrefix}\" matches ${matches.length} sessions; use more characters.`);\n }\n const top = matches[0];\n const st = await stat(join(dir, top));\n return {\n id: top.replace(/\\.jsonl$/, \"\"),\n cwd,\n createdAt: st.mtime.toISOString(),\n path: join(dir, top),\n };\n }\n\n /**\n * 按修改时间倒序列出当前 cwd 下的 session,附带 preview 与消息数。\n * 读 preview 需要打开每个文件;调用方通过 limit 控制 IO 量。\n */\n static async listAll(cwd: string, limit?: number): Promise<SessionSummary[]> {\n const dir = sessionsDir(cwd);\n if (!existsSync(dir)) return [];\n const entries = await readdir(dir);\n const files = entries.filter((e) => e.endsWith(\".jsonl\"));\n if (files.length === 0) return [];\n\n const stats = await Promise.all(\n files.map(async (f) => {\n const path = join(dir, f);\n const st = await stat(path);\n return { file: f, path, mtime: st.mtime };\n }),\n );\n stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n const truncated = typeof limit === \"number\" ? stats.slice(0, limit) : stats;\n\n const summaries: SessionSummary[] = [];\n for (const s of truncated) {\n const meta: SessionMeta = {\n id: s.file.replace(/\\.jsonl$/, \"\"),\n cwd,\n createdAt: s.mtime.toISOString(),\n path: s.path,\n };\n const summary = await readSummary(meta);\n summaries.push(summary);\n }\n return summaries;\n }\n\n static async open(meta: SessionMeta): Promise<{ session: Session; events: SessionEvent[] }> {\n const session = new Session(meta);\n const events = await session.readAll();\n return { session, events };\n }\n\n /** 从已加载的 events 重建 messages 数组(按时序)。 */\n static messagesFromEvents(events: SessionEvent[]): Message[] {\n const out: Message[] = [];\n for (const ev of events) {\n if (ev.type === \"message\") out.push(ev.message);\n }\n return out;\n }\n\n async append(event: SessionEvent): Promise<void> {\n const line = JSON.stringify(event) + \"\\n\";\n // 串行写入避免交错\n this.writeQueue = this.writeQueue.then(async () => {\n try {\n await mkdir(dirname(this.meta.path), { recursive: true });\n await appendFile(this.meta.path, line, \"utf-8\");\n } catch (err) {\n log.warn(`session append failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n });\n return this.writeQueue;\n }\n\n async readAll(): Promise<SessionEvent[]> {\n if (!existsSync(this.meta.path)) return [];\n const raw = await readFile(this.meta.path, \"utf-8\");\n const events: SessionEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as SessionEvent);\n } catch {\n // skip corrupt lines\n }\n }\n return events;\n }\n}\n\nasync function readSummary(meta: SessionMeta): Promise<SessionSummary> {\n let events: SessionEvent[] = [];\n try {\n const raw = await readFile(meta.path, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as SessionEvent);\n } catch {\n // skip\n }\n }\n } catch {\n // unreadable; return minimal summary\n }\n const messages = events.filter((e): e is Extract<SessionEvent, { type: \"message\" }> => e.type === \"message\");\n const firstUser = messages.find((e) => e.message.role === \"user\");\n let preview: string | undefined;\n if (firstUser) {\n const c = firstUser.message.content;\n const text = typeof c === \"string\" ? c : c.map((p) => (p.type === \"text\" ? p.text : \"\")).join(\" \").trim();\n preview = text.slice(0, 60).replace(/\\s+/g, \" \");\n }\n return { ...meta, preview, messageCount: messages.length };\n}\n","/**\n * Session 内 Todo 清单。\n *\n * 仅存活于单次 muse 进程内,不入 JSONL 持久化(任务清单是 ephemeral 调度状态,\n * 不是对话内容;下次进程恢复 session 时 LLM 应基于历史重建清单)。\n *\n * 工具 TodoWrite 通过 ToolContext.todos 写入;buildSystemPrompt 读出注入下一轮 LLM 的视野。\n */\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface Todo {\n content: string;\n status: TodoStatus;\n /** 进行中状态的现在分词式描述,UI 可用作 spinner 文案。 */\n activeForm?: string;\n}\n\nexport class TodoStore {\n private items: Todo[] = [];\n\n list(): Todo[] {\n return this.items.slice();\n }\n\n set(items: Todo[]): void {\n this.items = items.slice();\n }\n\n clear(): void {\n this.items = [];\n }\n\n /** 把当前清单格式化为 system prompt 段落;无任务时返回空串。 */\n toPromptSection(): string {\n if (this.items.length === 0) return \"\";\n const lines = this.items.map((t, i) => {\n const marker = t.status === \"completed\" ? \"[x]\" : t.status === \"in_progress\" ? \"[~]\" : \"[ ]\";\n return ` ${i + 1}. ${marker} ${t.content}`;\n });\n return `# Current todos\\n${lines.join(\"\\n\")}\\n\\nUpdate via TodoWrite as you make progress. Keep exactly one item in_progress at a time.`;\n }\n}\n","/**\n * Agent loop:单循环 ReAct。\n *\n * loop:\n * llm.stream(messages, tools)\n * → emit text → 累计 assistant 消息\n * → 收到 tool_call → 累计\n * → finish\n * if no tool_calls: break\n * for each tool_call:\n * check permission → execute → push tool result\n */\n\nimport type { LLMClient, LLMEvent } from \"../llm/types.js\";\nimport type { Message, AssistantMessage, ContentPart, ToolUsePart, TokenUsage } from \"../types/index.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\nimport type { ToolContext } from \"../tools/types.js\";\nimport type { PermissionGate, Decision, PermissionDecision } from \"../permission/index.js\";\nimport type { Session } from \"../session/jsonl.js\";\nimport { TodoStore } from \"./todos.js\";\nimport { log } from \"../log/index.js\";\n\nexport interface AgentEvents {\n onText?: (delta: string) => void;\n onToolCallStart?: (id: string, name: string) => void;\n onToolCallArgs?: (id: string, args: unknown) => void;\n onToolResult?: (id: string, name: string, content: string, isError: boolean, summary?: string) => void;\n onPermissionRequest?: (toolName: string, args: unknown, summary: string) => Promise<PermissionDecision>;\n /** AskUserQuestion 工具调用时触发;resolve 把整批答案数组回填给工具。 */\n onAskQuestions?: (\n questions: import(\"../tools/builtin/ask-user-question.js\").AskQuestion[],\n ) => Promise<import(\"../tools/builtin/ask-user-question.js\").AskQuestionResponse[]>;\n onUsage?: (usage: TokenUsage) => void;\n onError?: (error: Error) => void;\n /**\n * 一段 assistant 流结束、assistantMessage 已 push 进 messages,但工具还没开始执行时触发。\n * 用于 UI 立刻把这一批 tool_use calls 显示出来——避免\"流完 → 第一个 result 到达\"\n * 之间用户面对空屏。turn 直接结束(无 tool calls)的场景不会触发,走 onTurnEnd。\n */\n onAssistantTurn?: () => void;\n onTurnEnd?: () => void;\n}\n\nexport interface AgentContext {\n llm: LLMClient;\n tools: ToolRegistry;\n permissions: PermissionGate;\n session: Session;\n cwd: string;\n systemPrompt: string;\n abortSignal?: AbortSignal;\n events?: AgentEvents;\n}\n\nexport class Agent {\n private messages: Message[] = [];\n readonly todos = new TodoStore();\n\n constructor(private ctx: AgentContext) {}\n\n getMessages(): Message[] {\n return this.messages;\n }\n\n setMessages(msgs: Message[]): void {\n this.messages = msgs;\n }\n\n /** 执行一次完整的\"用户输入 → 助手响应(含工具循环) → 等待下一轮输入\"。 */\n async runTurn(userInput: string): Promise<void> {\n const userMessage: Message = { role: \"user\", content: userInput };\n this.messages.push(userMessage);\n await this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: userMessage });\n\n // 内部循环:工具调用可能多轮\n while (true) {\n const mode = this.ctx.permissions.getMode();\n const tools = this.ctx.tools.toLLMDefinitions(\n mode === \"plan\" ? (t) => t.permission === \"read\" : undefined,\n );\n // 每轮把当前 todos 注入 system prompt 末尾,让 LLM 看到自己写的清单\n const todoSection = this.todos.toPromptSection();\n const systemPrompt = todoSection\n ? `${this.ctx.systemPrompt}\\n\\n${todoSection}`\n : this.ctx.systemPrompt;\n const stream = this.ctx.llm.stream({\n messages: this.messages,\n tools,\n systemPrompt,\n abortSignal: this.ctx.abortSignal,\n });\n\n const assistantParts: ContentPart[] = [];\n const toolCallsToRun: ToolUsePart[] = [];\n let lastError: Error | undefined;\n\n for await (const ev of stream) {\n this.handleEvent(ev, assistantParts, toolCallsToRun, (e) => {\n lastError = e;\n });\n if (lastError) break;\n }\n\n if (lastError) {\n this.ctx.events?.onError?.(lastError);\n log.error(\"agent stream error\", { msg: lastError.message });\n return;\n }\n\n // 把 assistant 消息加入历史\n const assistantMessage: AssistantMessage = { role: \"assistant\", content: assistantParts };\n this.messages.push(assistantMessage);\n await this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: assistantMessage });\n\n if (toolCallsToRun.length === 0) {\n this.ctx.events?.onTurnEnd?.();\n return;\n }\n\n // 流刚结束、tool 还没跑——给 UI 一个钩子立刻展示这一批 calls\n this.ctx.events?.onAssistantTurn?.();\n\n // 执行工具调用\n for (const call of toolCallsToRun) {\n await this.runToolCall(call);\n }\n }\n }\n\n private handleEvent(\n ev: LLMEvent,\n assistantParts: ContentPart[],\n toolCallsToRun: ToolUsePart[],\n onError: (e: Error) => void,\n ): void {\n switch (ev.type) {\n case \"text\":\n // 合并到最后一个 text part 或新增\n {\n const last = assistantParts[assistantParts.length - 1];\n if (last && last.type === \"text\") {\n last.text += ev.delta;\n } else {\n assistantParts.push({ type: \"text\", text: ev.delta });\n }\n }\n this.ctx.events?.onText?.(ev.delta);\n break;\n\n case \"tool_call_start\":\n this.ctx.events?.onToolCallStart?.(ev.id, ev.name);\n break;\n\n case \"tool_call_complete\": {\n const callPart: ToolUsePart = { type: \"tool_use\", id: ev.id, name: ev.name, args: ev.args };\n assistantParts.push(callPart);\n toolCallsToRun.push(callPart);\n this.ctx.events?.onToolCallArgs?.(ev.id, ev.args);\n break;\n }\n\n case \"finish\":\n if (ev.usage) {\n this.ctx.events?.onUsage?.(ev.usage);\n this.ctx.session.append({\n type: \"usage\",\n time: new Date().toISOString(),\n usage: ev.usage,\n provider: this.ctx.llm.providerName,\n model: this.ctx.llm.model,\n });\n }\n break;\n\n case \"error\":\n onError(ev.error);\n break;\n }\n }\n\n private async runToolCall(call: ToolUsePart): Promise<void> {\n const tool = this.ctx.tools.get(call.name);\n if (!tool) {\n const result = `Tool \"${call.name}\" is not available.`;\n this.recordToolResult(call.id, call.name, result, true);\n return;\n }\n\n const summary = tool.summarize?.(call.args) ?? `${call.name}(...)`;\n const decision: Decision = this.ctx.permissions.decide({\n toolName: call.name,\n args: call.args,\n permission: tool.permission,\n });\n\n let approved = decision === \"allow\";\n if (decision === \"deny\") {\n const reason =\n this.ctx.permissions.getMode() === \"plan\"\n ? `Denied: you are in plan mode. Only read-only tools are available. Propose changes instead of executing.`\n : `Denied by policy: ${call.name}.`;\n this.recordToolResult(call.id, call.name, reason, true);\n return;\n }\n if (decision === \"ask\") {\n const userDecision =\n (await this.ctx.events?.onPermissionRequest?.(call.name, call.args, summary)) ?? \"no\";\n if (userDecision === \"no\") {\n this.recordToolResult(call.id, call.name, `User rejected ${call.name}.`, true);\n return;\n }\n if (userDecision === \"session_allow\") {\n this.ctx.permissions.allowForSession(call.name);\n }\n approved = true;\n }\n\n const toolCtx: ToolContext = {\n cwd: this.ctx.cwd,\n abortSignal: this.ctx.abortSignal,\n askPermission: async () => true, // 已在外层处理\n todos: this.todos,\n askQuestions: this.ctx.events?.onAskQuestions\n ? (qs) => this.ctx.events!.onAskQuestions!(qs)\n : undefined,\n };\n\n const result = await this.ctx.tools.execute(call.name, call.args, toolCtx);\n this.recordToolResult(call.id, call.name, result.content, result.isError ?? false, result.summary, result.diff, result.kind);\n }\n\n private recordToolResult(\n id: string,\n name: string,\n content: string,\n isError: boolean,\n summary?: string,\n diff?: string,\n kind?: \"success\" | \"error\" | \"warn\",\n ): void {\n const toolMsg: Message = {\n role: \"tool\",\n toolUseId: id,\n content,\n isError,\n toolName: name,\n ...(diff ? { diff } : {}),\n ...(summary ? { summary } : {}),\n ...(kind ? { kind } : {}),\n };\n this.messages.push(toolMsg);\n this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: toolMsg });\n this.ctx.events?.onToolResult?.(id, name, content, isError, summary);\n }\n}\n","/**\n * System prompt 构造。\n *\n * 简短、命令式:把可用工具与运行时约束直接摆出来给 LLM。\n * 中文输出由 ui.lang 控制;英文为默认。\n */\n\nimport { homedir } from \"node:os\";\n\nexport interface SystemPromptOpts {\n cwd: string;\n model: string;\n provider: string;\n lang?: \"en\" | \"zh-CN\";\n toolNames: string[];\n /** MEMORY.md index 内容(loadMemoryIndex 加载后传入);空串视为无 memory。 */\n memoryIndex?: string;\n}\n\nexport function buildSystemPrompt(opts: SystemPromptOpts): string {\n const { cwd, model, provider, lang, toolNames, memoryIndex } = opts;\n const home = homedir();\n const displayCwd = cwd.startsWith(home) ? cwd.replace(home, \"~\") : cwd;\n\n const sections: string[] = [];\n\n sections.push(`You are Muse, a CLI coding assistant. You are running on the user's local machine via a terminal interface.`);\n\n sections.push(\n `# Environment\\n` +\n `- Working directory: ${displayCwd}\\n` +\n `- LLM backend: ${provider} (${model})\\n` +\n `- Date: ${new Date().toISOString().slice(0, 10)}`,\n );\n\n sections.push(\n `# Available tools\\n` +\n toolNames.map((n) => `- ${n}`).join(\"\\n\") +\n `\\n\\nPrefer the dedicated tool over Bash when one fits (Read for file reading, Edit for partial updates, Write for new files / full rewrites, Grep for content search, Glob for file lookup).`,\n );\n\n sections.push(\n `# Behavior\\n` +\n `- Be concise. State results, not your thinking. Don't narrate every step.\\n` +\n `- Before editing a file you have not seen, Read it first.\\n` +\n `- For Write/Edit/Bash the user may need to approve — proceed normally; the host will gate dangerous calls.\\n` +\n `- If a command may be destructive (rm -rf, force push, drop table, etc.), warn first and let the user run it manually.\\n` +\n `- When the user asks a question that does not need tools, just answer.`,\n );\n\n if (toolNames.includes(\"TodoWrite\")) {\n sections.push(\n `# Task management\\n` +\n `- For non-trivial, multi-step work, use TodoWrite to plan and track progress.\\n` +\n `- Keep exactly one task in_progress; mark a task completed immediately when done.\\n` +\n `- Skip it for trivial single-step requests.`,\n );\n }\n\n if (lang === \"zh-CN\") {\n sections.push(`# Output language\\nReply in Chinese (简体中文) unless the user writes in English.`);\n }\n\n if (memoryIndex && memoryIndex.trim()) {\n sections.push(\n `# Memory (long-term)\\n` +\n `Below is MEMORY.md — your index of persistent facts about the user, project, and prior feedback. ` +\n `Each line points at a file you can MemoryRead. Use MemoryWrite to record new durable knowledge ` +\n `(user role/preferences, validated decisions, project facts, external references). Do NOT save things ` +\n `derivable from the repo or git history.\\n\\n` +\n memoryIndex,\n );\n }\n\n return sections.join(\"\\n\\n\");\n}\n","/**\n * 配置加载:\n * 1. 内置默认值\n * 2. ~/.muse/settings.json\n * 3. <cwd>/.muse/settings.json\n * 4. <cwd>/.muse/settings.local.json\n * 5. 环境变量 (MUSE_*)\n * 6. CLI flags (在 cli.tsx 里覆盖)\n *\n * ${ENV_VAR} 占位符在加载后展开。\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport type { z } from \"zod\";\nimport { SettingsSchema, type Settings } from \"./types.js\";\nimport { expandEnvVars } from \"./_env.js\";\nimport { log } from \"../log/index.js\";\n\nfunction formatZodIssues(issues: z.ZodIssue[]): string {\n return issues\n .map((i) => `${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"; \");\n}\n\nconst DEFAULTS: Settings = {\n llm: {\n provider: \"deepseek\",\n model: \"deepseek-chat\",\n },\n providers: {\n deepseek: { apiKey: \"${DEEPSEEK_API_KEY}\" },\n openai: { apiKey: \"${OPENAI_API_KEY}\" },\n qwen: { apiKey: \"${DASHSCOPE_API_KEY}\" },\n moonshot: { apiKey: \"${MOONSHOT_API_KEY}\" },\n zhipu: { apiKey: \"${ZHIPU_API_KEY}\" },\n openrouter: { apiKey: \"${OPENROUTER_API_KEY}\" },\n ollama: { baseUrl: \"http://localhost:11434/v1\" },\n },\n permissions: {\n allow: [\"Read\", \"Grep\", \"Glob\", \"TodoWrite\"],\n ask: [\"Write\", \"Edit\", \"Bash\"],\n deny: [],\n defaultMode: \"ask\",\n },\n ui: {\n showBanner: true,\n lang: \"en\",\n },\n};\n\nasync function readJsonIfExists(path: string): Promise<unknown | undefined> {\n if (!existsSync(path)) return undefined;\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw);\n } catch (err) {\n log.warn(`Failed to parse settings at ${path}: ${err instanceof Error ? err.message : String(err)}`);\n return undefined;\n }\n}\n\n/** 深合并:高优先级覆盖低优先级。对象递归,数组/标量覆盖。 */\nfunction deepMerge<T>(low: T, high: Partial<T>): T {\n if (high == null) return low;\n if (typeof low !== \"object\" || typeof high !== \"object\" || low === null || high === null) {\n return high as T;\n }\n if (Array.isArray(high)) return high as unknown as T;\n const result: Record<string, unknown> = { ...(low as Record<string, unknown>) };\n for (const [k, v] of Object.entries(high)) {\n const existing = (low as Record<string, unknown>)[k];\n if (\n v !== null &&\n typeof v === \"object\" &&\n !Array.isArray(v) &&\n existing !== null &&\n typeof existing === \"object\" &&\n !Array.isArray(existing)\n ) {\n result[k] = deepMerge(existing, v as Record<string, unknown>);\n } else {\n result[k] = v;\n }\n }\n return result as T;\n}\n\nexport interface LoadedSettings {\n settings: Settings;\n sources: string[];\n}\n\nexport async function loadSettings(cwd: string = process.cwd()): Promise<LoadedSettings> {\n const sources: string[] = [\"<defaults>\"];\n let merged: Settings = DEFAULTS;\n\n const candidates = [\n join(homedir(), \".muse\", \"settings.json\"),\n join(cwd, \".muse\", \"settings.json\"),\n join(cwd, \".muse\", \"settings.local.json\"),\n ];\n\n for (const path of candidates) {\n const raw = await readJsonIfExists(path);\n if (raw != null) {\n const parsed = SettingsSchema.safeParse(raw);\n if (parsed.success) {\n merged = deepMerge(merged, parsed.data);\n sources.push(path);\n } else {\n log.warn(`Invalid settings at ${path}: ${formatZodIssues(parsed.error.issues)}`);\n }\n }\n }\n\n // Env overrides for the active LLM\n if (process.env.MUSE_PROVIDER && merged.llm) {\n merged = { ...merged, llm: { ...merged.llm, provider: process.env.MUSE_PROVIDER } };\n sources.push(\"env:MUSE_PROVIDER\");\n }\n if (process.env.MUSE_MODEL && merged.llm) {\n merged = { ...merged, llm: { ...merged.llm, model: process.env.MUSE_MODEL } };\n sources.push(\"env:MUSE_MODEL\");\n }\n\n // 展开 ${ENV_VAR} 占位符\n merged = expandEnvVars(merged) as Settings;\n\n return { settings: merged, sources };\n}\n\nexport { DEFAULTS };\nexport { resolve as resolvePath };\n","/**\n * 配置 schema。对应 ~/.muse/settings.json + .muse/settings.json 的内容。\n */\n\nimport { z } from \"zod\";\n\nexport const ProviderConfigSchema = z.object({\n apiKey: z.string().optional(),\n baseUrl: z.string().optional(),\n extraHeaders: z.record(z.string()).optional(),\n}).passthrough();\n\n// 新设计:model id 由 ~/.muse/models.local.json 提供,settings.json 只保留 active 选择。\n// provider 字段仅用于\"无 models.local.json 时的 fallback 路径\"(设计文档 §8 兼容层)。\n// 因此两者都可选——/models 切换只写 model,不写 provider。\nexport const LLMConfigSchema = z.object({\n provider: z.string().optional().describe(\"Fallback provider preset (only used when no models.local.json entry matches).\"),\n model: z.string().optional().describe(\"Active model id; should match an id in models.local.json.\"),\n temperature: z.number().min(0).max(2).optional(),\n maxTokens: z.number().int().positive().optional(),\n});\n\nexport const PermissionsSchema = z.object({\n allow: z.array(z.string()).optional(),\n ask: z.array(z.string()).optional(),\n deny: z.array(z.string()).optional(),\n defaultMode: z.enum([\"strict\", \"relaxed\", \"ask\"]).optional(),\n});\n\nexport const UISchema = z.object({\n theme: z.enum([\"dark\", \"light\"]).optional(),\n lang: z.enum([\"en\", \"zh-CN\"]).optional(),\n showBanner: z.boolean().optional(),\n});\n\nexport const SettingsSchema = z.object({\n llm: LLMConfigSchema.optional(),\n providers: z.record(ProviderConfigSchema).optional(),\n permissions: PermissionsSchema.optional(),\n ui: UISchema.optional(),\n mcpServers: z.record(z.unknown()).optional(),\n skills: z.object({\n enabled: z.boolean().optional(),\n disabled: z.array(z.string()).optional(),\n }).optional(),\n}).passthrough();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type LLMConfig = z.infer<typeof LLMConfigSchema>;\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\nexport type Permissions = z.infer<typeof PermissionsSchema>;\n","/**\n * ${ENV_VAR} 占位符递归展开。\n *\n * settings.json / models.local.json 都共用这套机制,避免把明文凭证落到可入 git 的文件。\n * 未定义的 env var → 空字符串(不抛错,让上层校验\"必填字段是否非空\"决定行为)。\n */\n\nconst ENV_PATTERN = /\\$\\{([A-Z_][A-Z0-9_]*)\\}/g;\n\nexport function expandEnvVars(value: unknown): unknown {\n if (typeof value === \"string\") {\n return value.replace(ENV_PATTERN, (_match, name) => process.env[name] ?? \"\");\n }\n if (Array.isArray(value)) {\n return value.map(expandEnvVars);\n }\n if (value && typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[k] = expandEnvVars(v);\n }\n return result;\n }\n return value;\n}\n"],"mappings":"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","names":["resolve","tool","resolve","homedir","resolve","readFile","stat","resolve","isAbsolute","dirname","z","z","isAbsolute","resolve","stat","readFile","dirname","readFile","writeFile","resolve","isAbsolute","z","z","isAbsolute","resolve","readFile","writeFile","z","z","truncate","execa","z","z","execa","cliArgs","result","out","z","z","DEFAULT_LIMIT","z","z","z","z","z","mkdir","readFile","writeFile","homedir","join","readFile","mkdir","writeFile","z","z","z","mkdir","readFile","stat","existsSync","homedir","dirname","join","createHash","projectHash","createHash","join","homedir","mkdir","existsSync","stat","dirname","readFile","tool","result","homedir","readFile","existsSync","homedir","join","resolve","z","ENV_PATTERN","existsSync","readFile","join","homedir"]}
|
|
1
|
+
{"version":3,"sources":["../src/llm/providers/openai-compatible.ts","../src/log/index.ts","../src/types/index.ts","../src/llm/client.ts","../src/tools/registry.ts","../src/tools/types.ts","../src/tools/builtin/read.ts","../src/tools/_sensitive.ts","../src/tools/builtin/write.ts","../src/tools/_diff.ts","../src/tools/builtin/edit.ts","../src/tools/builtin/bash.ts","../src/tools/builtin/grep.ts","../src/tools/builtin/glob.ts","../src/tools/builtin/todo.ts","../src/tools/builtin/webfetch.ts","../src/tools/builtin/memory.ts","../src/loop/memory.ts","../src/tools/builtin/ask-user-question.ts","../src/tools/builtin/index.ts","../src/permission/index.ts","../src/session/jsonl.ts","../src/loop/todos.ts","../src/preprocess/types.ts","../src/preprocess/pipeline.ts","../src/loop/system-prompt.ts","../src/loop/hierarchy.ts","../src/loop/memory-index.ts","../src/preprocess/tokenize.ts","../src/preprocess/hooks.ts","../src/loop/prompts/summarize.ts","../src/loop/context.ts","../src/preprocess/request/budget-guard.ts","../src/preprocess/request/ctx.ts","../src/loop/agent.ts","../src/preprocess/truncate.ts","../node_modules/chalk/source/vendor/ansi-styles/index.js","../node_modules/chalk/source/vendor/supports-color/index.js","../node_modules/chalk/source/utilities.js","../node_modules/chalk/source/index.js","../src/preprocess/render/markdown.ts","../src/preprocess/result/ctx.ts","../src/config/loader.ts","../src/config/types.ts","../src/config/_env.ts"],"sourcesContent":["/**\n * OpenAI 兼容协议 provider。\n * 覆盖:OpenAI 官方、DeepSeek、Qwen、Moonshot (Kimi)、智谱、OpenRouter、Ollama (其 /v1 endpoint)、自建 vLLM/LocalAI 等。\n *\n * Why 自己包一层而不是直接用 @ai-sdk/openai-compatible:\n * - 抹平 stream 事件差异,统一为本仓库的 LLMEvent 类型\n * - 在 stream 中拼装 tool_call.arguments(OpenAI 流式 tool_call 是分片增量的 JSON 字符串)\n * - 留口子未来插入降级、重试、token 计数估算\n */\n\nimport { createOpenAICompatible } from \"@ai-sdk/openai-compatible\";\nimport { streamText, jsonSchema, tool, type CoreMessage, type ToolSet } from \"ai\";\nimport type {\n LLMClient,\n LLMEvent,\n ModelCapabilities,\n ProviderConfig,\n StreamOptions,\n} from \"../types.js\";\nimport type { Message, AssistantMessage, ToolDefinition, ContentPart } from \"../../types/index.js\";\nimport { log, redactApiKey } from \"../../log/index.js\";\n\ninterface OpenAICompatibleProviderOpts {\n providerName: string;\n baseUrl: string;\n apiKey: string;\n model: string;\n capabilities?: Partial<ModelCapabilities>;\n}\n\nconst DEFAULT_CAPABILITIES: ModelCapabilities = {\n toolCalling: true,\n parallelToolCalls: true,\n vision: false,\n jsonMode: true,\n // 没在 models.local.json 显式声明 contextWindow 时的兜底值。\n // 200k 是 2026 年主流 LLM(GPT-4.1 / Claude / DeepSeek-v3 / Qwen-Plus / GLM-4 等)的\n // 常见容量,比 32k 兜底更接近真实,避免 ctx% 大幅虚高 / auto-compact 过早触发。\n // 仍建议在每条 entry 显式写 contextWindow,避免依赖默认值。\n maxContextWindow: 200_000,\n};\n\nexport class OpenAICompatibleClient implements LLMClient {\n readonly providerName: string;\n readonly model: string;\n readonly capabilities: ModelCapabilities;\n private modelProvider: ReturnType<ReturnType<typeof createOpenAICompatible>>;\n\n constructor(opts: OpenAICompatibleProviderOpts) {\n this.providerName = opts.providerName;\n this.model = opts.model;\n this.capabilities = { ...DEFAULT_CAPABILITIES, ...opts.capabilities };\n\n const provider = createOpenAICompatible({\n name: opts.providerName,\n baseURL: opts.baseUrl,\n apiKey: opts.apiKey,\n });\n this.modelProvider = provider(opts.model);\n\n log.debug(\"LLM provider initialized\", {\n provider: opts.providerName,\n model: opts.model,\n baseUrl: opts.baseUrl,\n apiKey: redactApiKey(opts.apiKey),\n });\n }\n\n async *stream(opts: StreamOptions): AsyncIterable<LLMEvent> {\n const { messages, tools, systemPrompt, temperature, maxTokens, abortSignal } = opts;\n\n const aiMessages = convertMessages(messages, systemPrompt);\n const aiTools = tools ? convertTools(tools) : undefined;\n\n // 重试:仅在还没收到任何 chunk 时(连接级错误)退避重试,最多 3 次\n let attempt = 0;\n const maxAttempts = 3;\n let result: ReturnType<typeof streamText> | undefined;\n while (true) {\n try {\n result = streamText({\n model: this.modelProvider,\n messages: aiMessages,\n tools: aiTools,\n temperature,\n maxTokens,\n abortSignal,\n });\n break;\n } catch (err) {\n if (abortSignal?.aborted) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n return;\n }\n if (!isRetryable(err) || attempt >= maxAttempts - 1) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n return;\n }\n const delay = 1000 * Math.pow(2, attempt);\n log.warn(`LLM connect failed (attempt ${attempt + 1}/${maxAttempts}); retrying in ${delay}ms`, {\n msg: err instanceof Error ? err.message : String(err),\n });\n await sleep(delay, abortSignal);\n attempt += 1;\n }\n }\n\n if (!result) {\n yield { type: \"error\", error: new Error(\"Internal: stream result is undefined after retry loop.\") };\n return;\n }\n const stream = result.fullStream;\n\n try {\n const seenToolCalls = new Set<string>();\n\n for await (const part of stream) {\n switch (part.type) {\n case \"text-delta\":\n yield { type: \"text\", delta: part.textDelta };\n break;\n\n case \"tool-call\":\n if (!seenToolCalls.has(part.toolCallId)) {\n seenToolCalls.add(part.toolCallId);\n yield { type: \"tool_call_start\", id: part.toolCallId, name: part.toolName };\n }\n yield {\n type: \"tool_call_complete\",\n id: part.toolCallId,\n name: part.toolName,\n args: part.args,\n };\n break;\n\n case \"finish\":\n yield {\n type: \"finish\",\n reason: mapFinishReason(part.finishReason),\n usage: part.usage\n ? {\n inputTokens: part.usage.promptTokens ?? 0,\n outputTokens: part.usage.completionTokens ?? 0,\n totalTokens: part.usage.totalTokens ?? 0,\n }\n : undefined,\n };\n break;\n\n case \"error\":\n yield { type: \"error\", error: part.error instanceof Error ? part.error : new Error(String(part.error)) };\n break;\n\n default:\n // 忽略其它(如 step-start / step-finish / tool-call-streaming-start 等)\n break;\n }\n }\n } catch (err) {\n yield { type: \"error\", error: err instanceof Error ? err : new Error(String(err)) };\n }\n }\n}\n\n// ---------- helpers ----------\n\nfunction convertMessages(messages: Message[], systemPrompt?: string): CoreMessage[] {\n const result: CoreMessage[] = [];\n if (systemPrompt) {\n result.push({ role: \"system\", content: systemPrompt });\n }\n for (const msg of messages) {\n switch (msg.role) {\n case \"system\":\n result.push({ role: \"system\", content: msg.content });\n break;\n case \"user\":\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else {\n result.push({ role: \"user\", content: convertUserParts(msg.content) });\n }\n break;\n case \"assistant\":\n result.push({ role: \"assistant\", content: convertAssistantContent(msg) });\n break;\n case \"tool\":\n result.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: msg.toolUseId,\n toolName: \"_tool\",\n result: msg.content,\n isError: msg.isError ?? false,\n },\n ],\n });\n break;\n }\n }\n return result;\n}\n\ntype UserContent = Extract<CoreMessage, { role: \"user\" }>[\"content\"];\ntype UserPart = Exclude<UserContent, string>[number];\n\n/**\n * 把 muse 的 user ContentPart[] 转 Vercel AI SDK UserContent。\n *\n * 策略:\n * - text 直通\n * - image → SDK ImagePart(SDK 内部按 provider 翻译为 image_url 等)\n * - file → **降级为 text part 用 XML wrap**。原因:OpenAI Chat Completions 协议\n * 与多数兼容 provider 不支持 file part(只有 Assistants API 才有);把文本文件\n * 直接 wrap 进 text 在所有 provider 上都能工作,不依赖能力探测。\n * - tool_use / tool_result 在 user role 不出现,跳过\n */\n// 仅为测试导出 — 业务代码通过 convertMessages 间接调用\nexport function convertUserParts(parts: ContentPart[]): UserContent {\n const out: UserPart[] = [];\n for (const part of parts) {\n if (part.type === \"text\") {\n out.push({ type: \"text\", text: part.text });\n } else if (part.type === \"image\") {\n out.push({\n type: \"image\",\n // SDK 接受 base64 字符串作为 DataContent\n image: part.data,\n mimeType: part.mediaType,\n });\n } else if (part.type === \"file\") {\n // 退化为 text wrap\n out.push({\n type: \"text\",\n text: `<file path=\"${part.path}\"${part.mimeType ? ` mimeType=\"${part.mimeType}\"` : \"\"}>\\n${part.text}\\n</file>`,\n });\n }\n // tool_use / tool_result 在 user role 不应该出现,丢\n }\n if (out.length === 0) return \"\";\n // 全 text 时 join 成 string 更紧凑,行为也与 string-content 用户消息等同\n if (out.every((p) => p.type === \"text\")) {\n return (out as Array<{ type: \"text\"; text: string }>).map((p) => p.text).join(\"\\n\\n\");\n }\n return out;\n}\n\ntype AssistantContent = Extract<CoreMessage, { role: \"assistant\" }>[\"content\"];\n\nfunction convertAssistantContent(msg: AssistantMessage): AssistantContent {\n const parts: Array<\n { type: \"text\"; text: string } | { type: \"tool-call\"; toolCallId: string; toolName: string; args: unknown }\n > = [];\n for (const part of msg.content) {\n if (part.type === \"text\") {\n parts.push({ type: \"text\", text: part.text });\n } else if (part.type === \"tool_use\") {\n parts.push({\n type: \"tool-call\",\n toolCallId: part.id,\n toolName: part.name,\n args: part.args,\n });\n }\n }\n // 至少要有一个内容;空数组 SDK 会报错\n if (parts.length === 0) return \"\";\n return parts as AssistantContent;\n}\n\nfunction convertTools(tools: ToolDefinition[]): ToolSet {\n const result: ToolSet = {};\n for (const t of tools) {\n result[t.name] = tool({\n description: t.description,\n parameters: jsonSchema(t.parameters as Parameters<typeof jsonSchema>[0]),\n });\n }\n return result;\n}\n\nfunction isRetryable(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n const code = (err as Error & { code?: string }).code ?? \"\";\n if (\n code === \"ECONNRESET\" ||\n code === \"ETIMEDOUT\" ||\n code === \"ENOTFOUND\" ||\n code === \"ECONNREFUSED\" ||\n code === \"EAI_AGAIN\"\n ) {\n return true;\n }\n if (\n msg.includes(\"fetch failed\") ||\n msg.includes(\"network\") ||\n msg.includes(\"socket hang up\") ||\n msg.includes(\"under maintenance\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"429\") ||\n msg.includes(\"502\") ||\n msg.includes(\"503\") ||\n msg.includes(\"504\")\n ) {\n return true;\n }\n return false;\n}\n\nasync function sleep(ms: number, abortSignal?: AbortSignal): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n if (abortSignal?.aborted) return reject(new Error(\"aborted\"));\n const t = setTimeout(() => {\n abortSignal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n abortSignal?.removeEventListener(\"abort\", onAbort);\n reject(new Error(\"aborted\"));\n };\n abortSignal?.addEventListener(\"abort\", onAbort);\n });\n}\n\nfunction mapFinishReason(reason: string | undefined): \"stop\" | \"tool_calls\" | \"length\" | \"content_filter\" | \"error\" | \"unknown\" {\n switch (reason) {\n case \"stop\":\n case \"stop-sequence\":\n return \"stop\";\n case \"tool-calls\":\n case \"tool_calls\":\n return \"tool_calls\";\n case \"length\":\n return \"length\";\n case \"content-filter\":\n case \"content_filter\":\n return \"content_filter\";\n case \"error\":\n return \"error\";\n default:\n return \"unknown\";\n }\n}\n\n// ---------- 预设 provider 工厂 ----------\n\nexport interface PresetConfig {\n baseUrl: string;\n defaultModel: string;\n capabilities?: Partial<ModelCapabilities>;\n}\n\nexport const PRESETS: Record<string, PresetConfig> = {\n openai: {\n baseUrl: \"https://api.openai.com/v1\",\n defaultModel: \"gpt-4o-mini\",\n },\n deepseek: {\n baseUrl: \"https://api.deepseek.com/v1\",\n defaultModel: \"deepseek-chat\",\n capabilities: { maxContextWindow: 128_000 },\n },\n qwen: {\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n defaultModel: \"qwen-plus\",\n capabilities: { maxContextWindow: 128_000 },\n },\n moonshot: {\n baseUrl: \"https://api.moonshot.cn/v1\",\n defaultModel: \"moonshot-v1-32k\",\n capabilities: { maxContextWindow: 32_000 },\n },\n zhipu: {\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n defaultModel: \"glm-4-flash\",\n capabilities: { maxContextWindow: 128_000 },\n },\n ollama: {\n baseUrl: \"http://localhost:11434/v1\",\n defaultModel: \"llama3.1\",\n capabilities: { maxContextWindow: 8_000 },\n },\n openrouter: {\n baseUrl: \"https://openrouter.ai/api/v1\",\n defaultModel: \"openai/gpt-4o-mini\",\n },\n};\n\nexport function createPresetClient(\n providerName: string,\n config: ProviderConfig,\n model?: string,\n): OpenAICompatibleClient {\n const preset = PRESETS[providerName];\n if (!preset) {\n throw new Error(`Unknown provider preset: ${providerName}. Available: ${Object.keys(PRESETS).join(\", \")}`);\n }\n return new OpenAICompatibleClient({\n providerName,\n baseUrl: (config.baseUrl as string | undefined) ?? preset.baseUrl,\n apiKey: (config.apiKey as string | undefined) ?? \"\",\n model: model ?? preset.defaultModel,\n capabilities: preset.capabilities,\n });\n}\n","/**\n * Logger 包装。第一版用最朴素的 console + 文件追加;后期可替换 pino。\n * Why 不直接用 pino: 简化首版依赖图,等可观测性章节再上 pino。\n */\n\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LEVELS: Record<LogLevel, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n};\n\ninterface LogEntry {\n time: string;\n level: LogLevel;\n msg: string;\n [key: string]: unknown;\n}\n\nclass Logger {\n private level: LogLevel = \"info\";\n private logPath: string;\n private fileEnabled = true;\n /**\n * 是否把 warn/error 同时打到 stderr。**默认 false**,因为 Ink TUI 会捕获 stderr\n * 渲染区,造成 \"[error] xxx\" 拼接到 PermissionModeBar / footer 等正常 UI 后面的\n * 视觉污染(B-19 修复)。需要 stderr 输出的场景(cli.tsx die / runOneShot)\n * 都已经在用 process.stderr.write 显式打,不依赖 logger。\n *\n * 单元测试 / 后台脚本可显式 setStderrEnabled(true) 开启。\n */\n private stderrEnabled = false;\n\n constructor() {\n const date = new Date().toISOString().slice(0, 10);\n this.logPath = join(homedir(), \".muse\", \"logs\", `${date}.jsonl`);\n try {\n mkdirSync(dirname(this.logPath), { recursive: true });\n } catch {\n this.fileEnabled = false;\n }\n }\n\n setLevel(level: LogLevel) {\n this.level = level;\n }\n\n setStderrEnabled(enabled: boolean) {\n this.stderrEnabled = enabled;\n }\n\n private write(level: LogLevel, msg: string, extra?: Record<string, unknown>) {\n if (LEVELS[level] < LEVELS[this.level]) return;\n const entry: LogEntry = {\n time: new Date().toISOString(),\n level,\n msg,\n ...extra,\n };\n if (this.fileEnabled) {\n try {\n appendFileSync(this.logPath, JSON.stringify(entry) + \"\\n\");\n } catch {\n // 落盘失败不阻断主流程\n }\n }\n // 默认不写 stderr,避免污染 Ink TUI 渲染区\n if (this.stderrEnabled && (level === \"warn\" || level === \"error\")) {\n const prefix = level === \"error\" ? \"[error]\" : \"[warn]\";\n process.stderr.write(`${prefix} ${msg}\\n`);\n }\n }\n\n trace(msg: string, extra?: Record<string, unknown>) { this.write(\"trace\", msg, extra); }\n debug(msg: string, extra?: Record<string, unknown>) { this.write(\"debug\", msg, extra); }\n info(msg: string, extra?: Record<string, unknown>) { this.write(\"info\", msg, extra); }\n warn(msg: string, extra?: Record<string, unknown>) { this.write(\"warn\", msg, extra); }\n error(msg: string, extra?: Record<string, unknown>) { this.write(\"error\", msg, extra); }\n}\n\nexport const log = new Logger();\n\n/** API key 脱敏:前 4 后 4,中间打码。 */\nexport function redactApiKey(key: string | undefined): string {\n if (!key) return \"<unset>\";\n if (key.length <= 12) return \"***\";\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n","/**\n * 全局共享类型。其它模块按需 re-export 子集。\n * Why 集中:避免类型循环依赖。\n */\n\n// ---------- 消息(与 LLM 交互的最小单元)----------\n\nexport type MessageRole = \"system\" | \"user\" | \"assistant\" | \"tool\";\n\nexport interface TextPart {\n type: \"text\";\n text: string;\n}\n\n/**\n * 通过 @file 引用进来的纯文本文件附件。\n *\n * 设计:作为独立 part 而不是 wrap XML 拼进 text,目的让 PDF / audio / video 等\n * 后续多模态 part 进来时不动协议层(模块设计/消息预处理工程/设计.md 等讨论 §1)。\n *\n * 下游 LLM client 视 provider 能力序列化:\n * - 支持 file part 的 provider → 原生 file part\n * - 不支持的 provider → 退化为 text wrap `<file path=\"...\">…</file>`\n */\nexport interface FilePart {\n type: \"file\";\n path: string;\n /** RFC 6838 mime type;text/x-typescript / text/markdown 等;不强约束,信息性。 */\n mimeType?: string;\n /** 文本内容(utf-8)。 */\n text: string;\n}\n\n/**\n * 图片附件(@image.png 或拖拽 / 粘贴)。\n *\n * 用 base64 data URI 模式存,序列化为 OpenAI 兼容协议的 image_url part。\n */\nexport interface ImagePart {\n type: \"image\";\n /** image/png / image/jpeg / image/webp / image/gif。 */\n mediaType: string;\n /** base64 编码的图片字节。 */\n data: string;\n /** 来源路径(若有),用于 UI 展示与 LLM 上下文。 */\n path?: string;\n}\n\nexport interface ToolUsePart {\n type: \"tool_use\";\n id: string;\n name: string;\n args: unknown;\n}\n\nexport interface ToolResultPart {\n type: \"tool_result\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n}\n\nexport type ContentPart = TextPart | FilePart | ImagePart | ToolUsePart | ToolResultPart;\n\nexport interface SystemMessage {\n role: \"system\";\n content: string;\n}\n\nexport interface UserMessage {\n role: \"user\";\n content: string | ContentPart[];\n}\n\nexport interface AssistantMessage {\n role: \"assistant\";\n content: ContentPart[];\n}\n\nexport interface ToolMessage {\n role: \"tool\";\n toolUseId: string;\n content: string;\n isError?: boolean;\n /** Unified diff for UI display only (Write/Edit). Not sent to LLM. */\n diff?: string;\n /** UI-only one-line summary; if absent, UI falls back to content first line. */\n summary?: string;\n /** UI-only status dot color: success(green) / error(red) / warn(yellow). Default derived from isError. */\n kind?: \"success\" | \"error\" | \"warn\";\n /** 产生该结果的工具名;UI 据此做工具专属渲染(如 TodoWrite 隐藏结果行)。 */\n toolName?: string;\n}\n\nexport type Message = SystemMessage | UserMessage | AssistantMessage | ToolMessage;\n\n// ---------- LLM 工具定义(暴露给模型)----------\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n parameters: Record<string, unknown>; // JSON Schema\n}\n\n// ---------- Token 用量 ----------\n\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n}\n\nexport type FinishReason = \"stop\" | \"tool_calls\" | \"length\" | \"content_filter\" | \"error\" | \"unknown\";\n\n// ---------- 错误 ----------\n\nexport class MuseError extends Error {\n constructor(message: string, public readonly code?: string, public readonly cause?: unknown) {\n super(message);\n this.name = \"MuseError\";\n }\n}\n\nexport class ToolError extends MuseError {\n constructor(message: string, public readonly toolName: string, cause?: unknown) {\n super(message, \"TOOL_ERROR\", cause);\n this.name = \"ToolError\";\n }\n}\n\nexport class PermissionDeniedError extends MuseError {\n constructor(public readonly toolName: string, public readonly reason: string) {\n super(`Permission denied for ${toolName}: ${reason}`, \"PERMISSION_DENIED\");\n this.name = \"PermissionDeniedError\";\n }\n}\n","/**\n * LLMClient 工厂:根据配置创建对应 provider 的客户端。\n *\n * 当前只实现 openai-compatible 协议族(覆盖 95% 国产模型 + OpenAI 本身)。\n * Anthropic 走自己的协议,留待 v0.3 加。\n */\n\nimport { createPresetClient, PRESETS, OpenAICompatibleClient } from \"./providers/index.js\";\nimport type { LLMClient, ModelCapabilities, ProviderConfig } from \"./types.js\";\nimport { MuseError } from \"../types/index.js\";\nimport type { ModelEntry } from \"../config/models.js\";\n\nexport interface CreateClientOpts {\n provider: string;\n model: string;\n providers: Record<string, ProviderConfig>;\n}\n\n/**\n * 当前 active model 的 apiKey 注入到此进程 env 字段下。\n *\n * 业务代码(LLM client)只看到 env name,不直接持有 key 副本。\n * /model 切换或启动加载时由 setActiveModelEnv() 写入;从这里读出来给 client。\n */\nexport const ACTIVE_API_KEY_ENV = \"MUSE_ACTIVE_API_KEY\";\n\n/** 把 entry 的 apiKey 注入 process.env,供 createLLMClientFromModelEntry 读取。 */\nexport function setActiveModelEnv(entry: ModelEntry): void {\n if (entry.apiKey) {\n process.env[ACTIVE_API_KEY_ENV] = entry.apiKey;\n } else {\n delete process.env[ACTIVE_API_KEY_ENV];\n }\n}\n\n/**\n * 从用户在 models.local.json 里定义的 ModelEntry 构造 LLMClient。\n *\n * apiKey 不直接传值——而是从 process.env[ACTIVE_API_KEY_ENV] 读,调用前必须先\n * setActiveModelEnv(entry) 写入。这样业务代码只看到 env name,不直接持有 key。\n *\n * vendor 字段仅用于显示(providerName 显示在 banner / /status)。\n * 当前所有 entry 走 openai-compatible 协议;未来引入其他协议时按 entry.protocol 分流。\n */\nexport function createLLMClientFromModelEntry(entry: ModelEntry): LLMClient {\n const apiKey = process.env[ACTIVE_API_KEY_ENV] ?? \"\";\n if (!apiKey && !entry.baseUrl.includes(\"localhost\")) {\n throw new MuseError(buildMissingKeyMessage(entry), \"MISSING_API_KEY\");\n }\n const capabilities: Partial<ModelCapabilities> = {};\n if (entry.supportsToolCall !== undefined) capabilities.toolCalling = entry.supportsToolCall;\n if (entry.supportsImages !== undefined) capabilities.vision = entry.supportsImages;\n if (entry.contextWindow !== undefined) capabilities.maxContextWindow = entry.contextWindow;\n\n return new OpenAICompatibleClient({\n providerName: entry.vendor ?? \"custom\",\n baseUrl: entry.baseUrl,\n apiKey,\n model: entry.id,\n capabilities,\n });\n}\n\n/**\n * 用户向报错:当 apiKey 是 ${VAR} 占位符但 VAR 没设时,告诉用户具体缺哪个 env var\n * 和三种修复方式;不是占位符 / 直接缺字段时退化为通用提示。\n */\nfunction buildMissingKeyMessage(entry: ModelEntry): string {\n const envVars = ((entry as { _apiKeyEnvVars?: string[] })._apiKeyEnvVars ?? []).filter(\n (v) => !process.env[v],\n );\n const head = `Model \"${entry.id}\" needs an API key but none was found.`;\n\n if (envVars.length > 0) {\n const list = envVars.map((v) => `$${v}`).join(\", \");\n const fixVar = envVars[0];\n return [\n head,\n ``,\n `Cause: ~/.muse/models.local.json sets apiKey to a placeholder referencing ${list},`,\n ` but the shell environment does not have ${envVars.length > 1 ? \"those variables\" : \"that variable\"} set.`,\n ``,\n `Fix (pick one):`,\n ` 1. Replace the \\${${fixVar}} placeholder in ~/.muse/models.local.json with the literal key`,\n ` (recommended — the file is local-only and never enters git).`,\n ` 2. Export the variable in your shell:`,\n ` export ${fixVar}=<your-key>`,\n ].join(\"\\n\");\n }\n\n return [\n head,\n ``,\n `Edit ~/.muse/models.local.json and set \"apiKey\" on the \"${entry.id}\" entry`,\n `(plain text is fine — the file stays local-only).`,\n ].join(\"\\n\");\n}\n\nexport function createLLMClient(opts: CreateClientOpts): LLMClient {\n const { provider, model, providers } = opts;\n const config = providers[provider];\n\n if (!config) {\n throw new MuseError(\n `Provider \"${provider}\" is not configured. Add a \"providers.${provider}\" entry to your settings.json.`,\n \"PROVIDER_NOT_CONFIGURED\",\n );\n }\n\n // 预设 provider(含国产模型)\n if (PRESETS[provider]) {\n if (!config.apiKey && provider !== \"ollama\") {\n throw new MuseError(\n `Provider \"${provider}\" requires apiKey. Set it in settings.json or via the corresponding env var.`,\n \"MISSING_API_KEY\",\n );\n }\n return createPresetClient(provider, config, model);\n }\n\n // 自定义 openai-compatible 端点\n if (config.baseUrl) {\n return new OpenAICompatibleClient({\n providerName: provider,\n baseUrl: config.baseUrl as string,\n apiKey: (config.apiKey as string | undefined) ?? \"\",\n model,\n });\n }\n\n throw new MuseError(\n `Unknown provider \"${provider}\". Either use a preset (${Object.keys(PRESETS).join(\", \")}) or set \"baseUrl\" in providers.${provider}.`,\n \"UNKNOWN_PROVIDER\",\n );\n}\n","/**\n * 工具注册中心:管理所有可用工具,提供查询、调用、转 LLM-tool-definition 的能力。\n */\n\nimport { z } from \"zod\";\nimport type { AnyTool, ToolContext, ToolExecuteResult } from \"./types.js\";\nimport type { ToolDefinition as LLMToolDefinition } from \"../types/index.js\";\nimport { ToolError } from \"../types/index.js\";\n\n/** zod schema → JSON Schema (subset)。仅覆盖 v0.1 需要的类型。 */\nfunction zodToJsonSchema(schema: z.ZodType<unknown>): Record<string, unknown> {\n const def = (schema as unknown as { _def: { typeName: string } })._def;\n\n if (def.typeName === \"ZodObject\") {\n const shape = (schema as unknown as z.ZodObject<Record<string, z.ZodTypeAny>>).shape;\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = zodToJsonSchema(value as z.ZodType<unknown>);\n if (!(value as unknown as { isOptional?: () => boolean }).isOptional?.()) {\n required.push(key);\n }\n }\n return {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n additionalProperties: false,\n };\n }\n\n if (def.typeName === \"ZodString\") {\n const d = def as unknown as { description?: string };\n return { type: \"string\", ...(d.description ? { description: d.description } : {}) };\n }\n\n if (def.typeName === \"ZodNumber\") {\n return { type: \"number\" };\n }\n\n if (def.typeName === \"ZodBoolean\") {\n return { type: \"boolean\" };\n }\n\n if (def.typeName === \"ZodArray\") {\n const inner = (def as unknown as { type: z.ZodType<unknown> }).type;\n return { type: \"array\", items: zodToJsonSchema(inner) };\n }\n\n if (def.typeName === \"ZodOptional\" || def.typeName === \"ZodDefault\") {\n const inner = (def as unknown as { innerType: z.ZodType<unknown> }).innerType;\n return zodToJsonSchema(inner);\n }\n\n if (def.typeName === \"ZodEnum\") {\n const values = (def as unknown as { values: string[] }).values;\n return { type: \"string\", enum: values };\n }\n\n if (def.typeName === \"ZodUnion\") {\n const opts = (def as unknown as { options: z.ZodType<unknown>[] }).options;\n return { anyOf: opts.map(zodToJsonSchema) };\n }\n\n // Fallback: 任意类型\n return {};\n}\n\nfunction getDescription(schema: z.ZodType<unknown>): string | undefined {\n return (schema as unknown as { description?: string }).description;\n}\n\nexport class ToolRegistry {\n private tools = new Map<string, AnyTool>();\n\n register(tool: AnyTool): void {\n if (this.tools.has(tool.name)) {\n throw new Error(`Tool \"${tool.name}\" already registered.`);\n }\n this.tools.set(tool.name, tool);\n }\n\n registerAll(tools: AnyTool[]): void {\n for (const tool of tools) this.register(tool);\n }\n\n get(name: string): AnyTool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): AnyTool[] {\n return Array.from(this.tools.values());\n }\n\n /** 转为 LLM 可读的 tool definition 数组。可选 filter(如 plan 模式过滤只读工具)。 */\n toLLMDefinitions(filter?: (tool: AnyTool) => boolean): LLMToolDefinition[] {\n let tools = this.list();\n if (filter) tools = tools.filter(filter);\n return tools.map((t) => {\n const schema = zodToJsonSchema(t.parameters);\n // 顶层描述:从 zod schema 的 .describe 拿\n const desc = getDescription(t.parameters);\n if (desc && typeof schema === \"object\" && schema !== null) {\n (schema as Record<string, unknown>).description = desc;\n }\n return {\n name: t.name,\n description: t.description,\n parameters: schema,\n };\n });\n }\n\n /** 调用工具:校验参数 → 执行。 */\n async execute(name: string, rawArgs: unknown, ctx: ToolContext): Promise<ToolExecuteResult> {\n const tool = this.tools.get(name);\n if (!tool) {\n throw new ToolError(`Tool \"${name}\" not found.`, name);\n }\n const parseResult = tool.parameters.safeParse(rawArgs);\n if (!parseResult.success) {\n return {\n content: `Invalid arguments for ${name}: ${parseResult.error.message}`,\n isError: true,\n };\n }\n try {\n return await tool.execute(parseResult.data, ctx);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { content: `Tool ${name} threw: ${msg}`, isError: true };\n }\n }\n}\n","/**\n * 工具系统类型。\n * 内置工具与 MCP 工具都遵循同一接口。\n */\n\nimport type { z } from \"zod\";\nimport type { TodoStore } from \"../loop/todos.js\";\nimport type { AskQuestion, AskQuestionResponse } from \"./builtin/ask-user-question.js\";\n\nexport type PermissionLevel = \"read\" | \"write\" | \"execute\" | \"network\";\n\nexport interface ToolContext {\n cwd: string;\n abortSignal?: AbortSignal;\n /** 询问用户对该工具调用的批准。返回 true=允许,false=拒绝。 */\n askPermission: (toolName: string, args: unknown, summary: string) => Promise<boolean>;\n /** 主代理可能想在工具内部发起子任务,预留口子。 */\n invokeSubagent?: (prompt: string) => Promise<string>;\n /** Session 内 todo 清单(TodoWrite 写入;system prompt 读取注入下一轮)。 */\n todos?: TodoStore;\n /**\n * AskUserQuestion 工具用:一次性弹出整批选择题(链式 tab UI)。\n * 返回数组与入参 questions 等长;Esc 取消时所有项 cancelled=true。\n */\n askQuestions?: (questions: AskQuestion[]) => Promise<AskQuestionResponse[]>;\n}\n\nexport interface ToolExecuteResult {\n /** 给 LLM 看的文本结果。 */\n content: string;\n /** 标记为错误:让 LLM 知道需要修复。 */\n isError?: boolean;\n /** 给 TUI 展示的摘要(一行)。 */\n summary?: string;\n /** Unified diff(Write/Edit 等改文件工具填),交给 UI 渲染绿/红行;不进 LLM 上下文。 */\n diff?: string;\n /** 状态点颜色(仅 UI):success 绿 / error 红 / warn 黄。不填则由 isError 推断。 */\n kind?: \"success\" | \"error\" | \"warn\";\n}\n\nexport interface ToolDefinition<TArgs = unknown> {\n name: string;\n description: string;\n /** zod schema 用于参数校验 + 自动转 JSON Schema。 */\n parameters: z.ZodType<TArgs>;\n /** 权限级别:UI 与 permission 模块据此决定 ask/allow/deny。 */\n permission: PermissionLevel;\n /** 一行摘要,给 TUI 在 \"→ ToolName(...)\" 之后显示。 */\n summarize?: (args: TArgs) => string;\n /** 实际执行函数。 */\n execute: (args: TArgs, ctx: ToolContext) => Promise<ToolExecuteResult>;\n}\n\n/** 类型擦除后的工具,用于 registry 存储 / 调用。 */\nexport interface AnyTool {\n name: string;\n description: string;\n parameters: z.ZodType<unknown>;\n permission: PermissionLevel;\n summarize?: (args: unknown) => string;\n execute: (args: unknown, ctx: ToolContext) => Promise<ToolExecuteResult>;\n}\n\nexport function defineTool<TArgs>(def: ToolDefinition<TArgs>): AnyTool {\n return {\n name: def.name,\n description: def.description,\n parameters: def.parameters as z.ZodType<unknown>,\n permission: def.permission,\n summarize: def.summarize as ((args: unknown) => string) | undefined,\n execute: def.execute as (args: unknown, ctx: ToolContext) => Promise<ToolExecuteResult>,\n };\n}\n","/**\n * Read 工具:读取本地文件,支持 offset/limit 分页。\n * 返回带行号的 `cat -n` 格式,方便 LLM 引用具体行做编辑。\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { ToolError } from \"../../types/index.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst ReadArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n offset: z.number().int().min(0).optional().describe(\"Line offset (0-based).\"),\n limit: z.number().int().positive().optional().describe(\"Max lines to read. Default 2000.\"),\n});\n\nconst DEFAULT_LIMIT = 2000;\nconst MAX_LINE_LENGTH = 2000; // 单行超长时截断\n\nexport const ReadTool = defineTool({\n name: \"Read\",\n description: \"Read a file from the local filesystem. Returns content with 1-indexed line numbers (cat -n format). Use offset/limit for large files.\",\n parameters: ReadArgs,\n permission: \"read\",\n summarize: (args) => `Read(${args.file_path}${args.offset != null ? `, offset=${args.offset}` : \"\"}${args.limit != null ? `, limit=${args.limit}` : \"\"})`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let info;\n try {\n info = await stat(path);\n } catch (err) {\n throw new ToolError(`File not found: ${path}`, \"Read\", err);\n }\n\n if (!info.isFile()) {\n throw new ToolError(`Not a regular file: ${path}`, \"Read\");\n }\n\n const content = await readFile(path, \"utf-8\");\n const lines = content.split(/\\r?\\n/);\n const offset = args.offset ?? 0;\n const limit = args.limit ?? DEFAULT_LIMIT;\n const slice = lines.slice(offset, offset + limit);\n\n const numbered = slice.map((line, i) => {\n const lineNo = offset + i + 1;\n const truncated = line.length > MAX_LINE_LENGTH ? line.slice(0, MAX_LINE_LENGTH) + \"... [truncated]\" : line;\n return `${String(lineNo).padStart(5, \" \")}\\t${truncated}`;\n });\n\n let result = numbered.join(\"\\n\");\n if (offset + limit < lines.length) {\n result += `\\n... [${lines.length - offset - limit} more lines, use offset=${offset + limit} to read next]`;\n }\n\n return {\n content: result || \"(empty file)\",\n summary: `Read ${slice.length} lines from ${args.file_path}`,\n };\n },\n});\n","/**\n * 敏感文件路径默认 deny。设计文档 §12.3。\n *\n * 工具层做硬拦截(不通过 PermissionGate)。即使 settings.permissions.allow 加了 Read/Write,\n * 这层也兜底;用户要绕过必须在 PermissionGate 之外显式同意(v1.0 才考虑)。\n *\n * 规则:\n * - ~/.ssh (SSH 私钥 / known_hosts)\n * - ~/.aws (AWS 凭证)\n * - ~/.gnupg (GPG 私钥)\n * - ~/.kube/config (集群 token)\n * - .env / .env.* (任何位置的环境文件)\n * - id_rsa / id_ed25519 等私钥文件名\n */\n\nimport { homedir } from \"node:os\";\nimport { basename, resolve } from \"node:path\";\n\nconst HOME = homedir();\nconst SENSITIVE_DIRS = [\n resolve(HOME, \".ssh\"),\n resolve(HOME, \".aws\"),\n resolve(HOME, \".gnupg\"),\n resolve(HOME, \".config\", \"gh\"),\n];\nconst SENSITIVE_FILES = [\n resolve(HOME, \".kube\", \"config\"),\n resolve(HOME, \".netrc\"),\n resolve(HOME, \".pypirc\"),\n];\nconst SENSITIVE_BASENAMES = new Set([\n \"id_rsa\",\n \"id_ed25519\",\n \"id_ecdsa\",\n \"id_dsa\",\n]);\nconst ENV_PATTERN = /(?:^|\\/)\\.env(\\..+)?$/;\n\nexport interface SensitiveCheck {\n blocked: boolean;\n reason?: string;\n}\n\nexport function checkSensitivePath(path: string): SensitiveCheck {\n const abs = resolve(path);\n for (const dir of SENSITIVE_DIRS) {\n if (abs === dir || abs.startsWith(dir + \"/\")) {\n return { blocked: true, reason: `sensitive directory ${dir.replace(HOME, \"~\")}` };\n }\n }\n for (const f of SENSITIVE_FILES) {\n if (abs === f) return { blocked: true, reason: `sensitive file ${f.replace(HOME, \"~\")}` };\n }\n const base = basename(abs);\n if (SENSITIVE_BASENAMES.has(base)) {\n return { blocked: true, reason: `private key filename ${base}` };\n }\n if (ENV_PATTERN.test(abs)) {\n return { blocked: true, reason: `.env file (may contain secrets)` };\n }\n return { blocked: false };\n}\n","/**\n * Write 工具:写入文件(创建或覆盖)。\n *\n * 为防误覆盖,约定调用前必须先 Read 过同一路径(除非文件不存在)。\n * 这个约束实际由 LLM 遵守 (prompt 引导);本工具不强制,但记录到日志。\n */\n\nimport { readFile, writeFile, mkdir, stat } from \"node:fs/promises\";\nimport { resolve, isAbsolute, dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { makeUnifiedDiff } from \"../_diff.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst WriteArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n content: z.string().describe(\"Full content of the file.\"),\n});\n\nexport const WriteTool = defineTool({\n name: \"Write\",\n description: \"Write a complete file to the local filesystem. Creates parent directories if needed. Overwrites existing files — prefer Edit for partial updates.\",\n parameters: WriteArgs,\n permission: \"write\",\n summarize: (args) => `Write(${args.file_path}, ${args.content.length} chars)`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let existed = false;\n let oldContent = \"\";\n try {\n const info = await stat(path);\n existed = info.isFile();\n if (existed) oldContent = await readFile(path, \"utf-8\");\n } catch {\n // 文件不存在,正常情况\n }\n\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, args.content, \"utf-8\");\n\n const diff = makeUnifiedDiff(args.file_path, oldContent, args.content);\n\n return {\n content: existed\n ? `Overwrote ${path} (${args.content.length} bytes).`\n : `Created ${path} (${args.content.length} bytes).`,\n summary: `${existed ? \"Overwrote\" : \"Created\"} ${args.file_path}`,\n diff: diff || undefined,\n };\n },\n});\n","/**\n * 文件改动 → unified diff(jsdiff),仅给 UI 渲染用,不进 LLM 上下文。\n *\n * 上下文行数 3(GNU diff 默认);新文件 / 整体覆盖时呈现为全 + 行。\n */\n\nimport { createPatch } from \"diff\";\n\nconst MAX_DIFF_LINES = 200;\n\nexport function makeUnifiedDiff(filePath: string, oldContent: string, newContent: string): string {\n if (oldContent === newContent) return \"\";\n const patch = createPatch(filePath, oldContent, newContent, \"before\", \"after\", { context: 3 });\n return truncate(patch);\n}\n\nfunction truncate(diff: string): string {\n const lines = diff.split(\"\\n\");\n if (lines.length <= MAX_DIFF_LINES) return diff;\n return lines.slice(0, MAX_DIFF_LINES).join(\"\\n\") + `\\n... [${lines.length - MAX_DIFF_LINES} more diff lines truncated]`;\n}\n","/**\n * Edit 工具:在文件中做精确字符串替换。\n *\n * 必须先 Read 过文件(由调用方/LLM 遵守,不强制校验)。\n * old_string 必须在文件中唯一出现;replace_all=true 时不要求唯一。\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve, isAbsolute } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport { ToolError } from \"../../types/index.js\";\nimport { makeUnifiedDiff } from \"../_diff.js\";\nimport { checkSensitivePath } from \"../_sensitive.js\";\n\nconst EditArgs = z.object({\n file_path: z.string().describe(\"Absolute or cwd-relative path to the file.\"),\n old_string: z.string().describe(\"Exact substring to replace. Must be unique unless replace_all=true.\"),\n new_string: z.string().describe(\"Replacement string.\"),\n replace_all: z.boolean().optional().describe(\"Replace every occurrence. Default false.\"),\n});\n\nexport const EditTool = defineTool({\n name: \"Edit\",\n description: \"Perform an exact string replacement in a file. Old string must be unique unless replace_all=true. Cheaper than Write when only a small part needs to change.\",\n parameters: EditArgs,\n permission: \"write\",\n summarize: (args) => `Edit(${args.file_path})`,\n async execute(args, ctx) {\n const path = isAbsolute(args.file_path) ? args.file_path : resolve(ctx.cwd, args.file_path);\n\n const sensitive = checkSensitivePath(path);\n if (sensitive.blocked) {\n return { content: `Refused: ${path} matches sensitive path policy (${sensitive.reason}).`, isError: true };\n }\n\n let content: string;\n try {\n content = await readFile(path, \"utf-8\");\n } catch (err) {\n throw new ToolError(`Cannot read ${path}: ${err instanceof Error ? err.message : String(err)}`, \"Edit\", err);\n }\n\n if (args.old_string === args.new_string) {\n return { content: \"old_string is identical to new_string; nothing to do.\", isError: true };\n }\n\n const occurrences = countOccurrences(content, args.old_string);\n if (occurrences === 0) {\n return {\n content: `old_string not found in ${args.file_path}. Did you read the file first? Check whitespace and indentation.`,\n isError: true,\n };\n }\n if (occurrences > 1 && !args.replace_all) {\n return {\n content: `old_string occurs ${occurrences} times in ${args.file_path}. Either expand context to make it unique, or set replace_all=true.`,\n isError: true,\n };\n }\n\n const newContent = args.replace_all\n ? content.split(args.old_string).join(args.new_string)\n : content.replace(args.old_string, args.new_string);\n\n await writeFile(path, newContent, \"utf-8\");\n\n const diff = makeUnifiedDiff(args.file_path, content, newContent);\n\n return {\n content: `Edited ${path}: replaced ${args.replace_all ? occurrences : 1} occurrence(s).`,\n summary: `Edited ${args.file_path}`,\n diff: diff || undefined,\n };\n },\n});\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (needle.length === 0) return 0;\n let count = 0;\n let pos = 0;\n while ((pos = haystack.indexOf(needle, pos)) !== -1) {\n count += 1;\n pos += needle.length;\n }\n return count;\n}\n","/**\n * Bash 工具:执行 shell 命令。\n *\n * 安全:内置 deny 列表(无法 allow 绕过)。\n * 上限:超时 + stdout 截断。\n */\n\nimport { execa } from \"execa\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst BashArgs = z.object({\n command: z.string().describe(\"Shell command to run. Will be executed via sh -c.\"),\n timeout: z.number().int().positive().optional().describe(\"Timeout in milliseconds. Default 120000 (2 min). Max 600000.\"),\n description: z.string().optional().describe(\"Brief description (3-10 words) for the UI.\"),\n});\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MAX_TIMEOUT_MS = 600_000;\nconst MAX_OUTPUT_BYTES = 100_000;\n\n/** 即使在 allow 列表里也强制阻断的危险命令模式。 */\nconst HARD_DENY_PATTERNS: RegExp[] = [\n /\\brm\\s+-rf\\s+\\/(?:\\s|$)/, // rm -rf /\n /\\brm\\s+-rf\\s+~(?:\\/|\\s|$)/, // rm -rf ~ or ~/...\n /\\brm\\s+-rf\\s+\\*/, // rm -rf *\n /\\bdd\\s+.*of=\\/dev\\//, // dd of=/dev/*\n /\\bmkfs\\b/, // mkfs\n /:\\(\\)\\s*\\{\\s*:\\|:&\\s*\\}\\s*;\\s*:/, // fork bomb\n /\\bsudo\\b/, // sudo(v0.1 简单粗暴禁掉)\n /\\bcurl\\s+[^|]*\\|\\s*(?:sh|bash|zsh)/, // curl ... | sh\n /\\bwget\\s+[^|]*\\|\\s*(?:sh|bash|zsh)/, // wget ... | sh\n];\n\nfunction checkDangerous(command: string): { dangerous: true; reason: string } | { dangerous: false } {\n for (const pattern of HARD_DENY_PATTERNS) {\n if (pattern.test(command)) {\n return { dangerous: true, reason: `matches pattern ${pattern}` };\n }\n }\n return { dangerous: false };\n}\n\nexport const BashTool = defineTool({\n name: \"Bash\",\n description: \"Execute a shell command via sh -c. Use for git, file system listings, builds, tests, etc. Avoid interactive commands (prefer non-interactive flags). For file edits use Edit/Write, not sed/echo.\",\n parameters: BashArgs,\n permission: \"execute\",\n summarize: (args) => args.description ?? `Bash: ${args.command.length > 60 ? args.command.slice(0, 60) + \"...\" : args.command}`,\n async execute(args, ctx) {\n const danger = checkDangerous(args.command);\n if (danger.dangerous) {\n return {\n content: `Refused: command blocked by hard deny list (${danger.reason}). If you really need this, ask the user to run it manually.`,\n isError: true,\n };\n }\n\n const timeout = Math.min(args.timeout ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);\n\n try {\n const result = await execa(args.command, {\n shell: \"/bin/sh\",\n cwd: ctx.cwd,\n timeout,\n reject: false,\n stripFinalNewline: false,\n maxBuffer: MAX_OUTPUT_BYTES * 2,\n cancelSignal: ctx.abortSignal,\n });\n\n const stdout = truncate(result.stdout ?? \"\", MAX_OUTPUT_BYTES, \"stdout\");\n const stderr = truncate(result.stderr ?? \"\", MAX_OUTPUT_BYTES, \"stderr\");\n\n const parts: string[] = [];\n if (stdout) parts.push(`<stdout>\\n${stdout}\\n</stdout>`);\n if (stderr) parts.push(`<stderr>\\n${stderr}\\n</stderr>`);\n if (result.timedOut) parts.push(`<timeout>Command exceeded ${timeout}ms.</timeout>`);\n if (result.failed && !result.timedOut) parts.push(`<exit_code>${result.exitCode ?? \"unknown\"}</exit_code>`);\n\n const body = parts.length > 0 ? parts.join(\"\\n\") : \"(no output)\";\n return {\n content: body,\n isError: result.failed,\n summary: result.failed ? `Bash exited ${result.exitCode ?? \"?\"}` : `Bash ok`,\n };\n } catch (err) {\n return {\n content: `Bash threw: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n});\n\nfunction truncate(text: string, max: number, label: string): string {\n if (text.length <= max) return text;\n return text.slice(0, max) + `\\n... [${label} truncated, original ${text.length} bytes]`;\n}\n","/**\n * Grep 工具:基于 ripgrep 包装(若可用),fallback 到 bash grep。\n * v0.1 简单实现:直接调 system rg / grep。\n */\n\nimport { execa } from \"execa\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst GrepArgs = z.object({\n pattern: z.string().describe(\"Regex pattern to search for.\"),\n path: z.string().optional().describe(\"File or directory to search in. Default: cwd.\"),\n glob: z.string().optional().describe('Glob filter, e.g. \"*.ts\" or \"src/**/*.tsx\".'),\n output_mode: z.enum([\"content\", \"files_with_matches\", \"count\"]).optional().describe(\"Default: files_with_matches.\"),\n context: z.number().int().min(0).max(50).optional().describe(\"Context lines around each match (use only with output_mode=content).\"),\n case_insensitive: z.boolean().optional(),\n});\n\nlet rgChecked = false;\nlet rgAvailable = false;\n\nasync function checkRipgrep(): Promise<boolean> {\n if (rgChecked) return rgAvailable;\n try {\n await execa(\"rg\", [\"--version\"], { reject: false });\n rgAvailable = true;\n } catch {\n rgAvailable = false;\n }\n rgChecked = true;\n return rgAvailable;\n}\n\nexport const GrepTool = defineTool({\n name: \"Grep\",\n description: \"Search file contents using regex. Prefer this over Bash(grep|find) — handles ignore files & is much faster on large trees.\",\n parameters: GrepArgs,\n permission: \"read\",\n summarize: (args) => `Grep(${args.pattern}${args.path ? `, ${args.path}` : \"\"})`,\n async execute(args, ctx) {\n const hasRg = await checkRipgrep();\n const mode = args.output_mode ?? \"files_with_matches\";\n\n if (hasRg) {\n const cliArgs: string[] = [];\n if (args.case_insensitive) cliArgs.push(\"-i\");\n if (mode === \"files_with_matches\") cliArgs.push(\"-l\");\n else if (mode === \"count\") cliArgs.push(\"-c\");\n else if (args.context != null) cliArgs.push(\"-C\", String(args.context));\n if (args.glob) cliArgs.push(\"--glob\", args.glob);\n cliArgs.push(\"--\", args.pattern, args.path ?? \".\");\n\n const result = await execa(\"rg\", cliArgs, { cwd: ctx.cwd, reject: false, cancelSignal: ctx.abortSignal });\n const out = (result.stdout ?? \"\").trim();\n if (result.exitCode === 0 || result.exitCode === 1) {\n return { content: out || \"(no matches)\", summary: `Grep ${args.pattern}` };\n }\n return { content: `rg failed: ${result.stderr}`, isError: true };\n }\n\n // Fallback: bash grep -r\n const cliArgs = [\"-r\", \"-n\"];\n if (args.case_insensitive) cliArgs.push(\"-i\");\n if (mode === \"files_with_matches\") cliArgs.push(\"-l\");\n else if (mode === \"count\") cliArgs.push(\"-c\");\n cliArgs.push(\"-E\", args.pattern, args.path ?? \".\");\n\n const result = await execa(\"grep\", cliArgs, { cwd: ctx.cwd, reject: false, cancelSignal: ctx.abortSignal });\n const out = (result.stdout ?? \"\").trim();\n if (result.exitCode === 0 || result.exitCode === 1) {\n return { content: out || \"(no matches)\", summary: `Grep ${args.pattern}` };\n }\n return { content: `grep failed: ${result.stderr}`, isError: true };\n },\n});\n","/**\n * Glob 工具:用 fast-glob 列出匹配文件。\n */\n\nimport fg from \"fast-glob\";\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst GlobArgs = z.object({\n pattern: z.string().describe('Glob pattern, e.g. \"src/**/*.ts\" or \"**/*.{md,json}\".'),\n path: z.string().optional().describe(\"Base directory to search from. Default: cwd.\"),\n limit: z.number().int().positive().max(1000).optional().describe(\"Max results. Default 100.\"),\n});\n\nconst DEFAULT_LIMIT = 100;\n\nexport const GlobTool = defineTool({\n name: \"Glob\",\n description: \"Find files by glob pattern. Returns relative paths sorted by modification time (newest first).\",\n parameters: GlobArgs,\n permission: \"read\",\n summarize: (args) => `Glob(${args.pattern}${args.path ? `, ${args.path}` : \"\"})`,\n async execute(args, ctx) {\n const cwd = args.path ?? ctx.cwd;\n const limit = args.limit ?? DEFAULT_LIMIT;\n\n const entries = await fg(args.pattern, {\n cwd,\n onlyFiles: true,\n stats: true,\n dot: false,\n ignore: [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \"**/.muse/**\"],\n });\n\n // 按 mtime 倒序\n entries.sort((a, b) => {\n const ta = a.stats?.mtime?.getTime() ?? 0;\n const tb = b.stats?.mtime?.getTime() ?? 0;\n return tb - ta;\n });\n\n const truncated = entries.length > limit;\n const paths = entries.slice(0, limit).map((e) => e.path);\n\n let result = paths.join(\"\\n\") || \"(no matches)\";\n if (truncated) {\n result += `\\n... [${entries.length - limit} more, increase limit to see]`;\n }\n return { content: result, summary: `Glob found ${entries.length} file(s)` };\n },\n});\n","/**\n * TodoWrite 工具:维护 session 内任务清单。\n *\n * 把完整 todos 数组替换进 ctx.todos。约定:一次只一个 in_progress;完成立即标 completed\n * 不要批;任务尽量原子。MessageView 会读 args.todos 渲染 checkbox 清单。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface TodoItem {\n content: string;\n status: TodoStatus;\n activeForm?: string;\n}\n\nconst TodoSchema = z.object({\n content: z.string().describe(\"Imperative one-line task description (e.g. 'Run the test suite').\"),\n status: z.enum([\"pending\", \"in_progress\", \"completed\"]).describe(\"Current status.\"),\n activeForm: z.string().optional().describe(\"Present-continuous form for the spinner (e.g. 'Running the test suite').\"),\n});\n\nconst TodoWriteArgs = z.object({\n todos: z.array(TodoSchema).describe(\"Full list. Replaces the current store.\"),\n listTitle: z\n .string()\n .optional()\n .describe(\n \"Short (2-6 word) imperative title describing the OVERALL goal of this todo list, e.g. \" +\n \"'Refactor auth flow' / '分析 Muse 架构' / 'Migrate to ESM'. Shown as the list header in UI. \" +\n \"Keep it stable across calls within the same task; only change it if the goal genuinely shifts.\",\n ),\n});\n\nexport const TodoWriteTool = defineTool({\n name: \"TodoWrite\",\n description:\n \"Maintain a structured task list for the current session. Pass the FULL list every call (it replaces the store). \" +\n \"Mark exactly one task in_progress at a time; mark completed immediately when done; do not batch completions. \" +\n \"Use when the task has 3+ distinct steps or is non-trivial. Skip for single trivial actions. \" +\n \"Always include `listTitle` summarizing the overall goal so the UI can label this batch meaningfully.\",\n parameters: TodoWriteArgs,\n permission: \"read\",\n summarize: (args) => `TodoWrite(${args.todos.length} items)`,\n async execute(args, ctx) {\n if (!ctx.todos) {\n return {\n content: \"TodoWrite is unavailable: this agent run has no todo store. (Internal bug; tell the user.)\",\n isError: true,\n };\n }\n ctx.todos.set(args.todos);\n const summary = args.todos\n .map((t, i) => `${i + 1}. ${t.status === \"completed\" ? \"[x]\" : t.status === \"in_progress\" ? \"[~]\" : \"[ ]\"} ${t.content}`)\n .join(\"\\n\");\n return {\n content: `Updated todos (${args.todos.length} items):\\n${summary}`,\n summary: `Todos: ${args.todos.filter((t) => t.status === \"completed\").length}/${args.todos.length} done`,\n };\n },\n});\n","/**\n * WebFetch 工具:抓 URL → 文本 / 简易 markdown。\n *\n * 安全:\n * - 拒绝本机回环 / 链接本地 / 私有网段(SSRF 防护)\n * - http → https 自动升级\n * - 30s 超时;最大 1MB 响应体\n *\n * 输出:以 HTML 解析时 strip 标签后近似 markdown;非 HTML 直接返回文本(截断)。\n *\n * 不引入 turndown:v0.1 用 minimal regex 转换,够 LLM 阅读;\n * 后续如需精细 markdown(保留 link / list 嵌套),再换专门库。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nconst WebFetchArgs = z.object({\n url: z.string().describe(\"Fully-qualified URL. http will be upgraded to https.\"),\n prompt: z\n .string()\n .optional()\n .describe(\n \"What information to look for. The host returns the page content; the LLM should then read it to answer the prompt.\",\n ),\n});\n\nconst MAX_RESPONSE_BYTES = 1_000_000;\nconst FETCH_TIMEOUT_MS = 30_000;\n\nconst PRIVATE_HOST_PATTERNS: RegExp[] = [\n /^localhost$/i,\n /^127\\./,\n /^0\\.0\\.0\\.0$/,\n /^169\\.254\\./,\n /^10\\./,\n /^192\\.168\\./,\n /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./,\n /^::1$/,\n /^fc[0-9a-f]{2}:/i,\n /^fe80:/i,\n];\n\nfunction isPrivateHost(hostname: string): boolean {\n return PRIVATE_HOST_PATTERNS.some((p) => p.test(hostname));\n}\n\nexport const WebFetchTool = defineTool({\n name: \"WebFetch\",\n description:\n \"Fetch a URL and return its textual content (HTML stripped to a markdown-ish form). \" +\n \"Use for reading documentation, blog posts, or API specs. Private/loopback hosts are blocked. \" +\n \"If the URL redirects to a different host, the redirect target is returned for you to re-fetch.\",\n parameters: WebFetchArgs,\n permission: \"network\",\n summarize: (args) => `WebFetch(${args.url})`,\n async execute(args, ctx) {\n let target: URL;\n try {\n target = new URL(args.url);\n } catch {\n return { content: `Invalid URL: ${args.url}`, isError: true };\n }\n if (target.protocol === \"http:\") {\n target.protocol = \"https:\";\n }\n if (target.protocol !== \"https:\") {\n return { content: `Refused: only http(s) URLs are allowed.`, isError: true };\n }\n if (isPrivateHost(target.hostname)) {\n return { content: `Refused: ${target.hostname} is a private/loopback host (SSRF guard).`, isError: true };\n }\n\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n ctx.abortSignal?.addEventListener(\"abort\", onAbort);\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const resp = await fetch(target.toString(), {\n redirect: \"manual\",\n signal: controller.signal,\n headers: { \"user-agent\": \"muse-cli/0.1\" },\n });\n\n // 跨主机 redirect → 提示重试,不自动跟随\n if (resp.status >= 300 && resp.status < 400) {\n const loc = resp.headers.get(\"location\");\n if (loc) {\n try {\n const redirectURL = new URL(loc, target);\n if (redirectURL.hostname !== target.hostname) {\n return {\n content: `Redirect to a different host: ${redirectURL.toString()}\\nRe-fetch the new URL explicitly if you trust it.`,\n summary: `Redirect to a different host: ${redirectURL.toString()}`,\n kind: \"warn\",\n };\n }\n // 同 host redirect 也提示一下,让 LLM 决定是否跟\n return {\n content: `Redirect (same host): ${redirectURL.toString()}\\nRe-fetch the new URL to continue.`,\n summary: `Redirect → ${redirectURL.pathname}`,\n kind: \"warn\",\n };\n } catch {\n return { content: `Redirect with unparseable location: ${loc}`, isError: true };\n }\n }\n }\n\n if (!resp.ok) {\n return { content: `HTTP ${resp.status} ${resp.statusText} for ${target.toString()}`, isError: true };\n }\n\n const contentType = resp.headers.get(\"content-type\") ?? \"\";\n const reader = resp.body?.getReader();\n if (!reader) return { content: `Empty response body.`, isError: true };\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n if (value) {\n total += value.byteLength;\n if (total > MAX_RESPONSE_BYTES) {\n await reader.cancel();\n chunks.push(value.slice(0, value.byteLength - (total - MAX_RESPONSE_BYTES)));\n break;\n }\n chunks.push(value);\n }\n }\n const body = new TextDecoder(\"utf-8\", { fatal: false }).decode(Buffer.concat(chunks.map((c) => Buffer.from(c))));\n\n let processed = body;\n if (/^text\\/html|application\\/xhtml/i.test(contentType)) {\n processed = htmlToText(body);\n }\n\n const summary = args.prompt\n ? `# WebFetch result for: ${args.prompt}`\n : `Fetched ${target.hostname} (${total} bytes${total >= MAX_RESPONSE_BYTES ? \", truncated\" : \"\"})`;\n const truncated = processed.length > 200_000 ? processed.slice(0, 200_000) + \"\\n\\n... [truncated]\" : processed;\n const preface = args.prompt ? `# WebFetch result for: ${args.prompt}\\n\\nSource: ${target.toString()}\\n\\n` : `Source: ${target.toString()}\\n\\n`;\n return { content: preface + truncated, summary };\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n return { content: `WebFetch aborted (timeout or user cancel).`, isError: true };\n }\n return { content: `WebFetch failed: ${err instanceof Error ? err.message : String(err)}`, isError: true };\n } finally {\n clearTimeout(timer);\n ctx.abortSignal?.removeEventListener(\"abort\", onAbort);\n }\n },\n});\n\n/**\n * 极简 HTML → 文本:删 script/style,保留段落 / 列表 / 标题 / 链接。\n * 不追求精确——给 LLM 看的近似版本即可。\n */\nexport function htmlToText(html: string): string {\n let s = html;\n // 删 script / style / svg / noscript\n s = s.replace(/<(script|style|svg|noscript)\\b[^>]*>[\\s\\S]*?<\\/\\1>/gi, \"\");\n // 注释\n s = s.replace(/<!--[\\s\\S]*?-->/g, \"\");\n // 标题\n s = s.replace(/<h([1-6])\\b[^>]*>([\\s\\S]*?)<\\/h\\1>/gi, (_m, lvl: string, txt: string) => {\n return `\\n\\n${\"#\".repeat(parseInt(lvl, 10))} ${stripTags(txt).trim()}\\n\\n`;\n });\n // a 链接\n s = s.replace(/<a\\b[^>]*href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi, (_m, href: string, txt: string) => {\n const label = stripTags(txt).trim();\n return label ? `[${label}](${href})` : href;\n });\n // 列表项\n s = s.replace(/<li\\b[^>]*>([\\s\\S]*?)<\\/li>/gi, (_m, txt: string) => `\\n- ${stripTags(txt).trim()}`);\n // 段落 / 块级\n s = s.replace(/<(p|div|section|article|header|footer|main|aside|nav|pre|blockquote|br|hr)\\b[^>]*>/gi, \"\\n\");\n s = s.replace(/<\\/(p|div|section|article|header|footer|main|aside|nav|pre|blockquote)>/gi, \"\\n\");\n // code 行内\n s = s.replace(/<code\\b[^>]*>([\\s\\S]*?)<\\/code>/gi, (_m, txt: string) => `\\`${stripTags(txt)}\\``);\n // 删剩余标签\n s = stripTags(s);\n // entity 简版\n s = s\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n // 合并多空行\n s = s.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n return s;\n}\n\nfunction stripTags(s: string): string {\n return s.replace(/<[^>]+>/g, \"\");\n}\n","/**\n * MemoryWrite / MemoryRead 工具:长期 memory 操作。\n *\n * 两层 scope(2026-06-07):\n * - \"project\"(默认 / 安全偏向):跟当前 cwd 强相关的事实\n * - \"user\":跨项目用户级偏好 / 工作风格\n *\n * 由 ctx.cwd 决定项目身份;切目录后 project memory 自动隔离;user memory 跨项目共享。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\nimport {\n readMemoryFile,\n writeMemory,\n type MemoryType,\n type Scope,\n SCOPES,\n} from \"../../loop/memory.js\";\n\nconst TYPES: [MemoryType, ...MemoryType[]] = [\"user\", \"feedback\", \"project\", \"reference\"];\nconst SCOPE_VALUES: [Scope, ...Scope[]] = [\"project\", \"user\"];\n\nconst MemoryWriteArgs = z.object({\n name: z\n .string()\n .regex(/^[a-z0-9][a-z0-9-_]*$/i, \"must be a kebab- or snake-style slug\")\n .describe(\"Short kebab/snake slug; used as filename (<name>.md) and index key.\"),\n description: z\n .string()\n .describe(\"One-line summary used in MEMORY.md index (decides future relevance).\"),\n type: z.enum(TYPES).describe(\"user | feedback | project | reference\"),\n body: z.string().describe(\"Memory content (markdown). For feedback/project, lead with the rule/fact then **Why:** and **How to apply:** lines.\"),\n scope: z\n .enum(SCOPE_VALUES)\n .optional()\n .describe(\n 'Storage scope. \"project\"(default — safe bias) = saved under current project, not visible to other projects. ' +\n '\"user\"(global) = saved under ~/.muse/memory/, visible across ALL projects. ' +\n \"Choose carefully:\\n\" +\n \" scope=project — project architecture / file conventions / team agreements (pnpm vs npm) / project-specific bugs+fixes / API contracts.\\n\" +\n \" When unsure, choose project (safer; user can /memory promote-scope later).\\n\" +\n \" scope=user — user role / working language / timezone / cross-project editor preferences (tabs/spaces, naming style, comment language) / \" +\n \"tool preferences that apply EVERYWHERE / recurring feedback that reveals user personality.\\n\" +\n \" HARD RULE: personal preference items (tabs/spaces, comment language, editor) MUST be scope=user — \" +\n \"do NOT save them as project memory just because cwd is in a project. \" +\n \"If you cannot tell whether a fact is personal or project-specific, ask the user or default to project.\",\n ),\n});\n\nexport const MemoryWriteTool = defineTool({\n name: \"MemoryWrite\",\n description:\n \"Save a long-term memory file under ~/.muse/[projects/<hash>/]memory/<name>.md and update MEMORY.md index. \" +\n \"Choose scope carefully (see scope arg). \" +\n \"Use for: user role/preferences (scope=user), validated approach decisions (feedback), \" +\n \"project facts (auto-convert relative dates), external system references. \" +\n \"Do NOT save: code patterns derivable from the repo, git history, fix recipes, ephemeral task state.\",\n parameters: MemoryWriteArgs,\n permission: \"write\",\n summarize: (args) => `MemoryWrite(${args.name}, ${args.scope ?? \"project\"}, type=${args.type})`,\n async execute(args, ctx) {\n // LLM 自主写入强制 trust=auto + source=manual-write — LLM 不能自封 verified/trusted\n const result = await writeMemory(ctx.cwd, {\n name: args.name,\n description: args.description,\n type: args.type as MemoryType,\n body: args.body,\n trust: \"auto\",\n source: \"manual-write\",\n scope: args.scope as Scope | undefined, // defaults to \"project\" inside writeMemory\n });\n return {\n content: `Saved memory \"${args.name}\" (${args.type}, scope=${result.scope}, trust=auto) → ${result.filePath}${result.indexUpdated ? \"\\nMEMORY.md updated.\" : \"\"}`,\n summary: `MemoryWrite ${args.name} (${result.scope})`,\n };\n },\n});\n\nconst MemoryReadArgs = z.object({\n name: z.string().describe(\"Memory slug to read (no .md extension).\"),\n scope: z\n .enum(SCOPE_VALUES)\n .optional()\n .describe('Optional scope to read from. Default: project first, fallback user. Specify when name exists in both scopes.'),\n});\n\nexport const MemoryReadTool = defineTool({\n name: \"MemoryRead\",\n description:\n \"Read a specific long-term memory file by name. Default lookup: project scope first, then user scope. \" +\n \"Use after seeing it referenced in MEMORY.md (which is auto-injected into the system prompt). \" +\n \"Pass scope='project' or 'user' to disambiguate when the same name exists in both.\",\n parameters: MemoryReadArgs,\n permission: \"read\",\n summarize: (args) => `MemoryRead(${args.name}${args.scope ? `, ${args.scope}` : \"\"})`,\n async execute(args, ctx) {\n try {\n const content = await readMemoryFile(ctx.cwd, args.name, args.scope as Scope | undefined);\n return { content, summary: `MemoryRead ${args.name}` };\n } catch (err) {\n return { content: err instanceof Error ? err.message : String(err), isError: true };\n }\n },\n});\n","/**\n * 长期 Memory:跨 session 持久化的小段知识。\n *\n * 两层 scope(2026-06-07 设计扩展):\n * - project:`~/.muse/projects/<projectHash>/memory/`(已有)\n * - user:`~/.muse/memory/`(新增 — 跨项目用户级)\n *\n * 用户级 memory 对当前项目也生效,优先级低于项目级(召回时 project ×1.2)。\n *\n * 文件结构(每个 scope 内):\n * - MEMORY.md index(每行 `[trust] - [name](name.md) — one-line hook`)\n * - <name>.md 具体记忆,带 frontmatter(含 trust + source + timestamps)\n *\n * trust 三级(模块设计/Agent 记忆系统/设计.md §4.4):\n * - trusted hierarchy 层(MUSE.md / AGENTS.md / managed)\n * - verified 用户编辑过 / 显式 promote\n * - auto LLM 通过 MemoryWrite 自动写入,未审核(可被覆盖)\n *\n * source 来源:user-edit / user-remember / compact-promote / manual-write / imported / promote-scope。\n *\n * 类型:user / feedback / project / reference。\n */\n\nimport { mkdir, readFile, writeFile, unlink, readdir } from \"node:fs/promises\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createHash } from \"node:crypto\";\n\nexport type MemoryType = \"user\" | \"feedback\" | \"project\" | \"reference\";\nexport type TrustLevel = \"trusted\" | \"verified\" | \"auto\";\nexport type Scope = \"project\" | \"user\";\nexport type MemorySource =\n | \"user-edit\"\n | \"user-remember\"\n | \"compact-promote\"\n | \"manual-write\"\n | \"imported\"\n | \"promote-scope\";\n\nexport const TRUST_LEVELS: readonly TrustLevel[] = [\"trusted\", \"verified\", \"auto\"];\nexport const SCOPES: readonly Scope[] = [\"project\", \"user\"];\n\n/**\n * trust 排序:trusted > verified > auto。\n * II-5 向量召回的加权 / II-3 list 排序 用此函数比较。\n */\nexport function trustRank(t: TrustLevel): number {\n switch (t) {\n case \"trusted\":\n return 2;\n case \"verified\":\n return 1;\n case \"auto\":\n return 0;\n }\n}\n\nexport interface MemoryFrontmatter {\n name: string;\n description: string;\n type: MemoryType;\n trust: TrustLevel;\n source: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface MemoryFile {\n frontmatter: MemoryFrontmatter;\n body: string;\n filePath: string;\n scope: Scope;\n}\n\nfunction projectHash(cwd: string): string {\n return createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n}\n\n// ============================== 路径 helpers ==============================\n\nexport function memoryDir(cwd: string): string {\n return join(homedir(), \".muse\", \"projects\", projectHash(cwd), \"memory\");\n}\n\nexport function globalMemoryDir(): string {\n return join(homedir(), \".muse\", \"memory\");\n}\n\nexport function scopeDir(cwd: string, scope: Scope): string {\n return scope === \"user\" ? globalMemoryDir() : memoryDir(cwd);\n}\n\nexport function memoryIndexPath(cwd: string, scope: Scope = \"project\"): string {\n return join(scopeDir(cwd, scope), \"MEMORY.md\");\n}\n\nexport function memoryFilePath(cwd: string, name: string, scope: Scope = \"project\"): string {\n return join(scopeDir(cwd, scope), `${name}.md`);\n}\n\n// ============================== 加载 / 读取 ==============================\n\n/** 加载 MEMORY.md 前 N 行供 system prompt 注入。\n * 默认合并两层:project 在前 + user 在后(用 `---` 分隔)。 */\nexport async function loadMemoryIndex(cwd: string, maxLines = 200): Promise<string> {\n const parts: string[] = [];\n for (const scope of SCOPES) {\n const path = memoryIndexPath(cwd, scope);\n if (!existsSync(path)) continue;\n try {\n const raw = await readFile(path, \"utf-8\");\n const trimmed = raw.trim();\n if (!trimmed) continue;\n const tag = scope === \"project\" ? \"# project memory\" : \"# user (global) memory\";\n parts.push(`${tag}\\n${trimmed}`);\n } catch {\n // skip\n }\n }\n if (parts.length === 0) return \"\";\n const full = parts.join(\"\\n\\n---\\n\\n\");\n const lines = full.split(\"\\n\");\n if (lines.length <= maxLines) return full;\n return lines.slice(0, maxLines).join(\"\\n\") + `\\n... [truncated; ${lines.length - maxLines} more lines]`;\n}\n\n/**\n * 读取单条 memory:scope 未指定时**先 project,fallback user**;name 在两层都存在\n * 时 scope 显式可消歧。\n *\n * 旧文件无 trust/source/timestamps 时**懒填**(基于 file mtime),不写回磁盘。\n */\nexport async function readMemory(cwd: string, name: string, scope?: Scope): Promise<MemoryFile> {\n const candidates: Scope[] = scope ? [scope] : [\"project\", \"user\"];\n for (const s of candidates) {\n const filePath = memoryFilePath(cwd, name, s);\n if (!existsSync(filePath)) continue;\n const raw = await readFile(filePath, \"utf-8\");\n const { frontmatter, body } = parseMemoryFile(raw, name, filePath);\n return { frontmatter, body, filePath, scope: s };\n }\n const where = scope ? `${scope} scope` : `project or user scope`;\n throw new Error(`Memory \"${name}\" does not exist in ${where}.`);\n}\n\n/** 仅返回文件原文(含 frontmatter)。MemoryRead 工具用此让 LLM 看到 trust + scope。 */\nexport async function readMemoryFile(cwd: string, name: string, scope?: Scope): Promise<string> {\n const file = await readMemory(cwd, name, scope);\n return readFile(file.filePath, \"utf-8\");\n}\n\n// ============================== 写入 ==============================\n\nexport interface WriteMemoryOpts {\n name: string;\n description: string;\n type: MemoryType;\n body: string;\n /** 默认 \"auto\"。 */\n trust?: TrustLevel;\n /** 默认 \"manual-write\"。 */\n source?: MemorySource;\n /** 默认 \"project\"。LLM 自行判断 / /remember 命令显式覆盖。 */\n scope?: Scope;\n}\n\nexport interface WriteMemoryResult {\n filePath: string;\n indexUpdated: boolean;\n /** 新建文件 = true;更新已有 = false。 */\n created: boolean;\n /** 写入的实际 scope(便于 caller 提示)。 */\n scope: Scope;\n}\n\n/**\n * 写一条 memory + 更新对应 scope 的 MEMORY.md 索引。\n *\n * 行为:\n * - 新建:落 frontmatter + body,created_at = updated_at = now\n * - 已存在(同 scope):**保留**原 created_at,刷新 updated_at;trust 走升级语义\n * (不能从 verified 自动降回 auto;trusted 永久不变)\n * - 跨 scope 同名:两层独立存储,各自独立 frontmatter\n * - 索引:替换或追加 `[trust] - [name](name.md) — description` 行\n */\nexport async function writeMemory(cwd: string, opts: WriteMemoryOpts): Promise<WriteMemoryResult> {\n const scope = opts.scope ?? \"project\";\n const dir = scopeDir(cwd, scope);\n await mkdir(dir, { recursive: true });\n\n const filePath = memoryFilePath(cwd, opts.name, scope);\n const now = new Date().toISOString();\n const reqTrust: TrustLevel = opts.trust ?? \"auto\";\n const reqSource = opts.source ?? \"manual-write\";\n\n let createdAt = now;\n let finalTrust: TrustLevel = reqTrust;\n let finalSource: string = reqSource;\n const isCreating = !existsSync(filePath);\n\n if (!isCreating) {\n try {\n const raw = await readFile(filePath, \"utf-8\");\n const existing = parseMemoryFile(raw, opts.name, filePath).frontmatter;\n createdAt = existing.created_at;\n if (trustRank(existing.trust) > trustRank(reqTrust)) {\n finalTrust = existing.trust;\n finalSource = existing.source;\n }\n } catch {\n createdAt = now;\n }\n }\n\n const fm: MemoryFrontmatter = {\n name: opts.name,\n description: opts.description.replace(/\\n/g, \" \").trim(),\n type: opts.type,\n trust: finalTrust,\n source: finalSource,\n created_at: createdAt,\n updated_at: now,\n };\n\n const content = serializeMemoryFile(fm, opts.body);\n await writeFile(filePath, content, \"utf-8\");\n\n const indexUpdated = await upsertIndexLine(cwd, scope, fm);\n return { filePath, indexUpdated, created: isCreating, scope };\n}\n\n/**\n * 改 trust 但不动 body / description(同 scope 内)。用于:\n * - /memory edit 退出后自动升 verified\n * - /memory promote(auto → verified)\n * - /memory trust <verified|auto> 显式改\n *\n * 只升不降语义:trustRank(new) >= trustRank(old);否则报错。\n * scope 未指定 → 走 readMemory 自动定位规则。\n */\nexport async function setMemoryTrust(\n cwd: string,\n name: string,\n trust: TrustLevel,\n source: MemorySource = \"user-edit\",\n scope?: Scope,\n): Promise<void> {\n const file = await readMemory(cwd, name, scope);\n if (trustRank(trust) < trustRank(file.frontmatter.trust)) {\n throw new Error(\n `Cannot lower trust: \"${name}\" is currently ${file.frontmatter.trust}; ${trust} would be a downgrade.`,\n );\n }\n if (trust === file.frontmatter.trust && source === file.frontmatter.source) {\n return; // no-op\n }\n const fm: MemoryFrontmatter = {\n ...file.frontmatter,\n trust,\n source,\n updated_at: new Date().toISOString(),\n };\n const content = serializeMemoryFile(fm, file.body);\n await writeFile(file.filePath, content, \"utf-8\");\n await upsertIndexLine(cwd, file.scope, fm);\n}\n\n/** 删除单条 memory + 从对应 scope 索引移除。scope 未指定 → 自动定位。 */\nexport async function deleteMemory(cwd: string, name: string, scope?: Scope): Promise<Scope> {\n // 先确定 actual scope\n let actualScope: Scope | undefined = scope;\n if (!actualScope) {\n for (const s of SCOPES) {\n if (existsSync(memoryFilePath(cwd, name, s))) {\n actualScope = s;\n break;\n }\n }\n }\n if (!actualScope) {\n throw new Error(`Memory \"${name}\" does not exist in any scope.`);\n }\n const filePath = memoryFilePath(cwd, name, actualScope);\n if (existsSync(filePath)) await unlink(filePath);\n await removeIndexLine(cwd, actualScope, name);\n return actualScope;\n}\n\n/**\n * 把 project scope 的 memory 提升到 user scope(II-3 promote-scope)。\n * 行为:\n * 1. 从 project 读 → 写入 user(保留 created_at;source 改 promote-scope)\n * 2. 删除 project 下的原文件 + 索引行\n * 3. 失败任一步骤抛错(原子性:写 user 失败时不删 project)\n *\n * 已在 user scope:noop 返回 false。\n */\nexport async function promoteScopeToUser(cwd: string, name: string): Promise<boolean> {\n const projectPath = memoryFilePath(cwd, name, \"project\");\n const userPath = memoryFilePath(cwd, name, \"user\");\n if (!existsSync(projectPath)) {\n if (existsSync(userPath)) return false; // 已经在 user scope\n throw new Error(`Memory \"${name}\" does not exist in project scope.`);\n }\n if (existsSync(userPath)) {\n throw new Error(`Memory \"${name}\" already exists in user scope. Delete one of them first.`);\n }\n const file = await readMemory(cwd, name, \"project\");\n await writeMemory(cwd, {\n name: file.frontmatter.name,\n description: file.frontmatter.description,\n type: file.frontmatter.type,\n body: file.body,\n trust: file.frontmatter.trust,\n source: \"promote-scope\",\n scope: \"user\",\n });\n await deleteMemory(cwd, name, \"project\");\n return true;\n}\n\n// ============================== 列表 ==============================\n\nexport interface ListMemoriesOpts {\n /** \"project\" | \"user\" | \"all\"(默认)。 */\n scope?: Scope | \"all\";\n}\n\n/** 列出 memory(按 trust → updated_at 降序;all 时合并两层)。 */\nexport async function listMemories(cwd: string, opts: ListMemoriesOpts = {}): Promise<MemoryFile[]> {\n const scope = opts.scope ?? \"all\";\n const targets: Scope[] = scope === \"all\" ? [\"project\", \"user\"] : [scope];\n const files: MemoryFile[] = [];\n for (const s of targets) {\n const dir = scopeDir(cwd, s);\n if (!existsSync(dir)) continue;\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (!entry.endsWith(\".md\")) continue;\n if (entry === \"MEMORY.md\") continue;\n const name = entry.replace(/\\.md$/, \"\");\n try {\n files.push(await readMemory(cwd, name, s));\n } catch {\n // skip 损坏文件\n }\n }\n }\n files.sort((a, b) => {\n // 优先 trust,再 updated_at,scope 仅做最后 tie-break(project 在前)\n const t = trustRank(b.frontmatter.trust) - trustRank(a.frontmatter.trust);\n if (t !== 0) return t;\n const u = b.frontmatter.updated_at.localeCompare(a.frontmatter.updated_at);\n if (u !== 0) return u;\n if (a.scope === b.scope) return 0;\n return a.scope === \"project\" ? -1 : 1;\n });\n return files;\n}\n\n// ============================== frontmatter 内部实现 ==============================\n\nconst FRONTMATTER_RE = /^---\\n([\\s\\S]*?)\\n---\\n?/;\n\n/**\n * 极简 frontmatter 解析。仅识别:\n * name / description 顶层 key: value\n * metadata: 嵌套块,缩进的 key: value\n *\n * 缺失字段懒填:trust=auto, source=manual-write, created_at = file.mtime,\n * updated_at = created_at, type = \"user\"(兜底)。\n */\nfunction parseMemoryFile(\n raw: string,\n fallbackName: string,\n filePath: string,\n): { frontmatter: MemoryFrontmatter; body: string } {\n const m = raw.match(FRONTMATTER_RE);\n if (!m) {\n return {\n frontmatter: lazyDefaults(fallbackName, \"\", filePath),\n body: raw.trim(),\n };\n }\n const fmText = m[1];\n const body = raw.slice(m[0].length).trim();\n\n const lines = fmText.split(\"\\n\");\n let name = fallbackName;\n let description = \"\";\n let type: MemoryType = \"user\";\n let trust: TrustLevel = \"auto\";\n let source = \"manual-write\";\n let createdAt = \"\";\n let updatedAt = \"\";\n let inMetadata = false;\n\n for (const line of lines) {\n if (line.match(/^metadata:\\s*$/)) {\n inMetadata = true;\n continue;\n }\n if (!inMetadata) {\n const kv = parseKV(line);\n if (!kv) continue;\n if (kv.key === \"name\") name = kv.value;\n else if (kv.key === \"description\") description = kv.value;\n } else {\n if (!line.match(/^\\s+\\S/)) {\n inMetadata = false;\n continue;\n }\n const kv = parseKV(line);\n if (!kv) continue;\n switch (kv.key) {\n case \"type\":\n if (isMemoryType(kv.value)) type = kv.value;\n break;\n case \"trust\":\n if (isTrustLevel(kv.value)) trust = kv.value;\n break;\n case \"source\":\n source = kv.value;\n break;\n case \"created_at\":\n createdAt = kv.value;\n break;\n case \"updated_at\":\n updatedAt = kv.value;\n break;\n }\n }\n }\n\n if (!createdAt || !updatedAt) {\n const mtimeIso = safeFileMtime(filePath);\n if (!createdAt) createdAt = mtimeIso;\n if (!updatedAt) updatedAt = createdAt;\n }\n\n return {\n frontmatter: { name, description, type, trust, source, created_at: createdAt, updated_at: updatedAt },\n body,\n };\n}\n\nfunction parseKV(line: string): { key: string; value: string } | null {\n const m = line.match(/^\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*:\\s*(.*?)\\s*$/);\n if (!m) return null;\n const key = m[1];\n let value = m[2];\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n return { key, value };\n}\n\nfunction isMemoryType(v: string): v is MemoryType {\n return v === \"user\" || v === \"feedback\" || v === \"project\" || v === \"reference\";\n}\n\nfunction isTrustLevel(v: string): v is TrustLevel {\n return v === \"trusted\" || v === \"verified\" || v === \"auto\";\n}\n\nfunction safeFileMtime(filePath: string): string {\n try {\n return statSync(filePath).mtime.toISOString();\n } catch {\n return new Date().toISOString();\n }\n}\n\nfunction lazyDefaults(name: string, description: string, filePath: string): MemoryFrontmatter {\n const mtimeIso = safeFileMtime(filePath);\n return {\n name,\n description,\n type: \"user\",\n trust: \"auto\",\n source: \"manual-write\",\n created_at: mtimeIso,\n updated_at: mtimeIso,\n };\n}\n\nfunction serializeMemoryFile(fm: MemoryFrontmatter, body: string): string {\n const lines = [\n \"---\",\n `name: ${fm.name}`,\n `description: ${escapeYamlValue(fm.description)}`,\n \"metadata:\",\n ` type: ${fm.type}`,\n ` trust: ${fm.trust}`,\n ` source: ${fm.source}`,\n ` created_at: ${fm.created_at}`,\n ` updated_at: ${fm.updated_at}`,\n \"---\",\n \"\",\n body.trim(),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\nfunction escapeYamlValue(v: string): string {\n if (/[:#&*?{}[\\]|>!%@`]/.test(v) || v.startsWith(\" \") || v.endsWith(\" \")) {\n return `\"${v.replace(/\"/g, '\\\\\"')}\"`;\n }\n return v;\n}\n\n// ============================== MEMORY.md 索引 ==============================\n\nconst INDEX_LINE_RE = /^\\[(trusted|verified|auto)\\]\\s+-\\s+\\[([a-zA-Z0-9-_]+)\\]\\(([^)]+)\\)\\s+—\\s+(.*)$/;\n\nfunction formatIndexLine(fm: MemoryFrontmatter): string {\n return `[${fm.trust}] - [${fm.name}](${fm.name}.md) — ${fm.description}`;\n}\n\nasync function upsertIndexLine(cwd: string, scope: Scope, fm: MemoryFrontmatter): Promise<boolean> {\n const indexPath = memoryIndexPath(cwd, scope);\n let index = existsSync(indexPath) ? await readFile(indexPath, \"utf-8\") : \"\";\n const lines = index ? index.split(\"\\n\") : [];\n const newLine = formatIndexLine(fm);\n\n const existingIdx = lines.findIndex((l) => {\n const m = l.match(INDEX_LINE_RE);\n if (m) return m[2] === fm.name;\n return l.startsWith(`- [${fm.name}](${fm.name}.md)`);\n });\n\n let changed = false;\n if (existingIdx >= 0) {\n if (lines[existingIdx] !== newLine) {\n lines[existingIdx] = newLine;\n changed = true;\n }\n } else {\n lines.push(newLine);\n changed = true;\n }\n if (changed) {\n const out = lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trimEnd() + \"\\n\";\n await mkdir(scopeDir(cwd, scope), { recursive: true });\n await writeFile(indexPath, out, \"utf-8\");\n }\n return changed;\n}\n\nasync function removeIndexLine(cwd: string, scope: Scope, name: string): Promise<void> {\n const indexPath = memoryIndexPath(cwd, scope);\n if (!existsSync(indexPath)) return;\n const raw = await readFile(indexPath, \"utf-8\");\n const lines = raw.split(\"\\n\");\n const next = lines.filter((l) => {\n const m = l.match(INDEX_LINE_RE);\n if (m) return m[2] !== name;\n return !l.startsWith(`- [${name}](${name}.md)`);\n });\n if (next.length !== lines.length) {\n const out = next.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trimEnd() + \"\\n\";\n await writeFile(indexPath, out, \"utf-8\");\n }\n}\n","/**\n * AskUserQuestion 工具:在 agent loop 内同步弹出选择题让用户作答。\n *\n * 流程:tool.execute → ctx.askQuestion(req) → App 渲染 QuestionPicker → 用户 ↑↓ 选 + Enter\n * → resolve 把结果传回 → tool 把答案拼成文本喂给 LLM。Esc 取消会返回 cancelled=true。\n *\n * 一次调用可塞多个 questions(对齐业界 Q&A picker 形态),逐题展示,任一题 Esc 视为整批取消。\n *\n * 注意:tool 本身不调任何外部资源,permission 用 read(不弹权限确认)。\n */\n\nimport { z } from \"zod\";\nimport { defineTool } from \"../types.js\";\n\nexport const AskQuestionOptionSchema = z.object({\n label: z.string().min(1).describe(\"Option text shown to the user. Concise (1-5 words).\"),\n description: z\n .string()\n .optional()\n .describe(\"Optional one-line explanation of what this option means.\"),\n preview: z\n .string()\n .optional()\n .describe(\n \"Optional rich preview rendered in a right-side panel when this option is focused. \" +\n \"Use for code/diagram/config snippets that help compare options visually. \" +\n \"Multi-line text supported.\",\n ),\n});\n\nexport const AskQuestionSchema = z.object({\n question: z.string().min(1).describe(\"Full question text (end with ?).\"),\n header: z\n .string()\n .min(1)\n .max(16)\n .describe(\"Very short label (chip), max 12 chars. E.g. 'Auth method'.\"),\n options: z\n .array(AskQuestionOptionSchema)\n .min(2)\n .max(4)\n .describe(\"2-4 options. Mutually exclusive unless multiSelect=true.\"),\n multiSelect: z\n .boolean()\n .optional()\n .describe(\"Allow multiple selections. Default false.\"),\n});\n\nexport type AskQuestion = z.infer<typeof AskQuestionSchema>;\nexport type AskQuestionOption = z.infer<typeof AskQuestionOptionSchema>;\n\nexport interface AskQuestionResponse {\n cancelled: boolean;\n /** 单选:单元素数组;多选:所选 label 列表。cancelled=true 时为空。 */\n selections: string[];\n /** 用户对该题用 'n' 添加的自由备注。空字符串表示未填。 */\n notes?: string;\n}\n\nconst AskUserQuestionArgs = z.object({\n questions: z\n .array(AskQuestionSchema)\n .min(1)\n .max(4)\n .describe(\"1-4 questions to ask the user sequentially.\"),\n});\n\nexport const AskUserQuestionTool = defineTool({\n name: \"AskUserQuestion\",\n description:\n \"Ask the user one or more multiple-choice questions when their input is needed to proceed. \" +\n \"Each question has 2-4 options. Use multiSelect=true for non-mutually-exclusive choices. \" +\n \"Prefer this over plain-text questions when the answer space is bounded. \" +\n \"If the user presses Esc, the entire batch is treated as cancelled.\",\n parameters: AskUserQuestionArgs,\n permission: \"read\",\n summarize: (args) =>\n `AskUserQuestion(${args.questions.length} question${args.questions.length === 1 ? \"\" : \"s\"})`,\n async execute(args, ctx) {\n if (!ctx.askQuestions) {\n return {\n content:\n \"AskUserQuestion is unavailable: this agent run has no question handler. \" +\n \"(Internal bug; tell the user.)\",\n isError: true,\n };\n }\n\n const responses = await ctx.askQuestions(args.questions);\n // Esc 取消时所有项 cancelled=true(UI 一次性返回整批)\n if (responses.length > 0 && responses[0].cancelled) {\n return {\n content: \"User cancelled (Esc). No answers were collected.\",\n isError: false,\n };\n }\n\n const blocks = args.questions.map((q, qi) => {\n const r = responses[qi];\n const sel = r?.selections ?? [];\n const ans = sel.length === 0 ? \"(no answer)\" : sel.join(\", \");\n const notes = r?.notes?.trim();\n return notes ? `Q: ${q.question}\\nA: ${ans}\\nNotes: ${notes}` : `Q: ${q.question}\\nA: ${ans}`;\n });\n\n return {\n content: blocks.join(\"\\n\\n\"),\n summary: `Asked ${args.questions.length} question${args.questions.length === 1 ? \"\" : \"s\"}`,\n };\n },\n});\n","import type { AnyTool } from \"../types.js\";\nimport { ReadTool } from \"./read.js\";\nimport { WriteTool } from \"./write.js\";\nimport { EditTool } from \"./edit.js\";\nimport { BashTool } from \"./bash.js\";\nimport { GrepTool } from \"./grep.js\";\nimport { GlobTool } from \"./glob.js\";\nimport { TodoWriteTool } from \"./todo.js\";\nimport { WebFetchTool } from \"./webfetch.js\";\nimport { MemoryReadTool, MemoryWriteTool } from \"./memory.js\";\nimport { AskUserQuestionTool } from \"./ask-user-question.js\";\n\nexport {\n ReadTool,\n WriteTool,\n EditTool,\n BashTool,\n GrepTool,\n GlobTool,\n TodoWriteTool,\n WebFetchTool,\n MemoryReadTool,\n MemoryWriteTool,\n AskUserQuestionTool,\n};\n\nexport const BUILTIN_TOOLS: AnyTool[] = [\n ReadTool,\n WriteTool,\n EditTool,\n BashTool,\n GrepTool,\n GlobTool,\n TodoWriteTool,\n WebFetchTool,\n MemoryReadTool,\n MemoryWriteTool,\n AskUserQuestionTool,\n];\n","/**\n * 权限模型:三态 allow / ask / deny,叠加 4 档 PermissionMode。\n *\n * 模式匹配(pattern):\n * - \"ToolName\" 精确匹配\n * - \"Bash(<prefix>)\" 匹配 Bash 工具 + 命令前缀\n * - \"Bash(<prefix>:*)\" 通配\n *\n * PermissionMode(详见文档库 permission-modes.md):\n * - default:完全走 settings.permissions 规则\n * - acceptEdits:Edit/Write 自动 allow,其他走 default\n * - plan:只允许 read 类工具,其他全 deny\n * - bypassPermissions:除显式 deny 与 Bash 硬 deny 外全 allow\n *\n * 危险操作(rm -rf / sudo 等)由 Bash 工具内部 HARD_DENY_PATTERNS 兜底,所有模式都不可绕过。\n */\n\nimport type { Permissions } from \"../config/types.js\";\nimport type { PermissionLevel } from \"../tools/types.js\";\n\nexport type Decision = \"allow\" | \"ask\" | \"deny\";\n\n/** 用户对 PermissionPrompt 三档选择。 */\nexport type PermissionDecision = \"yes\" | \"session_allow\" | \"no\";\n\nexport type PermissionMode = \"default\" | \"acceptEdits\" | \"plan\" | \"bypassPermissions\";\n\nexport const MODE_CYCLE: readonly PermissionMode[] = [\n \"default\",\n \"acceptEdits\",\n \"plan\",\n \"bypassPermissions\",\n] as const;\n\nexport const MODE_LABEL: Record<PermissionMode, string> = {\n default: \"default permissions on\",\n acceptEdits: \"accept edits on\",\n plan: \"plan mode on\",\n bypassPermissions: \"bypass permissions on\",\n};\n\nexport const MODE_COLOR: Record<PermissionMode, string> = {\n default: \"gray\",\n acceptEdits: \"#EAB308\",\n plan: \"#06B6D4\",\n bypassPermissions: \"#EF4444\",\n};\n\nexport interface PermissionInput {\n toolName: string;\n args: unknown;\n /** Tool 的权限级别;由 Agent loop 从 ToolRegistry 注入。Plan 模式用此区分 read/write。 */\n permission?: PermissionLevel;\n}\n\nexport class PermissionGate {\n private rules: Required<Permissions>;\n private mode: PermissionMode = \"default\";\n /** Session 级 allow:用户在 PermissionPrompt 选 \"yes, for session\" 后填充。 */\n private sessionAllow = new Set<string>();\n\n constructor(rules: Permissions = {}) {\n this.rules = {\n allow: rules.allow ?? [],\n ask: rules.ask ?? [],\n deny: rules.deny ?? [],\n defaultMode: rules.defaultMode ?? \"ask\",\n };\n }\n\n setMode(mode: PermissionMode): void {\n this.mode = mode;\n }\n\n getMode(): PermissionMode {\n return this.mode;\n }\n\n cycleMode(): PermissionMode {\n const i = MODE_CYCLE.indexOf(this.mode);\n this.mode = MODE_CYCLE[(i + 1) % MODE_CYCLE.length];\n return this.mode;\n }\n\n /** 用户在 PermissionPrompt 选 \"yes, allow for session\" 时记下。 */\n allowForSession(toolName: string): void {\n this.sessionAllow.add(toolName);\n }\n\n isSessionAllowed(toolName: string): boolean {\n return this.sessionAllow.has(toolName);\n }\n\n decide(input: PermissionInput): Decision {\n // 用户显式 deny 永远生效,所有模式不可绕过\n if (this.matches(this.rules.deny, input)) return \"deny\";\n // session 级 allow 在 deny 之后、mode 分支之前生效\n if (this.sessionAllow.has(input.toolName)) return \"allow\";\n\n switch (this.mode) {\n case \"bypassPermissions\":\n return \"allow\";\n\n case \"plan\":\n // 只允许只读工具;写/执行/网络类直接 deny\n return input.permission === \"read\" ? \"allow\" : \"deny\";\n\n case \"acceptEdits\":\n if (input.toolName === \"Edit\" || input.toolName === \"Write\") return \"allow\";\n return this.defaultDecide(input);\n\n case \"default\":\n default:\n return this.defaultDecide(input);\n }\n }\n\n private defaultDecide(input: PermissionInput): Decision {\n if (this.matches(this.rules.allow, input)) return \"allow\";\n if (this.matches(this.rules.ask, input)) return \"ask\";\n switch (this.rules.defaultMode) {\n case \"strict\":\n return \"ask\";\n case \"relaxed\":\n return \"allow\";\n case \"ask\":\n default:\n return \"ask\";\n }\n }\n\n private matches(patterns: string[], input: PermissionInput): boolean {\n for (const pattern of patterns) {\n if (this.matchOne(pattern, input)) return true;\n }\n return false;\n }\n\n private matchOne(pattern: string, input: PermissionInput): boolean {\n // \"ToolName\" 精确匹配\n if (!pattern.includes(\"(\")) {\n return pattern === input.toolName;\n }\n // \"Bash(<prefix>:*)\" 形式\n const m = pattern.match(/^([A-Za-z_][A-Za-z0-9_]*)\\(([^)]*)\\)$/);\n if (!m) return false;\n const [, toolName, sub] = m;\n if (toolName !== input.toolName) return false;\n if (input.toolName === \"Bash\" && typeof input.args === \"object\" && input.args !== null) {\n const cmd = (input.args as { command?: string }).command ?? \"\";\n if (sub.endsWith(\":*\")) {\n const prefix = sub.slice(0, -2);\n return cmd.startsWith(prefix);\n }\n return cmd === sub || cmd.startsWith(sub + \" \");\n }\n return false;\n }\n}\n","/**\n * Session 持久化:append-only JSONL。\n * 路径:~/.muse/projects/<project-hash>/sessions/<uuid>.jsonl\n *\n * 每行一个事件:消息 / 工具调用 / 工具结果 / 使用统计 / ...\n */\n\nimport { appendFile, mkdir, readdir, readFile, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport type { Message, TokenUsage } from \"../types/index.js\";\nimport { log } from \"../log/index.js\";\n\nexport type SessionEvent =\n | { type: \"session_start\"; time: string; cwd: string; provider: string; model: string }\n | { type: \"message\"; time: string; message: Message }\n | { type: \"usage\"; time: string; usage: TokenUsage; provider: string; model: string }\n | { type: \"session_end\"; time: string; reason: \"user_exit\" | \"error\" };\n\nexport interface SessionMeta {\n id: string;\n cwd: string;\n createdAt: string;\n path: string;\n}\n\nexport interface SessionSummary extends SessionMeta {\n /** 首个 user 消息前 60 字符。 */\n preview?: string;\n messageCount: number;\n}\n\nfunction projectHash(cwd: string): string {\n return createHash(\"sha256\").update(cwd).digest(\"hex\").slice(0, 16);\n}\n\nfunction sessionsDir(cwd: string): string {\n return join(homedir(), \".muse\", \"projects\", projectHash(cwd), \"sessions\");\n}\n\nexport class Session {\n readonly meta: SessionMeta;\n private writeQueue: Promise<void> = Promise.resolve();\n\n private constructor(meta: SessionMeta) {\n this.meta = meta;\n }\n\n static async create(cwd: string): Promise<Session> {\n const id = randomUUID();\n const dir = sessionsDir(cwd);\n await mkdir(dir, { recursive: true });\n const path = join(dir, `${id}.jsonl`);\n const meta: SessionMeta = {\n id,\n cwd,\n createdAt: new Date().toISOString(),\n path,\n };\n log.debug(\"session created\", { id, path });\n return new Session(meta);\n }\n\n static async findLatest(cwd: string): Promise<SessionMeta | undefined> {\n const list = await Session.listAll(cwd, 1);\n return list[0];\n }\n\n static async resolve(cwd: string, idOrPrefix: string): Promise<SessionMeta | undefined> {\n const dir = sessionsDir(cwd);\n if (!existsSync(dir)) return undefined;\n const entries = await readdir(dir);\n const matches = entries.filter((e) => e.endsWith(\".jsonl\") && e.startsWith(idOrPrefix));\n if (matches.length === 0) return undefined;\n if (matches.length > 1) {\n throw new Error(`Ambiguous session id \"${idOrPrefix}\" matches ${matches.length} sessions; use more characters.`);\n }\n const top = matches[0];\n const st = await stat(join(dir, top));\n return {\n id: top.replace(/\\.jsonl$/, \"\"),\n cwd,\n createdAt: st.mtime.toISOString(),\n path: join(dir, top),\n };\n }\n\n /**\n * 按修改时间倒序列出当前 cwd 下的 session,附带 preview 与消息数。\n * 读 preview 需要打开每个文件;调用方通过 limit 控制 IO 量。\n */\n static async listAll(cwd: string, limit?: number): Promise<SessionSummary[]> {\n const dir = sessionsDir(cwd);\n if (!existsSync(dir)) return [];\n const entries = await readdir(dir);\n const files = entries.filter((e) => e.endsWith(\".jsonl\"));\n if (files.length === 0) return [];\n\n const stats = await Promise.all(\n files.map(async (f) => {\n const path = join(dir, f);\n const st = await stat(path);\n return { file: f, path, mtime: st.mtime };\n }),\n );\n stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n const truncated = typeof limit === \"number\" ? stats.slice(0, limit) : stats;\n\n const summaries: SessionSummary[] = [];\n for (const s of truncated) {\n const meta: SessionMeta = {\n id: s.file.replace(/\\.jsonl$/, \"\"),\n cwd,\n createdAt: s.mtime.toISOString(),\n path: s.path,\n };\n const summary = await readSummary(meta);\n summaries.push(summary);\n }\n return summaries;\n }\n\n static async open(meta: SessionMeta): Promise<{ session: Session; events: SessionEvent[] }> {\n const session = new Session(meta);\n const events = await session.readAll();\n return { session, events };\n }\n\n /** 从已加载的 events 重建 messages 数组(按时序)。 */\n static messagesFromEvents(events: SessionEvent[]): Message[] {\n const out: Message[] = [];\n for (const ev of events) {\n if (ev.type === \"message\") out.push(ev.message);\n }\n return out;\n }\n\n async append(event: SessionEvent): Promise<void> {\n const line = JSON.stringify(event) + \"\\n\";\n // 串行写入避免交错\n this.writeQueue = this.writeQueue.then(async () => {\n try {\n await mkdir(dirname(this.meta.path), { recursive: true });\n await appendFile(this.meta.path, line, \"utf-8\");\n } catch (err) {\n log.warn(`session append failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n });\n return this.writeQueue;\n }\n\n async readAll(): Promise<SessionEvent[]> {\n if (!existsSync(this.meta.path)) return [];\n const raw = await readFile(this.meta.path, \"utf-8\");\n const events: SessionEvent[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as SessionEvent);\n } catch {\n // skip corrupt lines\n }\n }\n return events;\n }\n}\n\nasync function readSummary(meta: SessionMeta): Promise<SessionSummary> {\n let events: SessionEvent[] = [];\n try {\n const raw = await readFile(meta.path, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n events.push(JSON.parse(line) as SessionEvent);\n } catch {\n // skip\n }\n }\n } catch {\n // unreadable; return minimal summary\n }\n const messages = events.filter((e): e is Extract<SessionEvent, { type: \"message\" }> => e.type === \"message\");\n const firstUser = messages.find((e) => e.message.role === \"user\");\n let preview: string | undefined;\n if (firstUser) {\n const c = firstUser.message.content;\n const text = typeof c === \"string\"\n ? c\n : c.map((p) => {\n if (p.type === \"text\") return p.text;\n if (p.type === \"file\") return `📎`;\n if (p.type === \"image\") return `🖼`;\n return \"\";\n }).join(\" \").trim();\n preview = text.slice(0, 60).replace(/\\s+/g, \" \");\n }\n return { ...meta, preview, messageCount: messages.length };\n}\n","/**\n * Session 内 Todo 清单。\n *\n * 仅存活于单次 muse 进程内,不入 JSONL 持久化(任务清单是 ephemeral 调度状态,\n * 不是对话内容;下次进程恢复 session 时 LLM 应基于历史重建清单)。\n *\n * 工具 TodoWrite 通过 ToolContext.todos 写入;buildSystemPrompt 读出注入下一轮 LLM 的视野。\n */\n\nexport type TodoStatus = \"pending\" | \"in_progress\" | \"completed\";\n\nexport interface Todo {\n content: string;\n status: TodoStatus;\n /** 进行中状态的现在分词式描述,UI 可用作 spinner 文案。 */\n activeForm?: string;\n}\n\nexport class TodoStore {\n private items: Todo[] = [];\n\n list(): Todo[] {\n return this.items.slice();\n }\n\n set(items: Todo[]): void {\n this.items = items.slice();\n }\n\n clear(): void {\n this.items = [];\n }\n\n /** 把当前清单格式化为 system prompt 段落;无任务时返回空串。 */\n toPromptSection(): string {\n if (this.items.length === 0) return \"\";\n const lines = this.items.map((t, i) => {\n const marker = t.status === \"completed\" ? \"[x]\" : t.status === \"in_progress\" ? \"[~]\" : \"[ ]\";\n return ` ${i + 1}. ${marker} ${t.content}`;\n });\n return `# Current todos\\n${lines.join(\"\\n\")}\\n\\nUpdate via TodoWrite as you make progress. Keep exactly one item in_progress at a time.`;\n }\n}\n","/**\n * 4 段预处理管线共享类型。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §3.3。\n */\n\n/** stage 执行结果(用于日志/metrics)。 */\nexport type StageStatus = \"ok\" | \"skip\" | \"error\" | \"timeout\";\n\nexport interface StageReport {\n pipeline: string;\n stage: string;\n durationMs: number;\n status: StageStatus;\n error?: string;\n}\n\nexport interface PreprocessLogger {\n stage(report: StageReport): void;\n warn(stage: string, msg: string, meta?: Record<string, unknown>): void;\n}\n\n/** noop logger:测试与默认接入时不传 logger 也能跑。 */\nexport const NOOP_LOGGER: PreprocessLogger = {\n stage() {},\n warn() {},\n};\n\nexport interface PreprocessTelemetry {\n /** stage 累计耗时(毫秒)。 */\n stageDurations: Map<string, number>;\n /** stage 执行次数。 */\n stageInvocations: Map<string, number>;\n}\n\nexport function createTelemetry(): PreprocessTelemetry {\n return {\n stageDurations: new Map(),\n stageInvocations: new Map(),\n };\n}\n","/**\n * 统一 Pipeline 抽象。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §2.1。\n *\n * 4 段管线(Input/Request/Result/Render)共享同一套框架。\n * stage 顺序执行 + 可变 ctx;单 stage 失败可配 throw / skip 容忍。\n */\n\nimport { NOOP_LOGGER, type PreprocessLogger, type StageStatus, type StageReport } from \"./types.js\";\n\n/** Pipeline 短路信号:抛出后 pipeline 立即停止,剩余 stage 跳过。 */\nexport class PipelineShortCircuit extends Error {\n constructor(public readonly reason: string) {\n super(`pipeline short-circuit: ${reason}`);\n this.name = \"PipelineShortCircuit\";\n }\n}\n\n/** Hook 阻断信号:用户配置的 hook 命令返回 block 时,pipeline 应转换为此错误向上抛。 */\nexport class PipelineBlockedError extends Error {\n constructor(public readonly point: string, public readonly reason: string) {\n super(`blocked at ${point}: ${reason}`);\n this.name = \"PipelineBlockedError\";\n }\n}\n\nexport interface PipelineStage<Ctx> {\n /** stage 名,唯一,kebab-case;用于日志、disable 列表。 */\n readonly name: string;\n /** 入参与出参共享同一个可变 ctx;返回 Promise<void> 表示就地修改。 */\n run(ctx: Ctx): Promise<void> | void;\n /** 可选:跳过条件;返回 true 时本 stage 不执行。 */\n skip?(ctx: Ctx): boolean;\n}\n\nexport interface PipelineRunOptions {\n /** 全局执行超时(毫秒);超时后剩余 stage 跳过并标 timeout。 */\n timeoutMs?: number;\n /** 单 stage 出错策略:\"throw\"(默认)| \"skip\"(记日志后跳过)。 */\n onStageError?: \"throw\" | \"skip\";\n /** 已禁用的 stage name 列表;来自 settings.preprocess.disable。 */\n disable?: ReadonlyArray<string>;\n /** 结构化日志器。 */\n logger?: PreprocessLogger;\n /** Pipeline 名,用于日志归类(如 \"input\" / \"request\")。 */\n pipelineName?: string;\n}\n\nexport class Pipeline<Ctx> {\n constructor(\n private readonly stages: ReadonlyArray<PipelineStage<Ctx>>,\n private readonly opts: PipelineRunOptions = {},\n ) {}\n\n /** 按声明顺序执行 stages,逐个写日志。 */\n async run(ctx: Ctx): Promise<void> {\n const logger = this.opts.logger ?? NOOP_LOGGER;\n const pipelineName = this.opts.pipelineName ?? \"pipeline\";\n const disable = new Set(this.opts.disable ?? []);\n const onStageError = this.opts.onStageError ?? \"throw\";\n const startWall = Date.now();\n const timeoutMs = this.opts.timeoutMs;\n\n for (const stage of this.stages) {\n if (timeoutMs != null && Date.now() - startWall >= timeoutMs) {\n report(logger, pipelineName, stage.name, 0, \"timeout\");\n continue;\n }\n if (disable.has(stage.name)) {\n report(logger, pipelineName, stage.name, 0, \"skip\");\n continue;\n }\n if (stage.skip?.(ctx)) {\n report(logger, pipelineName, stage.name, 0, \"skip\");\n continue;\n }\n\n const t0 = Date.now();\n try {\n await stage.run(ctx);\n report(logger, pipelineName, stage.name, Date.now() - t0, \"ok\");\n } catch (err) {\n if (err instanceof PipelineShortCircuit) {\n report(logger, pipelineName, stage.name, Date.now() - t0, \"ok\");\n return;\n }\n if (err instanceof PipelineBlockedError) {\n report(logger, pipelineName, stage.name, Date.now() - t0, \"error\", err.message);\n throw err;\n }\n const msg = err instanceof Error ? err.message : String(err);\n report(logger, pipelineName, stage.name, Date.now() - t0, \"error\", msg);\n if (onStageError === \"throw\") throw err;\n }\n }\n }\n}\n\nfunction report(\n logger: PreprocessLogger,\n pipeline: string,\n stage: string,\n durationMs: number,\n status: StageStatus,\n error?: string,\n): void {\n const r: StageReport = { pipeline, stage, durationMs, status, ...(error ? { error } : {}) };\n logger.stage(r);\n}\n","/**\n * System prompt 构造。\n *\n * 简短、命令式:把可用工具与运行时约束直接摆出来给 LLM。\n * 中文输出由 ui.lang 控制;英文为默认。\n */\n\nimport { homedir } from \"node:os\";\n\nexport interface SystemPromptOpts {\n cwd: string;\n model: string;\n provider: string;\n lang?: \"en\" | \"zh-CN\";\n toolNames: string[];\n /** MEMORY.md index 内容(loadMemoryIndex 加载后传入);空串视为无 memory。 */\n memoryIndex?: string;\n}\n\nexport function buildSystemPrompt(opts: SystemPromptOpts): string {\n const { cwd, model, provider, lang, toolNames, memoryIndex } = opts;\n const home = homedir();\n const displayCwd = cwd.startsWith(home) ? cwd.replace(home, \"~\") : cwd;\n\n const sections: string[] = [];\n\n sections.push(`You are Muse, a CLI coding assistant. You are running on the user's local machine via a terminal interface.`);\n\n sections.push(\n `# Environment\\n` +\n `- Working directory: ${displayCwd}\\n` +\n `- LLM backend: ${provider} (${model})\\n` +\n `- Date: ${new Date().toISOString().slice(0, 10)}`,\n );\n\n sections.push(\n `# Available tools\\n` +\n toolNames.map((n) => `- ${n}`).join(\"\\n\") +\n `\\n\\nPrefer the dedicated tool over Bash when one fits (Read for file reading, Edit for partial updates, Write for new files / full rewrites, Grep for content search, Glob for file lookup).`,\n );\n\n sections.push(\n `# Behavior\\n` +\n `- Be concise. State results, not your thinking. Don't narrate every step.\\n` +\n `- Before editing a file you have not seen, Read it first.\\n` +\n `- For Write/Edit/Bash the user may need to approve — proceed normally; the host will gate dangerous calls.\\n` +\n `- If a command may be destructive (rm -rf, force push, drop table, etc.), warn first and let the user run it manually.\\n` +\n `- When the user asks a question that does not need tools, just answer.`,\n );\n\n if (toolNames.includes(\"TodoWrite\")) {\n sections.push(\n `# Task management\\n` +\n `- For non-trivial, multi-step work, use TodoWrite to plan and track progress.\\n` +\n `- Keep exactly one task in_progress; mark a task completed immediately when done.\\n` +\n `- Skip it for trivial single-step requests.`,\n );\n }\n\n if (lang === \"zh-CN\") {\n sections.push(`# Output language\\nReply in Chinese (简体中文) unless the user writes in English.`);\n }\n\n if (memoryIndex && memoryIndex.trim()) {\n sections.push(\n `# Memory (long-term)\\n` +\n `Below is MEMORY.md — your index of persistent facts about the user, project, and prior feedback. ` +\n `Each line points at a file you can MemoryRead. Use MemoryWrite to record new durable knowledge ` +\n `(user role/preferences, validated decisions, project facts, external references). Do NOT save things ` +\n `derivable from the repo or git history.\\n\\n` +\n memoryIndex,\n );\n }\n\n return sections.join(\"\\n\\n\");\n}\n","/**\n * 项目级配置文件 hierarchy 加载(MUSE.md + AGENTS.md)。\n *\n * 设计文档:模块设计/Agent 记忆系统/设计.md §4.1。\n *\n * 5 层(低到高优先级):\n * 1. managed /etc/muse/MUSE.md 企业 IT 部署(本期占位,只读不写)\n * 2. user ~/.muse/MUSE.md 跨项目偏好\n * 3. project <root>/MUSE.md 或 AGENTS.md 团队共享(入 git);两者并存时 overlay(MUSE.md 优先)\n * 4. local <root>/.muse/MUSE.local.md 个人本地(不入 git)\n * 5. subdir <root>/<subdir>/MUSE.md 子目录上下文(惰性加载,下一阶段实装)\n *\n * 注入点:RequestPipeline.build-system-prompt 把前 4 层拼到 systemPrompt 头部。\n * 子目录(第 5 层)在 Agent loop 检测到文件路径触及未加载子目录时主动注入到 tool result prefix。\n *\n * projectRoot 识别:从 cwd 向上找 `.git` 或 `.muse`;找不到则用 cwd 本身。\n * 与 config loader(只用 cwd)略有差异,因为 hierarchy 文件通常落项目根,\n * 子目录跑 muse 也应能找到。\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\nexport type HierarchyLevel = \"managed\" | \"user\" | \"project\" | \"local\" | \"subdir\";\nexport type HierarchySource = \"MUSE.md\" | \"AGENTS.md\";\n\nexport interface HierarchyLayer {\n level: HierarchyLevel;\n path: string;\n content: string;\n source: HierarchySource;\n /** hierarchy 来源永远 trusted(对齐设计 §4.4)。 */\n trust: \"trusted\";\n}\n\nexport interface LoadHierarchyOpts {\n /** 启用 managed 层(读 /etc/muse/MUSE.md)。默认 false(本期占位)。 */\n enableManaged?: boolean;\n /** Managed 层路径覆盖(便于测试 / 自定义部署)。默认 /etc/muse/MUSE.md。 */\n managedPath?: string;\n /** 忽略 AGENTS.md(只读 MUSE.md)。默认 false。 */\n ignoreAgentsMd?: boolean;\n}\n\nconst DEFAULT_MANAGED_PATH = \"/etc/muse/MUSE.md\";\n\n/**\n * 从 cwd 向上找到第一个含 `.git` 或 `.muse` 的目录作为 project root。找不到则用 cwd。\n *\n * 用于 hierarchy 查找的项目层根目录,与 memory/projects/<hash>/ 的 cwd 隔离逻辑无关\n * (后者保留按 cwd 隔离,避免动既有 session/memory 数据)。\n */\nexport function findProjectRoot(cwd: string): string {\n let cur = resolve(cwd);\n while (true) {\n if (existsSync(join(cur, \".git\")) || existsSync(join(cur, \".muse\"))) {\n return cur;\n }\n const parent = dirname(cur);\n if (parent === cur) return resolve(cwd); // 到根没找到 — 回退 cwd\n cur = parent;\n }\n}\n\n/**\n * 加载前 4 层 hierarchy。子目录(第 5 层)由独立函数 loadSubdirMemory 在 Agent loop 触发。\n *\n * 行为:\n * - 每一层文件不存在 → skip(无副作用)\n * - project 层 MUSE.md + AGENTS.md 并存 → 两条 layer(MUSE.md 在前)\n * - 读取失败 → skip 该 layer,不抛错\n */\nexport async function loadHierarchy(cwd: string, opts: LoadHierarchyOpts = {}): Promise<HierarchyLayer[]> {\n const layers: HierarchyLayer[] = [];\n const ignoreAgents = opts.ignoreAgentsMd === true;\n\n // 1. managed(占位 — 默认 false)\n if (opts.enableManaged === true) {\n const path = opts.managedPath ?? DEFAULT_MANAGED_PATH;\n const layer = await tryLoadLayer(\"managed\", path, \"MUSE.md\");\n if (layer) layers.push(layer);\n }\n\n // 2. user\n const userPath = join(homedir(), \".muse\", \"MUSE.md\");\n const userLayer = await tryLoadLayer(\"user\", userPath, \"MUSE.md\");\n if (userLayer) layers.push(userLayer);\n\n // 3. project — MUSE.md 优先,AGENTS.md 备份;两者并存时各推一条\n const root = findProjectRoot(cwd);\n const projectMuse = await tryLoadLayer(\"project\", join(root, \"MUSE.md\"), \"MUSE.md\");\n if (projectMuse) layers.push(projectMuse);\n if (!ignoreAgents) {\n const projectAgents = await tryLoadLayer(\"project\", join(root, \"AGENTS.md\"), \"AGENTS.md\");\n if (projectAgents) layers.push(projectAgents);\n }\n\n // 4. local\n const localPath = join(root, \".muse\", \"MUSE.local.md\");\n const localLayer = await tryLoadLayer(\"local\", localPath, \"MUSE.md\");\n if (localLayer) layers.push(localLayer);\n\n return layers;\n}\n\nasync function tryLoadLayer(\n level: HierarchyLevel,\n path: string,\n source: HierarchySource,\n): Promise<HierarchyLayer | null> {\n if (!existsSync(path)) return null;\n try {\n const content = (await readFile(path, \"utf-8\")).trim();\n if (!content) return null;\n return { level, path, content, source, trust: \"trusted\" };\n } catch {\n return null;\n }\n}\n\n/**\n * 把多个 layer 拼成 system prompt 的 hierarchy 段。各层之间用 `---` 分隔,标注来源。\n *\n * 输出格式:\n * # Project guidance (hierarchy)\n *\n * [user: ~/.muse/MUSE.md]\n * ...\n *\n * ---\n *\n * [project: ./MUSE.md]\n * ...\n */\nexport function formatHierarchyForPrompt(layers: HierarchyLayer[]): string {\n if (layers.length === 0) return \"\";\n const sections = layers.map((l) => `[${l.level}: ${prettyPath(l.path)}]\\n${l.content}`);\n return `# Project guidance (hierarchy)\\n\\n${sections.join(\"\\n\\n---\\n\\n\")}`;\n}\n\n/**\n * 子目录惰性加载入口。给 Agent loop 用:每跑完一个工具,检测工具操作的路径是否进入了\n * 未加载过的子目录;若该子目录含 MUSE.md / AGENTS.md → 返回内容附加到 tool result prefix。\n *\n * 单次调用只读一个子目录;去重逻辑由调用方维护(用绝对路径 Set)。\n */\nexport async function loadSubdirMemory(\n absSubdir: string,\n opts: { ignoreAgentsMd?: boolean; sizeCapBytes?: number } = {},\n): Promise<{ content: string; source: HierarchySource; truncated: boolean } | null> {\n const sizeCap = opts.sizeCapBytes ?? 5120;\n // MUSE.md 优先,AGENTS.md 备份\n const candidates: { path: string; source: HierarchySource }[] = [\n { path: join(absSubdir, \"MUSE.md\"), source: \"MUSE.md\" },\n ];\n if (opts.ignoreAgentsMd !== true) {\n candidates.push({ path: join(absSubdir, \"AGENTS.md\"), source: \"AGENTS.md\" });\n }\n for (const { path, source } of candidates) {\n if (!existsSync(path)) continue;\n try {\n let raw = (await readFile(path, \"utf-8\")).trim();\n if (!raw) continue;\n const truncated = raw.length > sizeCap;\n if (truncated) {\n raw = raw.slice(0, sizeCap) + `\\n\\n[... truncated (over ${sizeCap}B; use Read tool to view full file)]`;\n }\n return { content: raw, source, truncated };\n } catch {\n // 单文件失败 → 试下一个 candidate\n }\n }\n return null;\n}\n\nfunction prettyPath(p: string): string {\n const home = homedir();\n if (p.startsWith(home)) return \"~\" + p.slice(home.length);\n return p;\n}\n\n/** 加载日志辅助:供 --debug 输出 hierarchy 加载情况。 */\nexport function describeLayers(layers: HierarchyLayer[]): string {\n if (layers.length === 0) return \"(no hierarchy files found)\";\n return layers\n .map((l) => {\n let size = 0;\n try {\n size = statSync(l.path).size;\n } catch {}\n return `[${l.level}] ${prettyPath(l.path)} (${size}B, ${l.source})`;\n })\n .join(\"\\n\");\n}\n","/**\n * Memory 向量索引(II-5)。\n *\n * 设计文档:模块设计/Agent 记忆系统/设计.md §4.5。\n *\n * 持久化:每个 scope 一份 .index.json(自家 JSON;ADR D8-rev 拍板,不用 LanceDB):\n * - `~/.muse/projects/<hash>/memory/.index.json`(项目层)\n * - `~/.muse/memory/.index.json`(全局层)\n *\n * 数据结构(每份):\n * PersistentIndex = { providerId, dim, entries: { [name]: { mtime, vector, ... } } }\n *\n * 启动 / 增量行为(每个 scope 独立):\n * 1. 读 .index.json,如果 providerId 一致 → entries 复用\n * 2. 列 memory/*.md,逐条对照 mtime;一致复用 vector,不一致重 embed\n * 3. .index.json 中 name 不在当前 memory 目录 → 删除该 entry\n * 4. providerId 切换 → 全量重 embed,文件覆盖\n *\n * 召回(R1 + R3):\n * - **embed 输入只用 `name + description`**(短而精,语义聚焦;body 留作召回后注入素材)\n * - query → embed → 余弦相似度 × 双重加权(trustW × scopeW)\n * - trustW:trusted ×1.5 / verified ×1.2 / auto ×1.0\n * - scopeW:project ×1.2 / user ×1.0\n *\n * 冷启动保护:memoryCount < minMemoryCount(默认 3,2026-06-07 修订;原 10 过激)\n * → 退化到全注入。\n */\n\nimport { readFile, writeFile, mkdir, unlink } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n listMemories,\n readMemory,\n memoryDir,\n globalMemoryDir,\n scopeDir,\n type MemoryFile,\n type MemoryType,\n type TrustLevel,\n type Scope,\n SCOPES,\n trustRank,\n} from \"./memory.js\";\nimport {\n createEmbeddingProvider,\n createAndProbeProvider,\n cosineSimilarity,\n type EmbeddingProvider,\n type EmbeddingConfig,\n type ExtendedEmbeddingConfig,\n} from \"./embedding/index.js\";\n\nexport interface MemoryIndexEntry {\n name: string;\n type: MemoryType;\n trust: TrustLevel;\n scope: Scope;\n description: string;\n /** 用于注入 prompt 的\"行格式\"片段:`[trust] - [name](name.md) — description`。 */\n rawIndexLine: string;\n /** 完整 frontmatter + body(给召回结果详情展示用)。 */\n bodySnippet: string;\n /** 完整 body(注入分级用:trusted 完整 / verified 摘要 / auto 不用)。 */\n fullBody: string;\n vector: number[];\n}\n\nexport interface MemoryIndex {\n provider: EmbeddingProvider;\n entries: MemoryIndexEntry[];\n /** 索引构建时刻 ISO。 */\n builtAt: string;\n /** cwd(用于增量 upsert / remove 操作时找文件)。 */\n cwd: string;\n}\n\n/** 落盘格式(.index.json):name → 持久化条目 + provider 元数据 + dim。 */\ninterface PersistentIndex {\n providerId: string;\n dim: number;\n schemaVersion: 1;\n entries: { [name: string]: PersistentEntry };\n}\n\ninterface PersistentEntry {\n mtime: string;\n type: MemoryType;\n trust: TrustLevel;\n description: string;\n bodySnippet: string;\n fullBody: string;\n vector: number[];\n}\n\nexport interface BuildIndexOpts {\n config?: ExtendedEmbeddingConfig;\n /** 自定义 provider(测试用);提供时覆盖 config。 */\n provider?: EmbeddingProvider;\n /** 是否禁用磁盘持久化(测试 / 临时场景)。默认 false。 */\n noPersist?: boolean;\n /** 是否跳过 probe 校验(测试 / hash-bag 场景默认跳过)。默认 false(自动按 provider id 判断)。 */\n skipProbe?: boolean;\n}\n\nfunction indexPath(cwd: string, scope: Scope): string {\n return join(scopeDir(cwd, scope), \".index.json\");\n}\n\nasync function readPersistent(cwd: string, scope: Scope): Promise<PersistentIndex | null> {\n const path = indexPath(cwd, scope);\n if (!existsSync(path)) return null;\n try {\n const raw = await readFile(path, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) return null;\n if (parsed.schemaVersion !== 1) return null;\n return parsed as PersistentIndex;\n } catch {\n return null;\n }\n}\n\nasync function writePersistent(cwd: string, scope: Scope, persistent: PersistentIndex): Promise<void> {\n const dir = scopeDir(cwd, scope);\n await mkdir(dir, { recursive: true });\n await writeFile(indexPath(cwd, scope), JSON.stringify(persistent), \"utf-8\");\n}\n\nfunction snippet(body: string): string {\n return body.length > 400 ? body.slice(0, 400) + \"\\n... [truncated]\" : body;\n}\n\n/** R1:embed 输入只用 `name + description`(短而精,语义聚焦)。 */\nfunction embedInputText(f: MemoryFile): string {\n return `${f.frontmatter.name}: ${f.frontmatter.description}`;\n}\n\nasync function embedMemoryFile(provider: EmbeddingProvider, f: MemoryFile): Promise<PersistentEntry> {\n const fm = f.frontmatter;\n const vector = await provider.embed(embedInputText(f));\n return {\n mtime: fm.updated_at,\n type: fm.type,\n trust: fm.trust,\n description: fm.description,\n bodySnippet: snippet(f.body),\n fullBody: f.body,\n vector,\n };\n}\n\nfunction makeEntry(name: string, scope: Scope, p: PersistentEntry): MemoryIndexEntry {\n return {\n name,\n type: p.type,\n trust: p.trust,\n scope,\n description: p.description,\n rawIndexLine: `[${p.trust}] - [${name}](${name}.md) — ${p.description}`,\n bodySnippet: p.bodySnippet,\n fullBody: p.fullBody,\n vector: p.vector,\n };\n}\n\n/**\n * 从 cwd 下所有 memory 文件构建向量索引(同时遍历 project + user 两 scope)。\n *\n * 行为(2026-06-07 D8-rev + scope 双层):\n * 每个 scope 独立处理:\n * 1. 读 .index.json\n * 2. 如果 providerId 不匹配 → 整库 invalidate,全部重 embed\n * 3. 否则按 mtime 增量:一致复用,不一致重 embed,删除多余\n * 4. 写回 .index.json\n *\n * 输出合并的 entries(每条带 scope 字段),按 scope 顺序 project → user。\n */\nexport async function buildMemoryIndex(cwd: string, opts: BuildIndexOpts = {}): Promise<MemoryIndex> {\n // 优先用 caller 注入的 provider;否则按配置创建并(默认)做 probe 校验\n let provider: EmbeddingProvider;\n if (opts.provider) {\n provider = opts.provider;\n } else if (opts.skipProbe) {\n provider = createEmbeddingProvider(opts.config);\n } else {\n provider = await createAndProbeProvider(opts.config ?? {});\n }\n const allEntries: MemoryIndexEntry[] = [];\n\n for (const scope of SCOPES) {\n const files = await listMemories(cwd, { scope });\n if (files.length === 0) continue;\n\n const persistent = opts.noPersist ? null : await readPersistent(cwd, scope);\n const sameProvider = persistent?.providerId === provider.id && persistent?.dim === provider.dim;\n const oldEntries = sameProvider ? persistent!.entries : {};\n\n const newEntries: { [name: string]: PersistentEntry } = {};\n for (const f of files) {\n const name = f.frontmatter.name;\n const old = oldEntries[name];\n if (old && old.mtime === f.frontmatter.updated_at) {\n newEntries[name] = {\n ...old,\n type: f.frontmatter.type,\n trust: f.frontmatter.trust,\n description: f.frontmatter.description,\n bodySnippet: snippet(f.body),\n fullBody: f.body,\n };\n } else {\n newEntries[name] = await embedMemoryFile(provider, f);\n }\n }\n\n if (!opts.noPersist) {\n await writePersistent(cwd, scope, {\n providerId: provider.id,\n dim: provider.dim,\n schemaVersion: 1,\n entries: newEntries,\n });\n }\n\n for (const [name, p] of Object.entries(newEntries)) {\n allEntries.push(makeEntry(name, scope, p));\n }\n }\n\n return { provider, entries: allEntries, builtAt: new Date().toISOString(), cwd };\n}\n\n/**\n * 增量 upsert:MemoryWrite 后调用,把单条 memory 加入或更新到已有索引。\n * scope 不指定时按 readMemory 规则自动定位(project 优先 fallback user)。\n */\nexport async function upsertMemoryEntry(index: MemoryIndex, name: string, scope?: Scope): Promise<void> {\n let f: MemoryFile;\n try {\n f = await readMemory(index.cwd, name, scope);\n } catch {\n return;\n }\n const p = await embedMemoryFile(index.provider, f);\n\n // in-memory 数组 upsert\n const idx = index.entries.findIndex((e) => e.name === name && e.scope === f.scope);\n const newEntry = makeEntry(name, f.scope, p);\n if (idx >= 0) index.entries[idx] = newEntry;\n else index.entries.push(newEntry);\n\n // 落盘(该 scope 的 .index.json)\n const persistent = (await readPersistent(index.cwd, f.scope)) ?? {\n providerId: index.provider.id,\n dim: index.provider.dim,\n schemaVersion: 1 as const,\n entries: {},\n };\n persistent.entries[name] = p;\n await writePersistent(index.cwd, f.scope, persistent);\n}\n\n/**\n * 移除单条 entry:deleteMemory 后调用。\n * scope 指定时只删该层;不指定时项目 + 全局都尝试删(无害,name 不存在不抛错)。\n */\nexport async function removeMemoryEntry(index: MemoryIndex, name: string, scope?: Scope): Promise<void> {\n const targets: Scope[] = scope ? [scope] : [\"project\", \"user\"];\n for (const s of targets) {\n // in-memory\n const idx = index.entries.findIndex((e) => e.name === name && e.scope === s);\n if (idx >= 0) index.entries.splice(idx, 1);\n // 落盘\n const persistent = await readPersistent(index.cwd, s);\n if (persistent && persistent.entries[name]) {\n delete persistent.entries[name];\n await writePersistent(index.cwd, s, persistent);\n }\n }\n}\n\n/** 强制 invalidate 某 scope 的索引文件,下次 buildMemoryIndex 全量重 embed。 */\nexport async function clearPersistedIndex(cwd: string, scope?: Scope): Promise<void> {\n const targets: Scope[] = scope ? [scope] : [\"project\", \"user\"];\n for (const s of targets) {\n const path = indexPath(cwd, s);\n if (!existsSync(path)) continue;\n try {\n await unlink(path);\n } catch {\n // ignore\n }\n }\n}\n\n// ============================== 查询 / 召回 ==============================\n\nexport interface QueryOpts {\n /** top-K(默认 5)。 */\n topK?: number;\n /** 最低相似度阈值(默认 0;降低阈值召回更多但噪音多)。 */\n minScore?: number;\n}\n\nexport interface QueryResult {\n entry: MemoryIndexEntry;\n /** 余弦相似度(0-1)。 */\n score: number;\n /** trust × scope 双重加权后的最终排序分。 */\n weighted: number;\n}\n\n/**\n * 召回:embed query → 双重加权(trust × scope) → top-K。\n *\n * 加权公式(R3 拍板):\n * weighted = cosine × trustW × scopeW\n *\n * trustW:trusted ×1.5 / verified ×1.2 / auto ×1.0\n * scopeW:project ×1.2 / user ×1.0\n */\nexport async function queryMemoryIndex(\n index: MemoryIndex,\n queryText: string,\n opts: QueryOpts = {},\n): Promise<QueryResult[]> {\n if (index.entries.length === 0) return [];\n const topK = opts.topK ?? 5;\n const minScore = opts.minScore ?? 0;\n const queryVec = await index.provider.embed(queryText);\n const scored = index.entries\n .map((entry) => {\n const score = cosineSimilarity(queryVec, entry.vector);\n const weighted = score * trustWeight(entry.trust) * scopeWeight(entry.scope);\n return { entry, score, weighted };\n })\n .filter((r) => r.score > minScore)\n .sort((a, b) => b.weighted - a.weighted);\n return scored.slice(0, topK);\n}\n\n/** trust 加权:trusted ×1.5,verified ×1.2,auto ×1.0(R3 设计 §4.5)。 */\nfunction trustWeight(t: TrustLevel): number {\n switch (t) {\n case \"trusted\":\n return 1.5;\n case \"verified\":\n return 1.2;\n case \"auto\":\n return 1.0;\n }\n}\n\n/** scope 加权:project ×1.2,user ×1.0(R3 — 项目优先 > 全局)。 */\nfunction scopeWeight(s: Scope): number {\n return s === \"project\" ? 1.2 : 1.0;\n}\n\n/** 把召回结果格式化为可注入 system prompt 的索引段(替代 loadMemoryIndex)。\n * 本函数只输出索引行;trust 分级 body 注入由 inject-memory stage 完成。 */\nexport function formatRetrievedAsIndex(results: QueryResult[]): string {\n if (results.length === 0) return \"\";\n return results.map((r) => r.entry.rawIndexLine).join(\"\\n\");\n}\n\nexport { trustRank, trustWeight, scopeWeight };\n","/**\n * Token 计数:基于 js-tiktoken(纯 JS,无 WASM 依赖)。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.2.3 trim-history / §4.2.4 budget-guard\n * ADR:暂用 cl100k_base 作为跨 provider 通用编码。OpenAI / DeepSeek / Qwen / Kimi\n * 系实际编码各异,但 trim/budget 的 0.8/0.95 阈值已留出 ~20% safety margin,\n * 不同 provider 真实 token 数偏差通常在 ±20% 内可吸收。后续需要 provider-aware\n * 时只改 getEncoder() 一处。\n *\n * 单例 encoder:getEncoding 内部已经做了缓存,但模块级 once 更明确。\n */\n\nimport { getEncoding, type Tiktoken } from \"js-tiktoken\";\nimport type { Message, ToolDefinition } from \"../types/index.js\";\n\nlet _enc: Tiktoken | undefined;\nfunction enc(): Tiktoken {\n if (!_enc) _enc = getEncoding(\"cl100k_base\");\n return _enc;\n}\n\n/** 计单段文本的 token 数。空字符串返 0。 */\nexport function countText(text: string): number {\n if (!text) return 0;\n return enc().encode(text).length;\n}\n\n/**\n * 计一组 messages + 可选 systemPrompt + 可选 tools 的总 prompt token 数。\n *\n * - text part 直接 encode\n * - tool_use part:name + JSON.stringify(args)\n * - tool result(role=\"tool\"):content 字符串\n * - file / image part:占位文本(图像真实 token 由 vision 模型另计,这里无法预知)\n * - tools 定义:JSON.stringify 后 encode\n *\n * 这是上层 RequestPipeline / Agent estimateInputTokens 的统一入口。\n */\nexport function countMessages(\n messages: Message[],\n systemPrompt?: string,\n tools?: ToolDefinition[],\n): number {\n let total = 0;\n if (systemPrompt) total += countText(systemPrompt);\n\n for (const m of messages) {\n if (m.role === \"tool\") {\n total += countText(m.content);\n continue;\n }\n const content = m.content;\n if (typeof content === \"string\") {\n total += countText(content);\n } else if (Array.isArray(content)) {\n for (const p of content) {\n if (p.type === \"text\") total += countText(p.text ?? \"\");\n else if (p.type === \"tool_use\") {\n total += countText(p.name) + countText(JSON.stringify(p.args ?? {}));\n } else if (p.type === \"file\") {\n // file part 在 client 序列化时 wrap 为 <file path=\"...\">...</file> 送 LLM;\n // 估算时把 path + text 全算上,避免 file 附件 token 数被漏估\n total += countText(p.path) + countText(p.text);\n } else if (p.type === \"image\") {\n // vision token 由模型方按 tile/resolution 计费,prompt 侧用占位估算\n total += countText(`[image: ${p.path ?? p.mediaType}]`);\n }\n }\n }\n }\n\n if (tools && tools.length > 0) {\n // tools 整段 JSON 序列化 — 与发给 LLM 的 schema 形态最接近的近似\n for (const t of tools) total += countText(JSON.stringify(t));\n }\n\n return total;\n}\n\n/**\n * 单条 message 的 token 数(trim-history 逐条估算用)。\n */\nexport function countMessage(m: Message): number {\n return countMessages([m]);\n}\n","/**\n * Hook 加载与执行。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §六。\n *\n * Hook 协议:外部 shell 命令 + stdin JSON / stdout JSON。\n * Hook 点位(MVP 只接 PreToolUse / PostToolUse,其余 schema 保留但不调用):\n * SessionStart / SessionEnd / UserPromptSubmit /\n * PreLLMRequest / PostLLMResponse /\n * PreToolUse / PostToolUse /\n * PreCompact / PostCompact\n */\n\nimport { execa } from \"execa\";\nimport { NOOP_LOGGER, type PreprocessLogger } from \"./types.js\";\nimport { PipelineBlockedError } from \"./pipeline.js\";\n\nexport type HookPoint =\n | \"SessionStart\"\n | \"SessionEnd\"\n | \"UserPromptSubmit\"\n | \"PreLLMRequest\"\n | \"PostLLMResponse\"\n | \"PreToolUse\"\n | \"PostToolUse\"\n | \"PreCompact\"\n | \"PostCompact\"\n | \"MemoryPromote\";\n\nexport interface HookSpec {\n /** 工具名 / 路径前缀的正则匹配字符串(不含 /);\"\" 或缺省视为全匹配 .* 。 */\n matcher?: string;\n /** 绝对路径或 PATH 可解析命令;**禁用 shell 元字符**。 */\n command: string;\n /** 毫秒,默认 30000,上限 60000。 */\n timeout?: number;\n /** \"skip\"(默认)记 warn 后继续 / \"throw\" 命中即 abort 当前 turn。 */\n onError?: \"skip\" | \"throw\";\n}\n\nexport interface HooksConfig {\n SessionStart?: HookSpec[];\n SessionEnd?: HookSpec[];\n UserPromptSubmit?: HookSpec[];\n PreLLMRequest?: HookSpec[];\n PostLLMResponse?: HookSpec[];\n PreToolUse?: HookSpec[];\n PostToolUse?: HookSpec[];\n PreCompact?: HookSpec[];\n PostCompact?: HookSpec[];\n /** I-5:compactMessages 在 promote 每条 fact 到 memory 之前调用;可 block 该条。 */\n MemoryPromote?: HookSpec[];\n}\n\nexport interface HookOutput {\n /** 由 hook 返回的字段,会与原 input merge(具体字段由点位定义)。 */\n [k: string]: unknown;\n block?: { reason: string };\n}\n\nconst DEFAULT_TIMEOUT = 30_000;\nconst MAX_TIMEOUT = 60_000;\nconst SHELL_META = /[;|&><`$()]/;\n\n/**\n * 跑同点位的全部 hooks(串行链式)。返回最终 merged 输出。\n *\n * - 任一 hook 返回 block → 立即抛 PipelineBlockedError\n * - hook 进程非 0 退出 / 超时 / stdout 非 JSON → 按 onError 处理\n *\n * MVP 期间只在 PreToolUse / PostToolUse 调用;其它点位 schema 保留,不接代码。\n */\nexport async function runHooks(\n point: HookPoint,\n input: Record<string, unknown>,\n hooks: HooksConfig | undefined,\n logger: PreprocessLogger = NOOP_LOGGER,\n): Promise<HookOutput> {\n const specs = hooks?.[point];\n if (!specs || specs.length === 0) return {};\n\n let merged: HookOutput = {};\n let payload: Record<string, unknown> = { ...input };\n\n const matcherKey = pickMatcherKey(input);\n\n for (const spec of specs) {\n if (!matchesMatcher(spec.matcher, payload, matcherKey)) continue;\n if (SHELL_META.test(spec.command)) {\n logger.warn(`hook:${point}`, `command rejected: contains shell metachar`, { command: spec.command });\n continue;\n }\n const timeout = Math.min(spec.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);\n try {\n const result = await execa(spec.command, [], {\n input: JSON.stringify(payload),\n timeout,\n reject: false,\n env: hookEnv(),\n });\n if (result.failed) {\n const reason = `exit ${result.exitCode ?? \"?\"} / signal ${result.signal ?? \"\"}`;\n handleHookError(point, spec, reason, logger);\n continue;\n }\n const text = (result.stdout ?? \"\").trim();\n if (!text) continue;\n let out: HookOutput;\n try {\n out = JSON.parse(text) as HookOutput;\n } catch (err) {\n handleHookError(point, spec, `stdout not JSON: ${(err as Error).message}`, logger);\n continue;\n }\n if (out?.block && typeof out.block === \"object\" && typeof out.block.reason === \"string\") {\n throw new PipelineBlockedError(point, out.block.reason);\n }\n merged = { ...merged, ...out };\n // 链式:下一 hook 看见上一个 hook 改写后的值\n payload = { ...payload, ...out };\n } catch (err) {\n if (err instanceof PipelineBlockedError) throw err;\n handleHookError(point, spec, (err as Error).message, logger);\n }\n }\n return merged;\n}\n\nfunction handleHookError(point: HookPoint, spec: HookSpec, reason: string, logger: PreprocessLogger): void {\n const onError = spec.onError ?? \"skip\";\n logger.warn(`hook:${point}`, reason, { command: spec.command, onError });\n if (onError === \"throw\") {\n throw new Error(`hook ${point} failed: ${reason}`);\n }\n}\n\n/** 输入哪个字段作 matcher 比较:PreToolUse/PostToolUse 用 toolName,其余按 stage 自身约定。 */\nfunction pickMatcherKey(input: Record<string, unknown>): string | undefined {\n if (typeof input.toolName === \"string\") return \"toolName\";\n if (typeof input.path === \"string\") return \"path\";\n return undefined;\n}\n\nfunction matchesMatcher(matcher: string | undefined, payload: Record<string, unknown>, key: string | undefined): boolean {\n if (!matcher || matcher === \".*\") return true;\n if (!key) return true;\n const value = payload[key];\n if (typeof value !== \"string\") return true;\n try {\n return new RegExp(matcher).test(value);\n } catch {\n return false;\n }\n}\n\n/** Hook 子进程的环境变量白名单(避免泄露 MUSE_ACTIVE_API_KEY 等密钥)。 */\nfunction hookEnv(): NodeJS.ProcessEnv {\n const allow = [\"PATH\", \"HOME\", \"LANG\", \"LC_ALL\", \"TERM\", \"USER\", \"SHELL\"];\n const out: NodeJS.ProcessEnv = {};\n for (const key of allow) {\n const v = process.env[key];\n if (v) out[key] = v;\n }\n return out;\n}\n","/**\n * Compaction 摘要 prompt 模板。\n *\n * 设计文档:模块设计/上下文管理工程/设计.md §4.2(I-2)。\n *\n * 主 schema:9 节结构化(对齐业界共识),要求 LLM 完整列出所有 user 消息原文。\n * 降级 schema:6 节(合并较松散的小节),供未明实测稳定性的 provider 用。\n *\n * 摘要后附加 facts_to_promote JSON(I-5 联动):提取跨 session 价值事实供\n * compactMessages 自动写入长期 memory。LLM 强约束\"宁可少不可多\",防误存。\n */\n\nexport type SummarySchema = \"9-section\" | \"6-section\";\n\nconst FACTS_BLOCK = `\n\n---\n\n# Extracted Facts for Long-term Memory (optional)\n\nIf — and only if — the conversation revealed durable facts worth keeping across future sessions,\noutput one JSON code block in this format:\n\n\\`\\`\\`json\n{\n \"facts\": [\n {\n \"name\": \"kebab-case-slug\",\n \"type\": \"user\" | \"feedback\" | \"project\" | \"reference\",\n \"description\": \"one-line summary used as memory index hook\",\n \"body\": \"markdown content of the fact\"\n }\n ]\n}\n\\`\\`\\`\n\nStrict constraints (read carefully — over-eager extraction breaks user trust):\n- Only include facts with **cross-session value**: user role / preference, project hard rule, validated approach\n- Do NOT include: code visible in the repo, git history facts, transient task state, errors already fixed\n- Do NOT save chitchat, model-internal reasoning, or speculation\n- If nothing meets the bar, output \\`{\"facts\": []}\\` — empty is better than noise\n- Each fact \\`name\\` must be a unique slug (kebab- or snake-case alphanumeric)\n- For \\`feedback\\` / \\`project\\` types, body should lead with the rule, then \"Why:\" and \"How to apply:\" lines`;\n\nexport function buildSummaryPrompt(transcript: string, schema: SummarySchema): string {\n if (schema === \"9-section\") {\n return SECTION_9_TEMPLATE.replace(\"{TRANSCRIPT}\", transcript) + FACTS_BLOCK;\n }\n return SECTION_6_TEMPLATE.replace(\"{TRANSCRIPT}\", transcript) + FACTS_BLOCK;\n}\n\nconst SECTION_9_TEMPLATE = `Summarize the following conversation. Use **exactly these 9 sections in this order**. If a section has no content, write \"(none)\" — do not skip section numbers.\n\n# Conversation Summary\n\n1. **Primary Request and Intent**\n — Quote the user's original request verbatim (use > markdown quotes). Do not paraphrase.\n\n2. **Key Technical Concepts**\n — Bullet list of frameworks, languages, libraries, patterns relevant to the conversation.\n\n3. **Files and Code Sections**\n — File path + function / class name + what was read or changed. Be concrete.\n\n4. **Errors and fixes**\n — Each error message (or class of error) + the specific fix taken. Future you will repeat these mistakes if this section is sloppy.\n\n5. **Problem Solving**\n — Key reasoning steps and trade-offs considered. \"I chose A over B because X.\"\n\n6. **All user messages**\n — **List every user message verbatim**, separated by \\`---\\`. Sacred section: NEVER omit, paraphrase, or merge user messages.\n\n7. **Pending Tasks**\n — TODOs the user explicitly stated and items the assistant identified as not-yet-done.\n\n8. **Current Work**\n — What was actively being done at the moment of summarization. One paragraph.\n\n9. **Optional Next Step**\n — Recommended next action, anchored in quote(s) from the user's recent messages. If unclear, write \"(awaiting user direction)\".\n\n--- BEGIN CONVERSATION ---\n{TRANSCRIPT}\n--- END CONVERSATION ---`;\n\nconst SECTION_6_TEMPLATE = `Summarize the following conversation. Use these 6 sections in order. Do not skip section numbers; write \"(none)\" for empty sections.\n\n# Conversation Summary\n\n1. **Primary Request and Intent** — Quote the user's original request verbatim.\n\n2. **Concepts, Decisions, and Reasoning** — Frameworks involved + key trade-offs.\n\n3. **Files and Changes** — File paths + what was modified.\n\n4. **Errors and fixes** — Error messages + specific fixes.\n\n5. **All user messages** — List every user message verbatim, separated by \\`---\\`. Sacred: never omit.\n\n6. **Current Work + Next Step** — What was being done + recommended next action (anchored in user quotes).\n\n--- BEGIN CONVERSATION ---\n{TRANSCRIPT}\n--- END CONVERSATION ---`;\n\n/**\n * 从 LLM 输出中提取 facts JSON 块。\n *\n * 解析策略:\n * 1. 找 ```json ... ``` 代码块,解析内容\n * 2. 容错:含 facts 字段且为数组才返;否则返 null\n * 3. 单条 fact 字段缺失 / 非 string → 跳过该条\n * 4. 重复 name → 后写覆盖前(无报错)\n */\nexport interface ExtractedFact {\n name: string;\n type: \"user\" | \"feedback\" | \"project\" | \"reference\";\n description: string;\n body: string;\n}\n\nexport function extractFacts(summaryText: string): ExtractedFact[] {\n const jsonBlock = summaryText.match(/```(?:json)?\\s*\\n([\\s\\S]*?)\\n```/);\n if (!jsonBlock) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonBlock[1].trim());\n } catch {\n return [];\n }\n if (typeof parsed !== \"object\" || parsed === null) return [];\n const facts = (parsed as { facts?: unknown }).facts;\n if (!Array.isArray(facts)) return [];\n\n const out = new Map<string, ExtractedFact>();\n for (const raw of facts) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const r = raw as Record<string, unknown>;\n const name = typeof r.name === \"string\" ? r.name : \"\";\n const type = r.type;\n const description = typeof r.description === \"string\" ? r.description : \"\";\n const body = typeof r.body === \"string\" ? r.body : \"\";\n if (!name || !description || !body) continue;\n if (!/^[a-z0-9][a-z0-9-_]*$/i.test(name)) continue;\n if (type !== \"user\" && type !== \"feedback\" && type !== \"project\" && type !== \"reference\") continue;\n out.set(name, { name, type, description, body });\n }\n return [...out.values()];\n}\n\n/**\n * 把摘要文本里的 facts JSON 代码块剥掉,只留人类可读的摘要主体。\n * compactMessages 用此把\"干净摘要\"放回 messages,facts JSON 不污染对话。\n */\nexport function stripFactsBlock(summaryText: string): string {\n return summaryText\n .replace(/---\\s*\\n\\s*#?\\s*Extracted Facts[\\s\\S]*?```(?:json)?[\\s\\S]*?```/i, \"\")\n .replace(/```(?:json)?\\s*\\n[\\s\\S]*?\\n```/g, (match) => {\n // 仅剥 JSON 含 \"facts\" 的块,其他 code block 保留\n if (/\"facts\"\\s*:/.test(match)) return \"\";\n return match;\n })\n .trim();\n}\n","/**\n * 上下文管理:手动 / 自动压缩对话历史。\n *\n * 设计文档:muse-design.md §5.3 / 模块设计/上下文管理工程/设计.md §4.2 + §4.5。\n *\n * 算法:\n * 1. 找一个安全切割点 cutoff:cutoff 之前是 \"older\",之后是 \"recent\"\n * 2. 安全 = 不破坏 assistant 的 tool_use ↔ 紧随的 tool 消息 配对\n * (在 tool_use 之后但 tool result 之前切,会让 LLM 看到悬挂的 tool_use)\n * 3. older 拼成转录,调 LLM 摘要(I-2:9 节结构化 schema,带 facts JSON)\n * 4. 摘要剥 facts JSON 后包成一条 user message(\"[Previous conversation summary] ...\"),\n * 作为新历史的开头,后接 recent\n * 5. I-5:facts 经 MemoryPromote hook 后 writeMemory(trust=auto, source=compact-promote)\n *\n * Why user 角色而非 system:\n * - 系统提示 muse 已在 systemPrompt 单独管理;不污染它\n * - 用 user role 让 LLM 自然把它当成\"任务上下文\"继续推理\n */\n\nimport type { LLMClient } from \"../llm/types.js\";\nimport type { Message, AssistantMessage, ContentPart } from \"../types/index.js\";\nimport type { HooksConfig } from \"../preprocess/hooks.js\";\nimport { runHooks } from \"../preprocess/hooks.js\";\nimport { PipelineBlockedError } from \"../preprocess/pipeline.js\";\nimport {\n buildSummaryPrompt,\n extractFacts,\n stripFactsBlock,\n type ExtractedFact,\n type SummarySchema,\n} from \"./prompts/summarize.js\";\nimport { writeMemory } from \"./memory.js\";\n\nexport interface CompactOptions {\n llm: LLMClient;\n /** 保留最近 N 条原始消息不压缩。默认 4。 */\n keepRecent?: number;\n abortSignal?: AbortSignal;\n /** LLM 摘要流式过程中的字符进度回调(每个 text-delta 触发,传累计字符数)。 */\n onProgress?: (charsReceived: number) => void;\n /** PreCompact / PostCompact / MemoryPromote hooks 配置。 */\n hooks?: HooksConfig;\n /** I-2 schema 选择;默认 \"9-section\"。 */\n schema?: SummarySchema;\n /** I-5 联动:本次 compact 触发的 cwd,用于 writeMemory 写到正确项目下。\n * 未提供时跳过 facts 提取(纯摘要模式)。 */\n cwd?: string;\n /** I-5:是否自动把 facts 写入 memory(默认 true)。 */\n promoteFactsToMemory?: boolean;\n}\n\nexport class CompactBlockedError extends Error {\n constructor(public readonly reason: string) {\n super(`compact blocked by PreCompact hook: ${reason}`);\n this.name = \"CompactBlockedError\";\n }\n}\n\nexport interface CompactResult {\n newMessages: Message[];\n summary: string;\n originalCount: number;\n newCount: number;\n /** 没有可压缩内容时为 true,messages 原样返回。 */\n noop: boolean;\n /** I-5:被提取并尝试写入 memory 的 facts(可能被 hook block 部分)。 */\n promotedFacts?: PromotedFact[];\n}\n\nexport interface PromotedFact {\n name: string;\n type: ExtractedFact[\"type\"];\n description: string;\n /** 写入结果:\"saved\" / \"blocked\"(MemoryPromote hook 拒绝)/ \"failed\"(writeMemory 错)。 */\n status: \"saved\" | \"blocked\" | \"failed\";\n reason?: string;\n}\n\nexport async function compactMessages(\n messages: Message[],\n opts: CompactOptions,\n): Promise<CompactResult> {\n const keepRecent = opts.keepRecent ?? 4;\n const cutoff = findSafeCutoff(messages, keepRecent);\n\n if (cutoff <= 0) {\n return {\n newMessages: messages,\n summary: \"\",\n originalCount: messages.length,\n newCount: messages.length,\n noop: true,\n };\n }\n\n // PreCompact hook(可 block / 用于审计)\n try {\n await runHooks(\n \"PreCompact\",\n { messageCount: messages.length, cutoff, keepRecent },\n opts.hooks,\n );\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n throw new CompactBlockedError(err.reason);\n }\n throw err;\n }\n\n const older = messages.slice(0, cutoff);\n const recent = messages.slice(cutoff);\n const schema: SummarySchema = opts.schema ?? \"9-section\";\n const rawSummary = await summarizeConversation(\n older,\n opts.llm,\n schema,\n opts.abortSignal,\n opts.onProgress,\n );\n\n // I-2:剥 facts JSON 块,留人类可读摘要主体\n const summary = stripFactsBlock(rawSummary);\n const facts = opts.cwd ? extractFacts(rawSummary) : [];\n\n const summaryMessage: Message = {\n role: \"user\",\n content:\n `[Previous conversation summary]\\n\\n${summary}\\n\\n` +\n `[End of summary. The conversation continues below.]`,\n };\n\n const newMessages: Message[] = [summaryMessage, ...recent];\n\n // PostCompact hook(不阻断)\n try {\n await runHooks(\n \"PostCompact\",\n { before: messages.length, after: newMessages.length, summary, factCount: facts.length },\n opts.hooks,\n );\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n // PostCompact 不允许 block;降级为 no-op\n } else {\n throw err;\n }\n }\n\n // I-5:把 facts 写入 memory(每条走 MemoryPromote hook 审核;失败不阻塞 compact)\n let promotedFacts: PromotedFact[] | undefined;\n const shouldPromote = opts.promoteFactsToMemory !== false && opts.cwd && facts.length > 0;\n if (shouldPromote) {\n promotedFacts = await promoteFactsToMemory(facts, opts.cwd!, opts.hooks);\n }\n\n return {\n newMessages,\n summary,\n originalCount: messages.length,\n newCount: newMessages.length,\n noop: false,\n promotedFacts,\n };\n}\n\n/**\n * I-5:把 ExtractedFact 列表写入 long-term memory。\n *\n * 行为:\n * - 每条独立处理(失败不影响下一条)\n * - MemoryPromote hook 可 block:该条标记 status=blocked + reason\n * - writeMemory 异常:status=failed + reason\n * - 成功:status=saved,trust=auto + source=compact-promote\n */\nasync function promoteFactsToMemory(\n facts: ExtractedFact[],\n cwd: string,\n hooks: HooksConfig | undefined,\n): Promise<PromotedFact[]> {\n const results: PromotedFact[] = [];\n for (const fact of facts) {\n try {\n await runHooks(\n \"MemoryPromote\",\n { name: fact.name, type: fact.type, description: fact.description, body: fact.body, source: \"compact-promote\" },\n hooks,\n );\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n results.push({\n name: fact.name,\n type: fact.type,\n description: fact.description,\n status: \"blocked\",\n reason: err.reason,\n });\n continue;\n }\n results.push({\n name: fact.name,\n type: fact.type,\n description: fact.description,\n status: \"failed\",\n reason: err instanceof Error ? err.message : String(err),\n });\n continue;\n }\n try {\n await writeMemory(cwd, {\n name: fact.name,\n description: fact.description,\n type: fact.type,\n body: fact.body,\n trust: \"auto\",\n source: \"compact-promote\",\n });\n results.push({ name: fact.name, type: fact.type, description: fact.description, status: \"saved\" });\n } catch (err) {\n results.push({\n name: fact.name,\n type: fact.type,\n description: fact.description,\n status: \"failed\",\n reason: err instanceof Error ? err.message : String(err),\n });\n }\n }\n return results;\n}\n\n/**\n * 从理想切点(messages.length - keepRecent)向前找最近的安全边界。\n * 安全边界 = user 消息(自然 turn 起点),且其之前不存在悬挂的 tool_use。\n *\n * 退化策略:找不到合法切点 → 返回 0(不压缩)。\n */\nexport function findSafeCutoff(messages: Message[], keepRecent: number): number {\n if (messages.length <= keepRecent) return 0;\n const ideal = Math.max(0, messages.length - keepRecent);\n\n for (let i = ideal; i > 0; i--) {\n if (messages[i].role !== \"user\") continue;\n if (hasUnresolvedToolUse(messages.slice(0, i))) continue;\n return i;\n }\n return 0;\n}\n\n/** older 段是否有 assistant.tool_use 但缺对应 tool 消息。 */\nfunction hasUnresolvedToolUse(older: Message[]): boolean {\n const seenToolUseIds = new Set<string>();\n const seenToolResultIds = new Set<string>();\n for (const msg of older) {\n if (msg.role === \"assistant\") {\n for (const part of msg.content) {\n if (part.type === \"tool_use\") seenToolUseIds.add(part.id);\n }\n } else if (msg.role === \"tool\") {\n seenToolResultIds.add(msg.toolUseId);\n }\n }\n for (const id of seenToolUseIds) {\n if (!seenToolResultIds.has(id)) return true;\n }\n return false;\n}\n\nasync function summarizeConversation(\n older: Message[],\n llm: LLMClient,\n schema: SummarySchema,\n abortSignal?: AbortSignal,\n onProgress?: (chars: number) => void,\n): Promise<string> {\n const transcript = renderTranscript(older);\n const prompt: Message[] = [\n {\n role: \"user\",\n content: buildSummaryPrompt(transcript, schema),\n },\n ];\n\n let text = \"\";\n for await (const ev of llm.stream({ messages: prompt, abortSignal })) {\n if (ev.type === \"text\") {\n text += ev.delta;\n onProgress?.(text.length);\n } else if (ev.type === \"error\") throw ev.error;\n }\n return text.trim() || \"(empty summary)\";\n}\n\nfunction renderTranscript(messages: Message[]): string {\n const lines: string[] = [];\n for (const msg of messages) {\n switch (msg.role) {\n case \"system\":\n lines.push(`[system]\\n${msg.content}\\n`);\n break;\n case \"user\":\n lines.push(`[user]\\n${typeof msg.content === \"string\" ? msg.content : flattenContent(msg.content)}\\n`);\n break;\n case \"assistant\":\n lines.push(`[assistant]\\n${renderAssistant(msg)}\\n`);\n break;\n case \"tool\":\n lines.push(`[tool result${msg.isError ? \" ERROR\" : \"\"}]\\n${msg.content}\\n`);\n break;\n }\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderAssistant(msg: AssistantMessage): string {\n const parts: string[] = [];\n for (const part of msg.content) {\n if (part.type === \"text\") parts.push(part.text);\n else if (part.type === \"tool_use\") {\n parts.push(`<tool_call name=\"${part.name}\" args=${JSON.stringify(part.args)} />`);\n }\n }\n return parts.join(\"\\n\");\n}\n\nfunction flattenContent(parts: ContentPart[]): string {\n const out: string[] = [];\n for (const p of parts) {\n if (p.type === \"text\") out.push(p.text);\n else if (p.type === \"file\") out.push(`[file: ${p.path}]`);\n else if (p.type === \"image\") out.push(`[image: ${p.path ?? p.mediaType}]`);\n }\n return out.join(\"\\n\");\n}\n","/**\n * budget-guard stage:trim-history 后兜底。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.2.4。\n * 触发阈值:budget × 0.95(trim 后仍超 → 调 compact;原设计默认值)。\n *\n * 顺序约束:必须排在 trim-history 之后。trim-history 已经裁掉一波又写好了\n * ctx.estimatedTokens,本 stage 只做最后的兜底。\n *\n * 失败处理:\n * - 未配 services.compact 而又超阈值 → 抛 BudgetExceededError\n * - compact 调用抛错 → 包成 BudgetExceededError\n * - compact 成功但还超阈值 → 也抛 BudgetExceededError(意味着光 compact 也救不回来,\n * 需要用户介入)\n * Agent 捕获 BudgetExceededError → onError 报告给用户,turn 结束。\n */\n\nimport type { PipelineStage } from \"../pipeline.js\";\nimport type { RequestCtx } from \"./ctx.js\";\nimport { countMessages } from \"../tokenize.js\";\n\nconst DEFAULT_GUARD_RATIO = 0.95;\n\nexport class BudgetExceededError extends Error {\n constructor(\n public readonly estimated: number,\n public readonly budget: number,\n public readonly reason: string,\n ) {\n super(`context budget exceeded: estimated ${estimated} > budget ${budget} (${reason})`);\n this.name = \"BudgetExceededError\";\n }\n}\n\nexport class BudgetGuardStage implements PipelineStage<RequestCtx> {\n readonly name = \"budget-guard\";\n\n skip(ctx: RequestCtx): boolean {\n if (ctx.settings.budgetGuard?.enabled === false) return true;\n if (!ctx.services.contextWindow) return true;\n return false;\n }\n\n async run(ctx: RequestCtx): Promise<void> {\n const budget = ctx.services.contextWindow!;\n const guardRatio = ctx.settings.budgetGuard?.budgetRatio ?? DEFAULT_GUARD_RATIO;\n const triggerAt = budget * guardRatio;\n\n // trim-history 已经写了 estimatedTokens;若未写则现场算一次\n let estimated = ctx.estimatedTokens ?? countMessages(ctx.messages, ctx.systemPrompt, ctx.tools);\n ctx.estimatedTokens = estimated;\n if (estimated <= triggerAt) return;\n\n if (!ctx.services.compact) {\n throw new BudgetExceededError(estimated, budget, \"no compact available and over 0.95 budget\");\n }\n\n let compacted: import(\"../../types/index.js\").Message[];\n try {\n compacted = await ctx.services.compact(ctx.services.abortSignal);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new BudgetExceededError(estimated, budget, `compact failed: ${msg}`);\n }\n\n ctx.messages = compacted;\n estimated = countMessages(compacted, ctx.systemPrompt, ctx.tools);\n ctx.estimatedTokens = estimated;\n if (estimated > triggerAt) {\n throw new BudgetExceededError(\n estimated,\n budget,\n \"still over 0.95 budget after compact — context unrecoverable\",\n );\n }\n }\n}\n","/**\n * RequestPipeline 上下文。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.2.1。\n */\n\nimport type { Message, ToolDefinition } from \"../../types/index.js\";\nimport type { PermissionMode } from \"../../permission/index.js\";\nimport type { TodoStore } from \"../../loop/todos.js\";\nimport type { ToolRegistry } from \"../../tools/registry.js\";\nimport type { HierarchyLayer } from \"../../loop/hierarchy.js\";\nimport type { MemoryIndex } from \"../../loop/memory-index.js\";\n\nexport interface RequestPreprocessSettings {\n trimHistory?: { enabled?: boolean; budgetRatio?: number };\n budgetGuard?: { enabled?: boolean; budgetRatio?: number };\n redact?: { enabled?: boolean };\n /** I-3 stale tool result clearing。默认开,keepRecentTurns=3,clearTools=[Read/Grep/Glob]。 */\n clearStaleToolResults?: {\n enabled?: boolean;\n keepRecentTurns?: number;\n clearTools?: string[];\n };\n}\n\nexport interface RequestServices {\n todos: TodoStore;\n /** 已加载的 MEMORY.md 索引(由 app/cli 在 turn 前刷新一次后注入)。 */\n memoryIndex: string;\n /** 已加载的 hierarchy(MUSE.md / AGENTS.md 5 层)。II-1 引入。 */\n hierarchy?: HierarchyLayer[];\n /** 已构建的 memory 向量索引(II-5,settings.memory.embedding.enabled=true 时由 caller 注入)。 */\n memoryEmbeddingIndex?: MemoryIndex;\n /** memory.embedding.topK 配置;默认 5。 */\n memoryEmbeddingTopK?: number;\n /** memory.embedding.minMemoryCount;少于此值退化到全注入。默认 3(2026-06-07 R5 修订)。 */\n memoryEmbeddingMinCount?: number;\n /** memory.embedding.maxInjectTokens;注入预算上限,超出按 trust 优先级保留。默认 1500。 */\n memoryEmbeddingMaxInjectTokens?: number;\n /** 工具注册中心,用于 toLLMDefinitions + tool 元数据。 */\n toolRegistry: ToolRegistry;\n /** 输出语言。 */\n lang?: \"en\" | \"zh-CN\";\n /** Provider 名(用于 system prompt 拼装)。 */\n provider: string;\n /** SessionStart hook 返回的额外 system prompt 片段(append 到 base 末尾)。 */\n extraSystemPrompt?: string;\n /** 当前模型可见上下文窗口(token 数);trim-history / budget-guard 用。\n * 未提供时这两个 stage 自动 skip。 */\n contextWindow?: number;\n /** 主动触发上下文压缩(budget-guard 用)。\n * 返回压缩后的新 messages。Agent 注入时会同步更新 agent.messages。\n * 抛错 = 压缩失败(LLM 调用失败 / hook block / 无可压缩内容等)。 */\n compact?: (abortSignal?: AbortSignal) => Promise<import(\"../../types/index.js\").Message[]>;\n /** 本轮 abortSignal,透给 compact 用。 */\n abortSignal?: AbortSignal;\n}\n\nexport interface RequestCtx {\n /** 当前 messages 数组(可变;stage 直接修改)。 */\n messages: Message[];\n /** 当前系统提示(stage 内累积拼装)。 */\n systemPrompt: string;\n /** 当前可见工具列表(plan 模式过滤后)。 */\n tools: ToolDefinition[];\n /** 模型 ID。 */\n modelId: string;\n /** 当前 PermissionMode。 */\n mode: PermissionMode;\n /** 估算的 prompt token 数;BudgetGuard 写入,后续 stage 可读。 */\n estimatedTokens?: number;\n /** settings.preprocess.request 配置。 */\n settings: RequestPreprocessSettings;\n /** 关联 services。 */\n services: RequestServices;\n /** 工作目录。 */\n cwd: string;\n}\n\nexport function createRequestCtx(init: {\n messages: Message[];\n modelId: string;\n mode: PermissionMode;\n cwd: string;\n services: RequestServices;\n settings?: RequestPreprocessSettings;\n}): RequestCtx {\n return {\n messages: init.messages,\n systemPrompt: \"\",\n tools: [],\n modelId: init.modelId,\n mode: init.mode,\n cwd: init.cwd,\n services: init.services,\n settings: init.settings ?? {},\n };\n}\n","/**\n * Agent loop:单循环 ReAct。\n *\n * loop:\n * RequestPipeline.run(ctx) — 拼装 systemPrompt + tools(stage 化预处理)\n * llm.stream(messages, tools)\n * → emit text → 累计 assistant 消息\n * → 收到 tool_call → 累计\n * → finish\n * if no tool_calls: break\n * for each tool_call:\n * PreToolUse hook(可阻断 / 改写 args)\n * check permission → execute\n * ResultPipeline.run(ctx) — 截断 / 检测二进制 / summary / 错误归一化\n * PostToolUse hook(可改写 content / summary)\n * push tool result\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.2 / §4.3。\n */\n\nimport type { LLMClient, LLMEvent } from \"../llm/types.js\";\nimport type { Message, AssistantMessage, ContentPart, ToolUsePart, TokenUsage } from \"../types/index.js\";\nimport type { ToolRegistry } from \"../tools/registry.js\";\nimport type { ToolContext, ToolExecuteResult } from \"../tools/types.js\";\nimport type { PermissionGate, Decision, PermissionDecision } from \"../permission/index.js\";\nimport type { Session } from \"../session/jsonl.js\";\nimport { TodoStore } from \"./todos.js\";\nimport { log } from \"../log/index.js\";\nimport type { Pipeline } from \"../preprocess/pipeline.js\";\nimport { PipelineBlockedError } from \"../preprocess/pipeline.js\";\nimport type { RequestCtx, RequestServices } from \"../preprocess/request/index.js\";\nimport { createRequestCtx, BudgetExceededError } from \"../preprocess/request/index.js\";\nimport { countMessages } from \"../preprocess/tokenize.js\";\nimport { compactMessages } from \"./context.js\";\nimport { findProjectRoot, loadSubdirMemory } from \"./hierarchy.js\";\nimport { upsertMemoryEntry, removeMemoryEntry } from \"./memory-index.js\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport type { ResultCtx, ResultPreprocessSettings } from \"../preprocess/result/index.js\";\nimport { createResultCtx } from \"../preprocess/result/index.js\";\nimport type { HooksConfig } from \"../preprocess/hooks.js\";\nimport { runHooks } from \"../preprocess/hooks.js\";\nimport type { PreprocessLogger } from \"../preprocess/types.js\";\n\n/**\n * 合并 0..N 个 AbortSignal:任一 aborted → 返回的 signal aborted。\n * 全 undefined 时返 undefined,保持 LLM stream 的\"无中断\"行为不变。\n */\nfunction combineSignals(...signals: Array<AbortSignal | undefined>): AbortSignal | undefined {\n const live = signals.filter((s): s is AbortSignal => !!s);\n if (live.length === 0) return undefined;\n if (live.length === 1) return live[0];\n const combined = new AbortController();\n for (const s of live) {\n if (s.aborted) {\n combined.abort(s.reason);\n break;\n }\n s.addEventListener(\"abort\", () => combined.abort(s.reason), { once: true });\n }\n return combined.signal;\n}\n\n/**\n * 判断是否 AbortError(node fetch / execa / undici / spec / Vercel SDK 几种风格都覆盖)。\n *\n * 之前用 name === \"AbortError\" 漏检了 Vercel AI SDK 在 abort 时抛的\n * \"This operation was aborted\" 错(name 是 APICallError / DOMException 等),\n * 加 message 关键字兜底。\n */\nfunction isAbortError(err: unknown): boolean {\n if (!err) return false;\n if (err instanceof Error) {\n if (err.name === \"AbortError\") return true;\n const code = (err as Error & { code?: string }).code;\n if (code === \"ABORT_ERR\" || code === \"ECANCELED\") return true;\n const msg = err.message.toLowerCase();\n if (msg.includes(\"aborted\") || msg.includes(\"cancelled\") || msg.includes(\"canceled\")) return true;\n }\n return false;\n}\n\nexport interface AgentEvents {\n onText?: (delta: string) => void;\n onToolCallStart?: (id: string, name: string) => void;\n onToolCallArgs?: (id: string, args: unknown) => void;\n onToolResult?: (id: string, name: string, content: string, isError: boolean, summary?: string) => void;\n onPermissionRequest?: (toolName: string, args: unknown, summary: string) => Promise<PermissionDecision>;\n onAskQuestions?: (\n questions: import(\"../tools/builtin/ask-user-question.js\").AskQuestion[],\n ) => Promise<import(\"../tools/builtin/ask-user-question.js\").AskQuestionResponse[]>;\n onUsage?: (usage: TokenUsage) => void;\n /**\n * 流式开始前 chars/4 估算 input tokens,推给 UI 让 StatusLine/ctx 立刻显示。\n * 与 onUsage 解耦:这是\"本轮 ctx 占用快照\"信号,不应进 session 累计(避免重复计费)。\n * 真实 finish usage 到达时 onUsage 会再用真实 inputTokens **覆盖**(不是累加)turn 快照。\n */\n onEstimate?: (inputTokens: number) => void;\n /**\n * 队列里的 guidance 被 inject 进 messages 数组后触发(在新一轮 LLM stream 启动**之前**)。\n * UI 用来清空\"待引导\"小框 — 内容已经\"上车\"了,不再 pending。\n */\n onGuidanceInjected?: (parts: ContentPart[]) => void;\n onError?: (error: Error) => void;\n /**\n * 一段 assistant 流结束、assistantMessage 已 push 进 messages,但工具还没开始执行时触发。\n * 用于 UI 立刻把这一批 tool_use calls 显示出来——避免\"流完 → 第一个 result 到达\"\n * 之间用户面对空屏。turn 直接结束(无 tool calls)的场景不会触发,走 onTurnEnd。\n */\n onAssistantTurn?: () => void;\n onTurnEnd?: () => void;\n /** Pipeline 被 hook 阻断 / 致命错误时触发。 */\n onBlocked?: (reason: string) => void;\n}\n\nexport interface AgentContext {\n llm: LLMClient;\n tools: ToolRegistry;\n permissions: PermissionGate;\n session: Session;\n cwd: string;\n /**\n * Legacy system prompt(向后兼容 runOneShot / 测试)。\n * 与 requestPipeline 互斥:有 pipeline 时优先 pipeline,无 pipeline 时回退到 systemPrompt + 内置 mode filter。\n */\n systemPrompt?: string;\n /** 注入式预处理:每轮 LLM 请求前跑。 */\n requestPipeline?: Pipeline<RequestCtx>;\n /** 与 requestPipeline 配套的 services(memoryIndex / provider / lang 等)。 */\n requestServices?: RequestServices;\n /** 工具结果后处理 pipeline。 */\n resultPipeline?: Pipeline<ResultCtx>;\n /** result pipeline 的运行时设置(每轮统一)。 */\n resultSettings?: ResultPreprocessSettings;\n /** 用户配置的 hooks(MVP 只跑 PreToolUse / PostToolUse)。 */\n hooks?: HooksConfig;\n /** 预处理日志器,串到 pino。 */\n hookLogger?: PreprocessLogger;\n /** Pipeline disable 列表(来自 settings.preprocess.disable)。 */\n pipelineDisable?: ReadonlyArray<string>;\n abortSignal?: AbortSignal;\n events?: AgentEvents;\n /** 注入式 TodoStore:与 requestServices.todos 共享同一实例。 */\n todos?: TodoStore;\n}\n\nexport class Agent {\n private messages: Message[] = [];\n readonly todos: TodoStore;\n /** 本轮 stream 发出时的 input tokens 估算值;finish 真实 usage 回来时减去,补差量给 UI。\n * 为什么:OpenAI 兼容 stream 的 usage 只在 finish 下发,期间 StatusLine 拿不到 token 数;\n * 先用 chars/4 估算并即刻推一次 onUsage,流式中就能显示 \"↑ N tokens\",真实值到达时无缝覆盖。 */\n private lastEstimateInputTokens = 0;\n /** 当前轮次的 abort signal(runTurn 开始时设,结束清);runToolCall 读它给 execa 等用。 */\n private turnAbortSignal?: AbortSignal;\n /**\n * \"引导(guidance)\"队列:模型还在跑时用户继续输入的内容暂存这里。\n * 主循环每轮 stream 启动前 check + flush;合并成一条 role:user 注入 messages,\n * 让 LLM 在下一轮看到\"已跑完的 tool result + 用户新输入\"一起决策。\n *\n * 注入点:工具批跑完、下一轮 LLM stream 之前。**不打断**正在跑的工具,避免模型\n * 因丢失中间结果而重跑(用户原话:\"不应该直接终止某一个小的命令或者工具执行\")。\n *\n * Esc 单击时若队列非空,优先清队列(轻撤销),还有空也不 abort turn。\n */\n private pendingGuidance: ContentPart[][] = [];\n\n /**\n * II-1.3 子目录惰性加载状态:已注入过子目录 MUSE.md / AGENTS.md 的绝对路径集合。\n *\n * tool 操作触及未加载过的子目录(包含 MUSE.md 或 AGENTS.md)时,把内容附加到 tool result\n * prefix,让 LLM 看到该子目录的 guidance。同一子目录只注入一次(去重)。\n *\n * /clear 调 clearLoadedSubdirs() 重置;/resume 不重置(假设旧 session 已加载过)。\n */\n private loadedSubdirs = new Set<string>();\n private readonly projectRoot: string;\n\n constructor(private ctx: AgentContext) {\n this.todos = ctx.todos ?? new TodoStore();\n this.projectRoot = findProjectRoot(ctx.cwd);\n }\n\n /** 给 /clear 等场景重置子目录加载状态。 */\n clearLoadedSubdirs(): void {\n this.loadedSubdirs.clear();\n }\n\n /** 估算 input tokens:走 src/preprocess/tokenize.ts(js-tiktoken cl100k_base)。\n * 比旧 chars/4 精度高,trim-history / budget-guard 也共享同一个估算口径。 */\n private estimateInputTokens(\n messages: Message[],\n systemPrompt: string,\n tools: import(\"../types/index.js\").ToolDefinition[],\n ): number {\n return countMessages(messages, systemPrompt, tools);\n }\n\n getMessages(): Message[] {\n return this.messages;\n }\n\n setMessages(msgs: Message[]): void {\n this.messages = msgs;\n }\n\n /**\n * 把一段\"引导\"内容塞进队列。下一轮 stream 启动前会被合并成一条 role:user 注入 messages。\n * 调用方:App 的 handleSubmit 在 state.status !== \"idle\" 时走这条路径。\n */\n enqueueGuidance(content: string | ContentPart[]): void {\n const parts: ContentPart[] = typeof content === \"string\"\n ? [{ type: \"text\", text: content }]\n : content;\n this.pendingGuidance.push(parts);\n }\n\n /** 用户单击 Esc 时若队列非空,清掉(轻撤销;不 abort 当前 turn)。 */\n clearGuidance(): void {\n this.pendingGuidance.length = 0;\n }\n\n getPendingGuidanceCount(): number {\n return this.pendingGuidance.length;\n }\n\n /**\n * 把当前 pendingGuidance 合并成一条 role:user message push 进 messages,清空队列。\n * 多条 guidance 之间用空行分隔(模型把它们读成\"一次性补充的几点\")。\n * 返回 true 表示真的注入了内容;false 表示队列本就空。\n */\n private flushGuidance(): boolean {\n if (this.pendingGuidance.length === 0) return false;\n const queued = this.pendingGuidance;\n this.pendingGuidance = [];\n\n // 合并:每条 guidance 是 ContentPart[];多条之间塞一段分隔 text。\n // 优先合并所有相邻 text part 成一段(避免一堆零散 part 在 LLM 端看起来怪)。\n const merged: ContentPart[] = [];\n const SEP = \"\\n\\n---\\n\\n\";\n for (let i = 0; i < queued.length; i++) {\n const parts = queued[i];\n if (i > 0) {\n // 分隔符尽量并入前一段 text 末尾\n const tail = merged[merged.length - 1];\n if (tail && tail.type === \"text\") tail.text += SEP;\n else merged.push({ type: \"text\", text: SEP });\n }\n for (const p of parts) {\n const tail = merged[merged.length - 1];\n if (p.type === \"text\" && tail && tail.type === \"text\") {\n tail.text += p.text;\n } else {\n // 浅拷贝避免外部突变影响 messages\n merged.push({ ...p });\n }\n }\n }\n\n const guidanceMsg: Message = { role: \"user\", content: merged };\n this.messages.push(guidanceMsg);\n this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: guidanceMsg });\n this.ctx.events?.onGuidanceInjected?.(merged);\n return true;\n }\n\n /**\n * 执行一次完整的\"用户输入 → 助手响应(含工具循环) → 等待下一轮输入\"。\n *\n * userInput 可以是:\n * - string:纯文本(向后兼容,无附件场景)\n * - ContentPart[]:多 part 内容(text + file/image 附件)\n *\n * abortSignal:本轮专属信号(每轮新建,App.handleSubmit 传入);Esc 触发 abort\n * 时立刻打断 LLM stream + execa 工具 + 等待循环。优先级高于 ctx.abortSignal\n * (后者是进程级 / 启动时签名,用于全局退出)。\n */\n async runTurn(userInput: string | ContentPart[], abortSignal?: AbortSignal): Promise<void> {\n const turnSignal = combineSignals(abortSignal, this.ctx.abortSignal);\n this.turnAbortSignal = turnSignal;\n const userMessage: Message = { role: \"user\", content: userInput };\n this.messages.push(userMessage);\n await this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: userMessage });\n\n // 内部循环:工具调用可能多轮\n while (true) {\n // 上一轮 tool 跑完(或 turn 刚开始)→ stream 启动前 flush guidance 队列。\n // 注入点:已落到 messages 的\"tool_result 序列\"之后 + 下一轮 stream 之前,\n // 这样 LLM 在 prompt 里看到的就是「上轮工具结果 + 用户新输入」,顺势继续推进\n // 而不会因为消息丢失重跑刚才的工具。\n this.flushGuidance();\n\n let systemPrompt: string;\n let tools: import(\"../types/index.js\").ToolDefinition[];\n let messagesForStream: Message[];\n try {\n const built = await this.buildRequest();\n systemPrompt = built.systemPrompt;\n tools = built.tools;\n messagesForStream = built.messages;\n } catch (err) {\n // budget-guard 抛 BudgetExceededError → 报给用户,turn 结束\n if (err instanceof BudgetExceededError) {\n this.ctx.events?.onError?.(err);\n log.error(\"budget exceeded\", { msg: err.message });\n this.turnAbortSignal = undefined;\n return;\n }\n throw err;\n }\n\n // PreLLMRequest hook 可改写 messages / systemPrompt / tools 或 block\n try {\n const hookOut = await runHooks(\n \"PreLLMRequest\",\n { messages: this.messages, systemPrompt, tools, modelId: this.ctx.llm.model },\n this.ctx.hooks,\n this.ctx.hookLogger,\n );\n if (typeof hookOut.systemPrompt === \"string\") systemPrompt = hookOut.systemPrompt;\n if (Array.isArray(hookOut.messages)) messagesForStream = hookOut.messages as Message[];\n if (Array.isArray(hookOut.tools)) tools = hookOut.tools as import(\"../types/index.js\").ToolDefinition[];\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n this.ctx.events?.onBlocked?.(err.reason);\n this.ctx.events?.onError?.(new Error(`PreLLMRequest blocked: ${err.reason}`));\n return;\n }\n throw err;\n }\n\n // 流式开始前用 chars/4 估算 input tokens 即刻推给 UI,让 StatusLine 立刻显示。\n // 走 onEstimate(不是 onUsage)避免污染 session 累计计费;finish 真实 usage 到达后\n // 上层 reducer 会用真实 inputTokens 覆盖本轮 ctx 快照(不累加)。\n const estimate = this.estimateInputTokens(messagesForStream, systemPrompt, tools);\n this.lastEstimateInputTokens = estimate;\n this.ctx.events?.onEstimate?.(estimate);\n\n const stream = this.ctx.llm.stream({\n messages: messagesForStream,\n tools,\n systemPrompt,\n abortSignal: turnSignal,\n });\n\n const assistantParts: ContentPart[] = [];\n const toolCallsToRun: ToolUsePart[] = [];\n let lastError: Error | undefined;\n\n try {\n for await (const ev of stream) {\n this.handleEvent(ev, assistantParts, toolCallsToRun, (e) => {\n lastError = e;\n });\n if (lastError) break;\n if (turnSignal?.aborted) break;\n }\n } catch (err) {\n if (isAbortError(err) || turnSignal?.aborted) {\n // Esc 触发的优雅中断:保留已生成的 assistant 文本 + 任何已完成的 tool_use 在 history,\n // 但**不**进入工具执行环节(toolCallsToRun 直接清空)。让 UI 看到\"我已经说了一半\"。\n this.persistInterruptedAssistant(assistantParts);\n this.ctx.events?.onTurnEnd?.();\n this.turnAbortSignal = undefined;\n return;\n }\n throw err;\n }\n\n if (lastError) {\n this.ctx.events?.onError?.(lastError);\n log.error(\"agent stream error\", { msg: lastError.message });\n this.turnAbortSignal = undefined;\n return;\n }\n\n // Esc 在 stream loop 内 break 但未抛错(turnSignal.aborted)\n if (turnSignal?.aborted) {\n this.persistInterruptedAssistant(assistantParts);\n this.ctx.events?.onTurnEnd?.();\n this.turnAbortSignal = undefined;\n return;\n }\n\n // 把 assistant 消息加入历史\n const assistantMessage: AssistantMessage = { role: \"assistant\", content: assistantParts };\n this.messages.push(assistantMessage);\n await this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: assistantMessage });\n\n // PostLLMResponse hook(不阻断,仅审计 / 镜像;返回值忽略)\n const assistantText = assistantParts\n .filter((p): p is { type: \"text\"; text: string } => p.type === \"text\")\n .map((p) => p.text)\n .join(\"\");\n const toolCalls = toolCallsToRun.map((t) => ({ id: t.id, name: t.name, args: t.args }));\n try {\n await runHooks(\n \"PostLLMResponse\",\n { assistantText, toolCalls },\n this.ctx.hooks,\n this.ctx.hookLogger,\n );\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n log.warn(\"PostLLMResponse tried to block, ignored\", { reason: err.reason });\n } else {\n throw err;\n }\n }\n\n if (toolCallsToRun.length === 0) {\n // 模型刚说完一段 text 没要工具——本该 turn 结束。但若用户在生成期间塞了 guidance\n // 进队列,把\"结束\"折叠成\"继续下一轮\":循环顶上 flushGuidance 会把它注入成新的\n // user message,LLM 在新一轮 stream 里基于\"刚答完的内容 + 用户追问\"自然推进。\n if (this.pendingGuidance.length > 0) continue;\n this.ctx.events?.onTurnEnd?.();\n this.turnAbortSignal = undefined;\n return;\n }\n\n // 流刚结束、tool 还没跑——给 UI 一个钩子立刻展示这一批 calls\n this.ctx.events?.onAssistantTurn?.();\n\n // 执行工具调用;每个工具开始前再检查 abort,避免 stream 中断后还硬跑工具。\n // 每个工具跑完后 yield 一次 event loop:让 React commit + Ink paint 完成,\n // 避免快速本地工具(ls/cat 等 ~30ms)让 React 18 auto-batching 把多次 history_set\n // 合并成单次 commit——那样用户会错过 active row 切换的全部中间帧。\n for (const call of toolCallsToRun) {\n if (turnSignal?.aborted) {\n this.recordToolResult(call.id, call.name, `Interrupted by user (Esc).`, true);\n } else {\n await this.runToolCall(call);\n await new Promise<void>((resolve) => setImmediate(resolve));\n }\n }\n // 工具循环跑完后若已 abort,本轮直接收尾,不再开新一轮 LLM stream\n if (turnSignal?.aborted) {\n this.ctx.events?.onTurnEnd?.();\n this.turnAbortSignal = undefined;\n return;\n }\n }\n }\n\n /** 拼装本轮 system prompt + tools(+ 可能 trim 后的 messages)。\n * 优先走 RequestPipeline,无 pipeline 时回退到 legacy 路径。\n *\n * 注意:trim-history 可能替换 ctx.messages,这里把它回流出去给主循环作为\n * messagesForStream。**不污染** this.messages — 因为 trim 是临时为本次请求\n * 做的窗口缩减,真正的历史不动(budget-guard 触发的 compact 例外:那是\n * 通过 services.compact 真实写回 this.messages 的)。 */\n private async buildRequest(): Promise<{\n systemPrompt: string;\n tools: import(\"../types/index.js\").ToolDefinition[];\n messages: Message[];\n }> {\n if (this.ctx.requestPipeline && this.ctx.requestServices) {\n const ctx = createRequestCtx({\n messages: this.messages,\n modelId: this.ctx.llm.model,\n mode: this.ctx.permissions.getMode(),\n cwd: this.ctx.cwd,\n services: {\n ...this.ctx.requestServices,\n todos: this.todos,\n contextWindow: this.ctx.llm.capabilities.maxContextWindow,\n abortSignal: this.turnAbortSignal,\n // compact 闭包:budget-guard 触发时调用。真实改写 this.messages\n // (compact 是历史压缩,不可逆,要落到 agent state)。\n compact: async (signal) => {\n // I-5 联动:传 cwd 触发 facts 自动 promote 到 long-term memory\n const result = await compactMessages(this.messages, {\n llm: this.ctx.llm,\n abortSignal: signal,\n hooks: this.ctx.hooks,\n cwd: this.ctx.cwd,\n });\n this.messages = result.newMessages;\n // II-5 联动:把成功 promote 的 facts upsert 到 in-memory 向量索引(session 内立即可召回)\n if (result.promotedFacts && this.ctx.requestServices?.memoryEmbeddingIndex) {\n for (const f of result.promotedFacts) {\n if (f.status !== \"saved\") continue;\n try {\n await upsertMemoryEntry(this.ctx.requestServices.memoryEmbeddingIndex, f.name, \"project\");\n } catch (err) {\n log.warn(\"memory index upsert (compact-promote) failed\", { name: f.name, msg: (err as Error).message });\n }\n }\n }\n return this.messages;\n },\n },\n });\n await this.ctx.requestPipeline.run(ctx);\n return { systemPrompt: ctx.systemPrompt, tools: ctx.tools, messages: ctx.messages };\n }\n // Legacy fallback\n const mode = this.ctx.permissions.getMode();\n const tools = this.ctx.tools.toLLMDefinitions(\n mode === \"plan\" ? (t) => t.permission === \"read\" : undefined,\n );\n const todoSection = this.todos.toPromptSection();\n const base = this.ctx.systemPrompt ?? \"\";\n const systemPrompt = todoSection ? `${base}\\n\\n${todoSection}` : base;\n return { systemPrompt, tools, messages: this.messages };\n }\n\n private handleEvent(\n ev: LLMEvent,\n assistantParts: ContentPart[],\n toolCallsToRun: ToolUsePart[],\n onError: (e: Error) => void,\n ): void {\n switch (ev.type) {\n case \"text\":\n {\n const last = assistantParts[assistantParts.length - 1];\n if (last && last.type === \"text\") {\n last.text += ev.delta;\n } else {\n assistantParts.push({ type: \"text\", text: ev.delta });\n }\n }\n this.ctx.events?.onText?.(ev.delta);\n break;\n\n case \"tool_call_start\":\n this.ctx.events?.onToolCallStart?.(ev.id, ev.name);\n break;\n\n case \"tool_call_complete\": {\n const callPart: ToolUsePart = { type: \"tool_use\", id: ev.id, name: ev.name, args: ev.args };\n assistantParts.push(callPart);\n toolCallsToRun.push(callPart);\n this.ctx.events?.onToolCallArgs?.(ev.id, ev.args);\n break;\n }\n\n case \"finish\":\n if (ev.usage) {\n // 推 delta:已经通过 estimate 注入了 lastEstimateInputTokens,这里只补 (real - estimate);\n // outputTokens 没估算过,直接推真实值。\n const adjusted: TokenUsage = {\n inputTokens: ev.usage.inputTokens - this.lastEstimateInputTokens,\n outputTokens: ev.usage.outputTokens,\n totalTokens: ev.usage.totalTokens - this.lastEstimateInputTokens,\n };\n this.ctx.events?.onUsage?.(adjusted);\n this.ctx.session.append({\n type: \"usage\",\n time: new Date().toISOString(),\n usage: ev.usage, // session 写真实值,不写 estimate\n provider: this.ctx.llm.providerName,\n model: this.ctx.llm.model,\n });\n }\n this.lastEstimateInputTokens = 0; // 不论 usage 是否回都复位,下一轮 stream 重新估\n break;\n\n case \"error\":\n onError(ev.error);\n break;\n }\n }\n\n /** Esc 中断时:把\"已经流出来\"的 assistant 内容存进 history,标 [interrupted] 后缀。 */\n private persistInterruptedAssistant(parts: ContentPart[]): void {\n const cleanedParts: ContentPart[] = parts.filter((p) => p.type !== \"tool_use\");\n // 在最后一段 text 末尾追加 [interrupted] 标识;无 text 时新建一段\n const lastIdx = cleanedParts.length - 1;\n if (lastIdx >= 0 && cleanedParts[lastIdx].type === \"text\") {\n const t = cleanedParts[lastIdx] as { type: \"text\"; text: string };\n cleanedParts[lastIdx] = { type: \"text\", text: `${t.text}\\n\\n[interrupted]` };\n } else {\n cleanedParts.push({ type: \"text\", text: \"[interrupted]\" });\n }\n const assistantMessage: AssistantMessage = { role: \"assistant\", content: cleanedParts };\n this.messages.push(assistantMessage);\n this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: assistantMessage });\n }\n\n private async runToolCall(call: ToolUsePart): Promise<void> {\n const tool = this.ctx.tools.get(call.name);\n if (!tool) {\n const result = `Tool \"${call.name}\" is not available.`;\n this.recordToolResult(call.id, call.name, result, true);\n return;\n }\n\n const summary = tool.summarize?.(call.args) ?? `${call.name}(...)`;\n const decision: Decision = this.ctx.permissions.decide({\n toolName: call.name,\n args: call.args,\n permission: tool.permission,\n });\n\n if (decision === \"deny\") {\n const reason =\n this.ctx.permissions.getMode() === \"plan\"\n ? `Denied: you are in plan mode. Only read-only tools are available. Propose changes instead of executing.`\n : `Denied by policy: ${call.name}.`;\n this.recordToolResult(call.id, call.name, reason, true);\n return;\n }\n if (decision === \"ask\") {\n const userDecision =\n (await this.ctx.events?.onPermissionRequest?.(call.name, call.args, summary)) ?? \"no\";\n if (userDecision === \"no\") {\n this.recordToolResult(call.id, call.name, `User rejected ${call.name}.`, true);\n return;\n }\n if (userDecision === \"session_allow\") {\n this.ctx.permissions.allowForSession(call.name);\n }\n }\n\n // PreToolUse hook 可改写 args 或阻断\n let effectiveArgs = call.args;\n try {\n const hookOut = await runHooks(\n \"PreToolUse\",\n { toolName: call.name, args: effectiveArgs },\n this.ctx.hooks,\n this.ctx.hookLogger,\n );\n if (hookOut.args !== undefined) effectiveArgs = hookOut.args;\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n this.ctx.events?.onBlocked?.(err.reason);\n this.recordToolResult(call.id, call.name, `Blocked by PreToolUse hook: ${err.reason}`, true);\n return;\n }\n throw err;\n }\n\n const toolCtx: ToolContext = {\n cwd: this.ctx.cwd,\n abortSignal: this.turnAbortSignal ?? this.ctx.abortSignal,\n askPermission: async () => true, // 已在外层处理\n todos: this.todos,\n askQuestions: this.ctx.events?.onAskQuestions\n ? (qs) => this.ctx.events!.onAskQuestions!(qs)\n : undefined,\n };\n\n const raw: ToolExecuteResult = await this.ctx.tools.execute(call.name, effectiveArgs, toolCtx);\n\n // ResultPipeline 后处理 + PostToolUse hook\n const processed = await this.postProcessResult({\n toolName: call.name,\n toolUseId: call.id,\n args: effectiveArgs,\n raw,\n });\n\n this.recordToolResult(\n call.id,\n call.name,\n processed.content,\n processed.isError,\n processed.summary,\n processed.diff,\n processed.kind,\n );\n }\n\n private async postProcessResult(input: {\n toolName: string;\n toolUseId: string;\n args: unknown;\n raw: ToolExecuteResult;\n }): Promise<{ content: string; isError: boolean; summary?: string; diff?: string; kind?: \"success\" | \"error\" | \"warn\" }> {\n let content = input.raw.content;\n let summary = input.raw.summary;\n let diff = input.raw.diff;\n const isError = input.raw.isError ?? false;\n let kind = input.raw.kind;\n\n if (this.ctx.resultPipeline) {\n const rctx = createResultCtx({\n toolName: input.toolName,\n toolUseId: input.toolUseId,\n args: input.args,\n raw: input.raw,\n settings: this.ctx.resultSettings,\n });\n try {\n await this.ctx.resultPipeline.run(rctx);\n content = rctx.content;\n summary = rctx.summary;\n diff = rctx.diff;\n } catch (err) {\n log.warn(\"result pipeline error\", { msg: (err as Error).message });\n }\n }\n\n // PostToolUse hook(默认不阻断,仅改写 content / summary)\n try {\n const hookOut = await runHooks(\n \"PostToolUse\",\n { toolName: input.toolName, args: input.args, content, summary, isError },\n this.ctx.hooks,\n this.ctx.hookLogger,\n );\n if (typeof hookOut.content === \"string\") content = hookOut.content;\n if (typeof hookOut.summary === \"string\") summary = hookOut.summary;\n } catch (err) {\n if (err instanceof PipelineBlockedError) {\n // PostToolUse 不允许阻断;降级为告警\n log.warn(\"PostToolUse hook tried to block, ignored\", { reason: err.reason });\n } else {\n throw err;\n }\n }\n\n // II-5:MemoryWrite 完成后,如果当前 session 有 memoryEmbeddingIndex,\n // 触发增量 upsert 让本轮新 memory 立即可召回(避免要等下次 muse 启动)\n if (input.toolName === \"MemoryWrite\" && !isError) {\n const index = this.ctx.requestServices?.memoryEmbeddingIndex;\n if (index) {\n try {\n const args = input.args as { name?: string; scope?: string } | null | undefined;\n const name = typeof args?.name === \"string\" ? args.name : undefined;\n const scope = args?.scope === \"user\" ? \"user\" : \"project\";\n if (name) {\n await upsertMemoryEntry(index, name, scope);\n }\n } catch (err) {\n log.warn(\"memory index upsert failed\", { msg: (err as Error).message });\n }\n }\n }\n\n // II-1.3 子目录惰性加载:tool 操作触及未加载子目录(有 MUSE.md / AGENTS.md)\n // 时,把子目录内容附加到 result content 前面,让 LLM 看到该子目录的额外约束。\n try {\n const subdirInjection = await this.maybeInjectSubdirHierarchy(input.toolName, input.args);\n if (subdirInjection) {\n content = `${subdirInjection}\\n\\n---\\n\\n[Original tool result]\\n${content}`;\n }\n } catch (err) {\n // 子目录加载失败不应阻塞工具结果;只记 warn\n log.warn(\"subdir hierarchy inject failed\", { msg: (err as Error).message });\n }\n\n return { content, isError, summary, diff, kind };\n }\n\n /**\n * 检查工具操作的路径是否落入未加载过的子目录;子目录(向上找最近的)若含 MUSE.md / AGENTS.md\n * 就把内容封装成 system 注释返回(由 caller 前置到 tool result)。\n */\n private async maybeInjectSubdirHierarchy(toolName: string, args: unknown): Promise<string | null> {\n const path = extractToolPath(toolName, args);\n if (!path) return null;\n const absPath = isAbsolute(path) ? path : resolve(this.ctx.cwd, path);\n const subdir = findContainingSubdirWithHierarchy(absPath, this.projectRoot);\n if (!subdir) return null;\n if (this.loadedSubdirs.has(subdir)) return null;\n this.loadedSubdirs.add(subdir);\n const loaded = await loadSubdirMemory(subdir);\n if (!loaded) return null;\n const relPath = relative(this.projectRoot, subdir) || \".\";\n const truncatedNote = loaded.truncated ? \" (content truncated; use Read to view full file)\" : \"\";\n return `[System: loaded ${loaded.source} from ${relPath}/${truncatedNote}]\\n${loaded.content}`;\n }\n\n private recordToolResult(\n id: string,\n name: string,\n content: string,\n isError: boolean,\n summary?: string,\n diff?: string,\n kind?: \"success\" | \"error\" | \"warn\",\n ): void {\n const toolMsg: Message = {\n role: \"tool\",\n toolUseId: id,\n content,\n isError,\n toolName: name,\n ...(diff ? { diff } : {}),\n ...(summary ? { summary } : {}),\n ...(kind ? { kind } : {}),\n };\n this.messages.push(toolMsg);\n this.ctx.session.append({ type: \"message\", time: new Date().toISOString(), message: toolMsg });\n this.ctx.events?.onToolResult?.(id, name, content, isError, summary);\n }\n}\n\n// ============================== II-1.3 子目录惰性 helpers ==============================\n\n/**\n * 从工具 args 提路径字段。\n * - Read / Edit / Write 用 file_path\n * - Grep / Glob 用 path(可选)\n * - Bash 命令字符串不可靠(可能含多路径,跳过)\n * - 其他工具不提路径(返 null)\n */\nexport function extractToolPath(toolName: string, args: unknown): string | null {\n if (typeof args !== \"object\" || args === null) return null;\n if (toolName === \"Read\" || toolName === \"Edit\" || toolName === \"Write\") {\n const fp = (args as { file_path?: unknown }).file_path;\n if (typeof fp === \"string\") return fp;\n }\n if (toolName === \"Grep\" || toolName === \"Glob\") {\n const p = (args as { path?: unknown }).path;\n if (typeof p === \"string\") return p;\n }\n return null;\n}\n\n/**\n * 从 absPath 的 dirname 开始向上找,直到 projectRoot(不含 root 本身) — 返回第一个\n * 含 MUSE.md 或 AGENTS.md 的目录绝对路径。找不到返 null。\n *\n * 不返回 projectRoot 本身:root 的 MUSE.md / AGENTS.md 已在启动时由 loadHierarchy 加载,\n * 不属于\"子目录惰性\"范围。\n */\nexport function findContainingSubdirWithHierarchy(absPath: string, projectRoot: string): string | null {\n const rel = relative(projectRoot, absPath);\n if (!rel || rel.startsWith(\"..\") || isAbsolute(rel)) return null; // 不在 root 下\n\n let cur = dirname(absPath);\n // 边界:cur 必须严格在 projectRoot 内部\n while (cur !== projectRoot && cur.startsWith(projectRoot)) {\n if (existsSync(join(cur, \"MUSE.md\")) || existsSync(join(cur, \"AGENTS.md\"))) {\n return cur;\n }\n const parent = dirname(cur);\n if (parent === cur) break;\n cur = parent;\n }\n return null;\n}\n","/**\n * 统一截断算法。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §5.1。\n *\n * 默认策略:头 70% + 尾 30%,中间替换为 `... [omitted N bytes] ...`。\n * Why 头+尾:bash/grep 关键信息常在两端(开头声明、末尾错误),纯头部截断会丢错误码。\n */\n\nexport interface TruncateConfig {\n /** 字节预算(默认 64 × 1024)。 */\n budgetBytes?: number;\n /** 触发后保留头/尾的字节比例(默认 0.7 / 0.3)。 */\n headTailRatio?: [number, number];\n /** 截断 marker 文本工厂。 */\n marker?: (omitted: number) => string;\n /** 行边界对齐(默认 true,不切坏行)。 */\n alignToLine?: boolean;\n}\n\nexport interface TruncateResult {\n content: string;\n truncated: boolean;\n /** 被丢弃的字节数(按 utf-8 编码计)。 */\n omittedBytes: number;\n}\n\nconst DEFAULT_BUDGET = 64 * 1024;\nconst DEFAULT_RATIO: [number, number] = [0.7, 0.3];\nconst DEFAULT_MARKER = (omitted: number) => `\\n... [omitted ${omitted.toLocaleString()} bytes] ...\\n`;\n\nexport function truncate(content: string, cfg: TruncateConfig = {}): TruncateResult {\n const budget = cfg.budgetBytes ?? DEFAULT_BUDGET;\n const [headRatio, tailRatio] = cfg.headTailRatio ?? DEFAULT_RATIO;\n const marker = cfg.marker ?? DEFAULT_MARKER;\n const alignToLine = cfg.alignToLine ?? true;\n\n const bytes = Buffer.byteLength(content, \"utf-8\");\n if (bytes <= budget) {\n return { content, truncated: false, omittedBytes: 0 };\n }\n\n const markerStr = marker(bytes - budget);\n const markerBytes = Buffer.byteLength(markerStr, \"utf-8\");\n const available = Math.max(1024, budget - markerBytes);\n const headBudget = Math.floor(available * headRatio);\n const tailBudget = available - headBudget;\n\n let head = takePrefix(content, headBudget);\n let tail = takeSuffix(content, tailBudget);\n\n if (alignToLine) {\n const lastNL = head.lastIndexOf(\"\\n\");\n if (lastNL > headBudget * 0.5) head = head.slice(0, lastNL + 1);\n const firstNL = tail.indexOf(\"\\n\");\n if (firstNL >= 0 && firstNL < tail.length * 0.5) tail = tail.slice(firstNL);\n }\n\n const omitted = bytes - Buffer.byteLength(head, \"utf-8\") - Buffer.byteLength(tail, \"utf-8\");\n return {\n content: head + marker(Math.max(omitted, 0)) + tail,\n truncated: true,\n omittedBytes: Math.max(omitted, 0),\n };\n}\n\n/** 按字节预算从前往后取,不切坏 utf-8 多字节字符。 */\nfunction takePrefix(s: string, bytes: number): string {\n if (bytes <= 0) return \"\";\n const buf = Buffer.from(s, \"utf-8\");\n if (buf.byteLength <= bytes) return s;\n // 找一个不切坏 utf-8 的边界:回退到上一字符\n let cut = bytes;\n while (cut > 0 && (buf[cut] & 0xc0) === 0x80) cut--;\n return buf.subarray(0, cut).toString(\"utf-8\");\n}\n\n/** 按字节预算从后往前取。 */\nfunction takeSuffix(s: string, bytes: number): string {\n if (bytes <= 0) return \"\";\n const buf = Buffer.from(s, \"utf-8\");\n if (buf.byteLength <= bytes) return s;\n let cut = buf.byteLength - bytes;\n while (cut < buf.byteLength && (buf[cut] & 0xc0) === 0x80) cut++;\n return buf.subarray(cut).toString(\"utf-8\");\n}\n","const ANSI_BACKGROUND_OFFSET = 10;\n\nconst wrapAnsi16 = (offset = 0) => code => `\\u001B[${code + offset}m`;\n\nconst wrapAnsi256 = (offset = 0) => code => `\\u001B[${38 + offset};5;${code}m`;\n\nconst wrapAnsi16m = (offset = 0) => (red, green, blue) => `\\u001B[${38 + offset};2;${red};${green};${blue}m`;\n\nconst styles = {\n\tmodifier: {\n\t\treset: [0, 0],\n\t\t// 21 isn't widely supported and 22 does the same thing\n\t\tbold: [1, 22],\n\t\tdim: [2, 22],\n\t\titalic: [3, 23],\n\t\tunderline: [4, 24],\n\t\toverline: [53, 55],\n\t\tinverse: [7, 27],\n\t\thidden: [8, 28],\n\t\tstrikethrough: [9, 29],\n\t},\n\tcolor: {\n\t\tblack: [30, 39],\n\t\tred: [31, 39],\n\t\tgreen: [32, 39],\n\t\tyellow: [33, 39],\n\t\tblue: [34, 39],\n\t\tmagenta: [35, 39],\n\t\tcyan: [36, 39],\n\t\twhite: [37, 39],\n\n\t\t// Bright color\n\t\tblackBright: [90, 39],\n\t\tgray: [90, 39], // Alias of `blackBright`\n\t\tgrey: [90, 39], // Alias of `blackBright`\n\t\tredBright: [91, 39],\n\t\tgreenBright: [92, 39],\n\t\tyellowBright: [93, 39],\n\t\tblueBright: [94, 39],\n\t\tmagentaBright: [95, 39],\n\t\tcyanBright: [96, 39],\n\t\twhiteBright: [97, 39],\n\t},\n\tbgColor: {\n\t\tbgBlack: [40, 49],\n\t\tbgRed: [41, 49],\n\t\tbgGreen: [42, 49],\n\t\tbgYellow: [43, 49],\n\t\tbgBlue: [44, 49],\n\t\tbgMagenta: [45, 49],\n\t\tbgCyan: [46, 49],\n\t\tbgWhite: [47, 49],\n\n\t\t// Bright color\n\t\tbgBlackBright: [100, 49],\n\t\tbgGray: [100, 49], // Alias of `bgBlackBright`\n\t\tbgGrey: [100, 49], // Alias of `bgBlackBright`\n\t\tbgRedBright: [101, 49],\n\t\tbgGreenBright: [102, 49],\n\t\tbgYellowBright: [103, 49],\n\t\tbgBlueBright: [104, 49],\n\t\tbgMagentaBright: [105, 49],\n\t\tbgCyanBright: [106, 49],\n\t\tbgWhiteBright: [107, 49],\n\t},\n};\n\nexport const modifierNames = Object.keys(styles.modifier);\nexport const foregroundColorNames = Object.keys(styles.color);\nexport const backgroundColorNames = Object.keys(styles.bgColor);\nexport const colorNames = [...foregroundColorNames, ...backgroundColorNames];\n\nfunction assembleStyles() {\n\tconst codes = new Map();\n\n\tfor (const [groupName, group] of Object.entries(styles)) {\n\t\tfor (const [styleName, style] of Object.entries(group)) {\n\t\t\tstyles[styleName] = {\n\t\t\t\topen: `\\u001B[${style[0]}m`,\n\t\t\t\tclose: `\\u001B[${style[1]}m`,\n\t\t\t};\n\n\t\t\tgroup[styleName] = styles[styleName];\n\n\t\t\tcodes.set(style[0], style[1]);\n\t\t}\n\n\t\tObject.defineProperty(styles, groupName, {\n\t\t\tvalue: group,\n\t\t\tenumerable: false,\n\t\t});\n\t}\n\n\tObject.defineProperty(styles, 'codes', {\n\t\tvalue: codes,\n\t\tenumerable: false,\n\t});\n\n\tstyles.color.close = '\\u001B[39m';\n\tstyles.bgColor.close = '\\u001B[49m';\n\n\tstyles.color.ansi = wrapAnsi16();\n\tstyles.color.ansi256 = wrapAnsi256();\n\tstyles.color.ansi16m = wrapAnsi16m();\n\tstyles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);\n\n\t// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js\n\tObject.defineProperties(styles, {\n\t\trgbToAnsi256: {\n\t\t\tvalue(red, green, blue) {\n\t\t\t\t// We use the extended greyscale palette here, with the exception of\n\t\t\t\t// black and white. normal palette only has 4 greyscale shades.\n\t\t\t\tif (red === green && green === blue) {\n\t\t\t\t\tif (red < 8) {\n\t\t\t\t\t\treturn 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (red > 248) {\n\t\t\t\t\t\treturn 231;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Math.round(((red - 8) / 247) * 24) + 232;\n\t\t\t\t}\n\n\t\t\t\treturn 16\n\t\t\t\t\t+ (36 * Math.round(red / 255 * 5))\n\t\t\t\t\t+ (6 * Math.round(green / 255 * 5))\n\t\t\t\t\t+ Math.round(blue / 255 * 5);\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToRgb: {\n\t\t\tvalue(hex) {\n\t\t\t\tconst matches = /[a-f\\d]{6}|[a-f\\d]{3}/i.exec(hex.toString(16));\n\t\t\t\tif (!matches) {\n\t\t\t\t\treturn [0, 0, 0];\n\t\t\t\t}\n\n\t\t\t\tlet [colorString] = matches;\n\n\t\t\t\tif (colorString.length === 3) {\n\t\t\t\t\tcolorString = [...colorString].map(character => character + character).join('');\n\t\t\t\t}\n\n\t\t\t\tconst integer = Number.parseInt(colorString, 16);\n\n\t\t\t\treturn [\n\t\t\t\t\t/* eslint-disable no-bitwise */\n\t\t\t\t\t(integer >> 16) & 0xFF,\n\t\t\t\t\t(integer >> 8) & 0xFF,\n\t\t\t\t\tinteger & 0xFF,\n\t\t\t\t\t/* eslint-enable no-bitwise */\n\t\t\t\t];\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi256: {\n\t\t\tvalue: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t\tansi256ToAnsi: {\n\t\t\tvalue(code) {\n\t\t\t\tif (code < 8) {\n\t\t\t\t\treturn 30 + code;\n\t\t\t\t}\n\n\t\t\t\tif (code < 16) {\n\t\t\t\t\treturn 90 + (code - 8);\n\t\t\t\t}\n\n\t\t\t\tlet red;\n\t\t\t\tlet green;\n\t\t\t\tlet blue;\n\n\t\t\t\tif (code >= 232) {\n\t\t\t\t\tred = (((code - 232) * 10) + 8) / 255;\n\t\t\t\t\tgreen = red;\n\t\t\t\t\tblue = red;\n\t\t\t\t} else {\n\t\t\t\t\tcode -= 16;\n\n\t\t\t\t\tconst remainder = code % 36;\n\n\t\t\t\t\tred = Math.floor(code / 36) / 5;\n\t\t\t\t\tgreen = Math.floor(remainder / 6) / 5;\n\t\t\t\t\tblue = (remainder % 6) / 5;\n\t\t\t\t}\n\n\t\t\t\tconst value = Math.max(red, green, blue) * 2;\n\n\t\t\t\tif (value === 0) {\n\t\t\t\t\treturn 30;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tlet result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));\n\n\t\t\t\tif (value === 2) {\n\t\t\t\t\tresult += 60;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\trgbToAnsi: {\n\t\t\tvalue: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi: {\n\t\t\tvalue: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t});\n\n\treturn styles;\n}\n\nconst ansiStyles = assembleStyles();\n\nexport default ansiStyles;\n","import process from 'node:process';\nimport os from 'node:os';\nimport tty from 'node:tty';\n\n// From: https://github.com/sindresorhus/has-flag/blob/main/index.js\n/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {\nfunction hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) {\n\tconst prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');\n\tconst position = argv.indexOf(prefix + flag);\n\tconst terminatorPosition = argv.indexOf('--');\n\treturn position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);\n}\n\nconst {env} = process;\n\nlet flagForceColor;\nif (\n\thasFlag('no-color')\n\t|| hasFlag('no-colors')\n\t|| hasFlag('color=false')\n\t|| hasFlag('color=never')\n) {\n\tflagForceColor = 0;\n} else if (\n\thasFlag('color')\n\t|| hasFlag('colors')\n\t|| hasFlag('color=true')\n\t|| hasFlag('color=always')\n) {\n\tflagForceColor = 1;\n}\n\nfunction envForceColor() {\n\tif ('FORCE_COLOR' in env) {\n\t\tif (env.FORCE_COLOR === 'true') {\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (env.FORCE_COLOR === 'false') {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);\n\t}\n}\n\nfunction translateLevel(level) {\n\tif (level === 0) {\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tlevel,\n\t\thasBasic: true,\n\t\thas256: level >= 2,\n\t\thas16m: level >= 3,\n\t};\n}\n\nfunction _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {\n\tconst noFlagForceColor = envForceColor();\n\tif (noFlagForceColor !== undefined) {\n\t\tflagForceColor = noFlagForceColor;\n\t}\n\n\tconst forceColor = sniffFlags ? flagForceColor : noFlagForceColor;\n\n\tif (forceColor === 0) {\n\t\treturn 0;\n\t}\n\n\tif (sniffFlags) {\n\t\tif (hasFlag('color=16m')\n\t\t\t|| hasFlag('color=full')\n\t\t\t|| hasFlag('color=truecolor')) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (hasFlag('color=256')) {\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\t// Check for Azure DevOps pipelines.\n\t// Has to be above the `!streamIsTTY` check.\n\tif ('TF_BUILD' in env && 'AGENT_NAME' in env) {\n\t\treturn 1;\n\t}\n\n\tif (haveStream && !streamIsTTY && forceColor === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst min = forceColor || 0;\n\n\tif (env.TERM === 'dumb') {\n\t\treturn min;\n\t}\n\n\tif (process.platform === 'win32') {\n\t\t// Windows 10 build 10586 is the first Windows release that supports 256 colors.\n\t\t// Windows 10 build 14931 is the first release that supports 16m/TrueColor.\n\t\tconst osRelease = os.release().split('.');\n\t\tif (\n\t\t\tNumber(osRelease[0]) >= 10\n\t\t\t&& Number(osRelease[2]) >= 10_586\n\t\t) {\n\t\t\treturn Number(osRelease[2]) >= 14_931 ? 3 : 2;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tif ('CI' in env) {\n\t\tif (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn min;\n\t}\n\n\tif ('TEAMCITY_VERSION' in env) {\n\t\treturn /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;\n\t}\n\n\tif (env.COLORTERM === 'truecolor') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-kitty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-ghostty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'wezterm') {\n\t\treturn 3;\n\t}\n\n\tif ('TERM_PROGRAM' in env) {\n\t\tconst version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n\t\tswitch (env.TERM_PROGRAM) {\n\t\t\tcase 'iTerm.app': {\n\t\t\t\treturn version >= 3 ? 3 : 2;\n\t\t\t}\n\n\t\t\tcase 'Apple_Terminal': {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tif (/-256(color)?$/i.test(env.TERM)) {\n\t\treturn 2;\n\t}\n\n\tif (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n\t\treturn 1;\n\t}\n\n\tif ('COLORTERM' in env) {\n\t\treturn 1;\n\t}\n\n\treturn min;\n}\n\nexport function createSupportsColor(stream, options = {}) {\n\tconst level = _supportsColor(stream, {\n\t\tstreamIsTTY: stream && stream.isTTY,\n\t\t...options,\n\t});\n\n\treturn translateLevel(level);\n}\n\nconst supportsColor = {\n\tstdout: createSupportsColor({isTTY: tty.isatty(1)}),\n\tstderr: createSupportsColor({isTTY: tty.isatty(2)}),\n};\n\nexport default supportsColor;\n","// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.\nexport function stringReplaceAll(string, substring, replacer) {\n\tlet index = string.indexOf(substring);\n\tif (index === -1) {\n\t\treturn string;\n\t}\n\n\tconst substringLength = substring.length;\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\treturnValue += string.slice(endIndex, index) + substring + replacer;\n\t\tendIndex = index + substringLength;\n\t\tindex = string.indexOf(substring, endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n\nexport function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\tconst gotCR = string[index - 1] === '\\r';\n\t\treturnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\\r\\n' : '\\n') + postfix;\n\t\tendIndex = index + 1;\n\t\tindex = string.indexOf('\\n', endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n","import ansiStyles from '#ansi-styles';\nimport supportsColor from '#supports-color';\nimport { // eslint-disable-line import/order\n\tstringReplaceAll,\n\tstringEncaseCRLFWithFirstIndex,\n} from './utilities.js';\n\nconst {stdout: stdoutColor, stderr: stderrColor} = supportsColor;\n\nconst GENERATOR = Symbol('GENERATOR');\nconst STYLER = Symbol('STYLER');\nconst IS_EMPTY = Symbol('IS_EMPTY');\n\n// `supportsColor.level` → `ansiStyles.color[name]` mapping\nconst levelMapping = [\n\t'ansi',\n\t'ansi',\n\t'ansi256',\n\t'ansi16m',\n];\n\nconst styles = Object.create(null);\n\nconst applyOptions = (object, options = {}) => {\n\tif (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {\n\t\tthrow new Error('The `level` option should be an integer from 0 to 3');\n\t}\n\n\t// Detect level if not set manually\n\tconst colorLevel = stdoutColor ? stdoutColor.level : 0;\n\tobject.level = options.level === undefined ? colorLevel : options.level;\n};\n\nexport class Chalk {\n\tconstructor(options) {\n\t\t// eslint-disable-next-line no-constructor-return\n\t\treturn chalkFactory(options);\n\t}\n}\n\nconst chalkFactory = options => {\n\tconst chalk = (...strings) => strings.join(' ');\n\tapplyOptions(chalk, options);\n\n\tObject.setPrototypeOf(chalk, createChalk.prototype);\n\n\treturn chalk;\n};\n\nfunction createChalk(options) {\n\treturn chalkFactory(options);\n}\n\nObject.setPrototypeOf(createChalk.prototype, Function.prototype);\n\nfor (const [styleName, style] of Object.entries(ansiStyles)) {\n\tstyles[styleName] = {\n\t\tget() {\n\t\t\tconst builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);\n\t\t\tObject.defineProperty(this, styleName, {value: builder});\n\t\t\treturn builder;\n\t\t},\n\t};\n}\n\nstyles.visible = {\n\tget() {\n\t\tconst builder = createBuilder(this, this[STYLER], true);\n\t\tObject.defineProperty(this, 'visible', {value: builder});\n\t\treturn builder;\n\t},\n};\n\nconst getModelAnsi = (model, level, type, ...arguments_) => {\n\tif (model === 'rgb') {\n\t\tif (level === 'ansi16m') {\n\t\t\treturn ansiStyles[type].ansi16m(...arguments_);\n\t\t}\n\n\t\tif (level === 'ansi256') {\n\t\t\treturn ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));\n\t\t}\n\n\t\treturn ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));\n\t}\n\n\tif (model === 'hex') {\n\t\treturn getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));\n\t}\n\n\treturn ansiStyles[type][model](...arguments_);\n};\n\nconst usedModels = ['rgb', 'hex', 'ansi256'];\n\nfor (const model of usedModels) {\n\tstyles[model] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n\n\tconst bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);\n\tstyles[bgModel] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n}\n\nconst proto = Object.defineProperties(() => {}, {\n\t...styles,\n\tlevel: {\n\t\tenumerable: true,\n\t\tget() {\n\t\t\treturn this[GENERATOR].level;\n\t\t},\n\t\tset(level) {\n\t\t\tthis[GENERATOR].level = level;\n\t\t},\n\t},\n});\n\nconst createStyler = (open, close, parent) => {\n\tlet openAll;\n\tlet closeAll;\n\tif (parent === undefined) {\n\t\topenAll = open;\n\t\tcloseAll = close;\n\t} else {\n\t\topenAll = parent.openAll + open;\n\t\tcloseAll = close + parent.closeAll;\n\t}\n\n\treturn {\n\t\topen,\n\t\tclose,\n\t\topenAll,\n\t\tcloseAll,\n\t\tparent,\n\t};\n};\n\nconst createBuilder = (self, _styler, _isEmpty) => {\n\t// Single argument is hot path, implicit coercion is faster than anything\n\t// eslint-disable-next-line no-implicit-coercion\n\tconst builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));\n\n\t// We alter the prototype because we must return a function, but there is\n\t// no way to create a function with a different prototype\n\tObject.setPrototypeOf(builder, proto);\n\n\tbuilder[GENERATOR] = self;\n\tbuilder[STYLER] = _styler;\n\tbuilder[IS_EMPTY] = _isEmpty;\n\n\treturn builder;\n};\n\nconst applyStyle = (self, string) => {\n\tif (self.level <= 0 || !string) {\n\t\treturn self[IS_EMPTY] ? '' : string;\n\t}\n\n\tlet styler = self[STYLER];\n\n\tif (styler === undefined) {\n\t\treturn string;\n\t}\n\n\tconst {openAll, closeAll} = styler;\n\tif (string.includes('\\u001B')) {\n\t\twhile (styler !== undefined) {\n\t\t\t// Replace any instances already present with a re-opening code\n\t\t\t// otherwise only the part of the string until said closing code\n\t\t\t// will be colored, and the rest will simply be 'plain'.\n\t\t\tstring = stringReplaceAll(string, styler.close, styler.open);\n\n\t\t\tstyler = styler.parent;\n\t\t}\n\t}\n\n\t// We can move both next actions out of loop, because remaining actions in loop won't have\n\t// any/visible effect on parts we add here. Close the styling before a linebreak and reopen\n\t// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92\n\tconst lfIndex = string.indexOf('\\n');\n\tif (lfIndex !== -1) {\n\t\tstring = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);\n\t}\n\n\treturn openAll + string + closeAll;\n};\n\nObject.defineProperties(createChalk.prototype, styles);\n\nconst chalk = createChalk();\nexport const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});\n\nexport {\n\tmodifierNames,\n\tforegroundColorNames,\n\tbackgroundColorNames,\n\tcolorNames,\n\n\t// TODO: Remove these aliases in the next major version\n\tmodifierNames as modifiers,\n\tforegroundColorNames as foregroundColors,\n\tbackgroundColorNames as backgroundColors,\n\tcolorNames as colors,\n} from './vendor/ansi-styles/index.js';\n\nexport {\n\tstdoutColor as supportsColor,\n\tstderrColor as supportsColorStderr,\n};\n\nexport default chalk;\n","/**\n * Assistant / user 消息的 markdown → ANSI 渲染入口。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.4。\n *\n * 之前散在 `src/components/MessageView.tsx` 内的 marked 初始化与 renderMarkdown\n * 函数集中到这里,作为 RenderPipeline 模块的对外 helper。UI 只 import 这一个入口。\n *\n * marked-terminal 7.x 默认配置 `showSectionPrefix: true`,会在 heading 文本前\n * 显式拼回 `## `,渲染出 `[bold green]## 标题[/]` 的效果 — 即使 heading 颜色生效,\n * 用户视觉上也会看到原始的 `## ` 标记。这里强制关掉。\n */\n\nimport chalk from \"chalk\";\nimport { marked } from \"marked\";\n// @ts-expect-error marked-terminal 7.x 无内置 .d.ts;运行时正常\nimport { markedTerminal } from \"marked-terminal\";\n\n// chalk 在 module load 时可能基于 stdout 探测把 level 锁成 0(非 TTY、CI 等场景),\n// 这会让 markedTerminal 的 chalk.bold/italic 全部返回纯文本。Ink 渲染到的目标是 TTY,\n// 强制至少 256 色,让 ANSI 码进得了 Text 节点。\nif (chalk.level === 0) chalk.level = 3;\n\nlet registered = false;\nfunction ensureRegistered(): void {\n if (registered) return;\n marked.use(\n markedTerminal({\n // 关键:不要在 heading 文本前拼回 `## `。\n showSectionPrefix: false,\n // 默认 4 空格缩进 list / blockquote,看起来过深 — 跟 Codex 风格对齐:\n // 圆点 + 空格作左边界,续行起点 = 首行文字起点,list 不再额外缩进 4 空格,\n // 用 2 空格只够区分嵌套层级。\n tab: \" \",\n }) as Parameters<typeof marked.use>[0],\n );\n registered = true;\n}\n\n/** Markdown → ANSI 字符串。流到一半的 ```code 等会让 parse 抛错,退化到纯文本。 */\nexport function renderMarkdown(text: string): string {\n ensureRegistered();\n try {\n let out = marked.parse(text) as string;\n out = out.replace(/\\n+$/, \"\"); // 末尾换行去掉,免得 Ink Box 多一行空白\n\n // 修 marked-terminal 在 list item 等场景里把 **bold** / *italic* 当文本吐出来:\n // 自己用正则补一刀(在 reset 处理之前做,否则 \\x1b[0m 会把 \\x1b[1m 切断)\n out = out.replace(/\\*\\*([^\\n*]+?)\\*\\*/g, (_, body) => `\\x1b[1m${body}\\x1b[22m`);\n out = out.replace(/(?<![*\\\\\\x1b])\\*([^\\n*]+?)\\*(?!\\*)/g, (_, body) => `\\x1b[3m${body}\\x1b[23m`);\n\n // marked-terminal 在每个 block 前后塞 \\x1b[0m 全 reset——这会把外层的\n // chalk.bgHex(用户消息条带)一并清掉,渲染出\"字体处没背景\"的断带。\n // 整体剥掉,让样式 close 各自的 \\x1b[22m / \\x1b[23m / \\x1b[39m 收尾即可。\n out = out.replace(/\\x1b\\[0m/g, \"\");\n\n // 兜底:LLM 自己写的 markdown 可能用 4-空格缩进表达\"代码块\"/\"突出段落\",\n // 即使 marked 不把它解析为 code(语义边界没满足),前导空白仍残留。\n // 把每行前导空白以 4 为单位减半成 2,既保留嵌套层级,又防\"过深\"。\n out = out.replace(/^( {4,})/gm, (m) => \" \".repeat(Math.floor(m.length / 2)));\n\n return out;\n } catch {\n return text;\n }\n}\n","/**\n * ResultPipeline 上下文。\n *\n * 设计文档:模块设计/消息预处理工程/设计.md §4.3.1。\n */\n\nimport type { ToolExecuteResult } from \"../../tools/types.js\";\n\nexport type NormalizedErrorKind = \"permission\" | \"timeout\" | \"not_found\" | \"network\" | \"binary\" | \"unknown\";\n\nexport interface NormalizedError {\n kind: NormalizedErrorKind;\n message: string;\n raw?: string;\n}\n\nexport interface ResultPreprocessSettings {\n truncate?: {\n /** 字节预算(默认 64KB)。 */\n budgetBytes?: number;\n };\n detectBinary?: {\n enabled?: boolean;\n };\n summarize?: {\n enabled?: boolean;\n };\n normalizeError?: {\n enabled?: boolean;\n };\n redact?: {\n /** 默认 true。 */\n enabled?: boolean;\n };\n /** inject-diff:把 diff 拼到 LLM 看见的 content 末尾(默认 false)。 */\n injectDiff?: boolean;\n}\n\nexport interface ResultCtx {\n /** 工具名(用于 stage skip 判断与 hook matcher)。 */\n toolName: string;\n /** 工具调用 ID,与 tool_use 配对。 */\n toolUseId: string;\n /** 工具调用参数(只读;用于 summarize 等 stage 判断)。 */\n args: unknown;\n /** 工具返回的原始结构。 */\n raw: ToolExecuteResult;\n /** stage 累积修改的 content(回灌给 LLM 的最终文本)。 */\n content: string;\n /** stage 累积修改的 summary(顶部一行展示)。 */\n summary?: string;\n /** stage 累积修改的 diff(只用于 UI,不进 LLM)。 */\n diff?: string;\n /** 检测到的二进制告警。 */\n binaryDetected?: { reason: string; bytes: number };\n /** stage 标的错误归一化结果。 */\n normalizedError?: NormalizedError;\n /** 截断信息(给 UI / 日志参考)。 */\n truncated?: { omittedBytes: number };\n /** stage 标的告警。 */\n warnings: Array<{ stage: string; message: string }>;\n settings: ResultPreprocessSettings;\n}\n\nexport function createResultCtx(init: {\n toolName: string;\n toolUseId: string;\n args: unknown;\n raw: ToolExecuteResult;\n settings?: ResultPreprocessSettings;\n}): ResultCtx {\n return {\n toolName: init.toolName,\n toolUseId: init.toolUseId,\n args: init.args,\n raw: init.raw,\n content: init.raw.content,\n summary: init.raw.summary,\n diff: init.raw.diff,\n warnings: [],\n settings: init.settings ?? {},\n };\n}\n","/**\n * 配置加载:\n * 1. 内置默认值\n * 2. ~/.muse/settings.json\n * 3. <cwd>/.muse/settings.json\n * 4. <cwd>/.muse/settings.local.json\n * 5. 环境变量 (MUSE_*)\n * 6. CLI flags (在 cli.tsx 里覆盖)\n *\n * ${ENV_VAR} 占位符在加载后展开。\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport type { z } from \"zod\";\nimport { SettingsSchema, type Settings } from \"./types.js\";\nimport { expandEnvVars } from \"./_env.js\";\nimport { log } from \"../log/index.js\";\n\nfunction formatZodIssues(issues: z.ZodIssue[]): string {\n return issues\n .map((i) => `${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\n .join(\"; \");\n}\n\nconst DEFAULTS: Settings = {\n llm: {\n provider: \"deepseek\",\n model: \"deepseek-chat\",\n },\n providers: {\n deepseek: { apiKey: \"${DEEPSEEK_API_KEY}\" },\n openai: { apiKey: \"${OPENAI_API_KEY}\" },\n qwen: { apiKey: \"${DASHSCOPE_API_KEY}\" },\n moonshot: { apiKey: \"${MOONSHOT_API_KEY}\" },\n zhipu: { apiKey: \"${ZHIPU_API_KEY}\" },\n openrouter: { apiKey: \"${OPENROUTER_API_KEY}\" },\n ollama: { baseUrl: \"http://localhost:11434/v1\" },\n },\n permissions: {\n allow: [\"Read\", \"Grep\", \"Glob\", \"TodoWrite\"],\n ask: [\"Write\", \"Edit\", \"Bash\"],\n deny: [],\n defaultMode: \"ask\",\n },\n ui: {\n showBanner: true,\n lang: \"en\",\n },\n};\n\nasync function readJsonIfExists(path: string): Promise<unknown | undefined> {\n if (!existsSync(path)) return undefined;\n try {\n const raw = await readFile(path, \"utf-8\");\n return JSON.parse(raw);\n } catch (err) {\n log.warn(`Failed to parse settings at ${path}: ${err instanceof Error ? err.message : String(err)}`);\n return undefined;\n }\n}\n\n/** 深合并:高优先级覆盖低优先级。对象递归,数组/标量覆盖。 */\nfunction deepMerge<T>(low: T, high: Partial<T>): T {\n if (high == null) return low;\n if (typeof low !== \"object\" || typeof high !== \"object\" || low === null || high === null) {\n return high as T;\n }\n if (Array.isArray(high)) return high as unknown as T;\n const result: Record<string, unknown> = { ...(low as Record<string, unknown>) };\n for (const [k, v] of Object.entries(high)) {\n const existing = (low as Record<string, unknown>)[k];\n if (\n v !== null &&\n typeof v === \"object\" &&\n !Array.isArray(v) &&\n existing !== null &&\n typeof existing === \"object\" &&\n !Array.isArray(existing)\n ) {\n result[k] = deepMerge(existing, v as Record<string, unknown>);\n } else {\n result[k] = v;\n }\n }\n return result as T;\n}\n\nexport interface LoadedSettings {\n settings: Settings;\n sources: string[];\n}\n\nexport async function loadSettings(cwd: string = process.cwd()): Promise<LoadedSettings> {\n const sources: string[] = [\"<defaults>\"];\n let merged: Settings = DEFAULTS;\n\n const candidates = [\n join(homedir(), \".muse\", \"settings.json\"),\n join(cwd, \".muse\", \"settings.json\"),\n join(cwd, \".muse\", \"settings.local.json\"),\n ];\n\n for (const path of candidates) {\n const raw = await readJsonIfExists(path);\n if (raw != null) {\n const parsed = SettingsSchema.safeParse(raw);\n if (parsed.success) {\n merged = deepMerge(merged, parsed.data);\n sources.push(path);\n } else {\n log.warn(`Invalid settings at ${path}: ${formatZodIssues(parsed.error.issues)}`);\n }\n }\n }\n\n // Env overrides for the active LLM\n if (process.env.MUSE_PROVIDER && merged.llm) {\n merged = { ...merged, llm: { ...merged.llm, provider: process.env.MUSE_PROVIDER } };\n sources.push(\"env:MUSE_PROVIDER\");\n }\n if (process.env.MUSE_MODEL && merged.llm) {\n merged = { ...merged, llm: { ...merged.llm, model: process.env.MUSE_MODEL } };\n sources.push(\"env:MUSE_MODEL\");\n }\n\n // 展开 ${ENV_VAR} 占位符\n merged = expandEnvVars(merged) as Settings;\n\n // settings.env 注入 process.env(对齐业界 CLI Agent 形态)。\n // 已存在的环境变量不覆盖 — shell / CLI 显式设置优先级最高。\n if (merged.env) {\n for (const [key, value] of Object.entries(merged.env)) {\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n }\n\n return { settings: merged, sources };\n}\n\nexport { DEFAULTS };\nexport { resolve as resolvePath };\n","/**\n * 配置 schema。对应 ~/.muse/settings.json + .muse/settings.json 的内容。\n */\n\nimport { z } from \"zod\";\n\nexport const ProviderConfigSchema = z.object({\n apiKey: z.string().optional(),\n baseUrl: z.string().optional(),\n extraHeaders: z.record(z.string()).optional(),\n}).passthrough();\n\n// 新设计:model id 由 ~/.muse/models.local.json 提供,settings.json 只保留 active 选择。\n// provider 字段仅用于\"无 models.local.json 时的 fallback 路径\"(设计文档 §8 兼容层)。\n// 因此两者都可选——/model 切换只写 model,不写 provider。\nexport const LLMConfigSchema = z.object({\n provider: z.string().optional().describe(\"Fallback provider preset (only used when no models.local.json entry matches).\"),\n model: z.string().optional().describe(\"Active model id; should match an id in models.local.json.\"),\n temperature: z.number().min(0).max(2).optional(),\n maxTokens: z.number().int().positive().optional(),\n});\n\nexport const PermissionsSchema = z.object({\n allow: z.array(z.string()).optional(),\n ask: z.array(z.string()).optional(),\n deny: z.array(z.string()).optional(),\n defaultMode: z.enum([\"strict\", \"relaxed\", \"ask\"]).optional(),\n});\n\nexport const UISchema = z.object({\n theme: z.enum([\"dark\", \"light\"]).optional(),\n lang: z.enum([\"en\", \"zh-CN\"]).optional(),\n showBanner: z.boolean().optional(),\n});\n\n// 消息预处理工程(模块设计/消息预处理工程/设计.md §6.2)。\n// MVP:settings 暴露 4 段管线开关 + 部分参数;hooks 只在 PreToolUse / PostToolUse 触发,\n// 其余点位 schema 保留但不接代码。\n\nexport const HookSpecSchema = z.object({\n matcher: z.string().optional(),\n command: z.string(),\n timeout: z.number().int().positive().optional(),\n onError: z.enum([\"skip\", \"throw\"]).optional(),\n});\n\nexport const HooksConfigSchema = z.object({\n SessionStart: z.array(HookSpecSchema).optional(),\n SessionEnd: z.array(HookSpecSchema).optional(),\n UserPromptSubmit: z.array(HookSpecSchema).optional(),\n PreLLMRequest: z.array(HookSpecSchema).optional(),\n PostLLMResponse: z.array(HookSpecSchema).optional(),\n PreToolUse: z.array(HookSpecSchema).optional(),\n PostToolUse: z.array(HookSpecSchema).optional(),\n PreCompact: z.array(HookSpecSchema).optional(),\n PostCompact: z.array(HookSpecSchema).optional(),\n MemoryPromote: z.array(HookSpecSchema).optional(),\n}).passthrough();\n\nexport const InputPreprocessSettingsSchema = z.object({\n atFileExpand: z.object({\n enabled: z.boolean().optional(),\n maxBytes: z.number().int().positive().optional(),\n }).optional(),\n templateExpand: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n maxChars: z.number().int().positive().optional(),\n redactPreScan: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n}).passthrough();\n\nexport const RequestPreprocessSettingsSchema = z.object({\n trimHistory: z.object({\n enabled: z.boolean().optional(),\n budgetRatio: z.number().min(0).max(1).optional(),\n }).optional(),\n budgetGuard: z.object({\n enabled: z.boolean().optional(),\n budgetRatio: z.number().min(0).max(1).optional(),\n }).optional(),\n redact: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n}).passthrough();\n\nexport const ResultPreprocessSettingsSchema = z.object({\n truncate: z.object({\n budgetBytes: z.number().int().positive().optional(),\n }).optional(),\n detectBinary: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n summarize: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n normalizeError: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n redact: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n injectDiff: z.boolean().optional(),\n}).passthrough();\n\nexport const RenderPreprocessSettingsSchema = z.object({\n streamMarkdown: z.object({\n enabled: z.boolean().optional(),\n }).optional(),\n collapseLong: z.object({\n enabled: z.boolean().optional(),\n threshold: z.number().int().positive().optional(),\n }).optional(),\n}).passthrough();\n\nexport const PreprocessSettingsSchema = z.object({\n input: InputPreprocessSettingsSchema.optional(),\n request: RequestPreprocessSettingsSchema.optional(),\n result: ResultPreprocessSettingsSchema.optional(),\n render: RenderPreprocessSettingsSchema.optional(),\n /** 全局禁用的 stage name 列表(kebab-case)。 */\n disable: z.array(z.string()).optional(),\n}).passthrough();\n\nexport const SettingsSchema = z.object({\n llm: LLMConfigSchema.optional(),\n providers: z.record(ProviderConfigSchema).optional(),\n permissions: PermissionsSchema.optional(),\n ui: UISchema.optional(),\n mcpServers: z.record(z.unknown()).optional(),\n skills: z.object({\n enabled: z.boolean().optional(),\n disabled: z.array(z.string()).optional(),\n }).optional(),\n hooks: HooksConfigSchema.optional(),\n preprocess: PreprocessSettingsSchema.optional(),\n /**\n * 启动时注入到 process.env 的额外环境变量(对齐业界 CLI Agent 的 settings.env 模式)。\n * 值必须是字符串(JSON 无 number→env 的隐式转换;约束传 \"1\" / \"0\" 这种字面值)。\n *\n * 当前支持的 muse 自识别变量:\n * MUSE_DISABLE_CURSOR_BLINK=1 关闭输入框光标闪烁(默认闪烁)\n * 其他 muse 模块可自行约定 MUSE_* 名字读取。\n *\n * 注意:这里写入的变量会进入 process.env,**但 Hook 子进程仍走环境变量白名单**\n * (见 src/preprocess/hooks.ts),不会自动透传给 hook 命令,避免泄露密钥。\n */\n env: z.record(z.string()).optional(),\n /** Memory 模块设置(II-5 向量索引)。 */\n memory: z.object({\n embedding: z.object({\n /** 启用 embedding 召回(默认 false;关闭时 inject-memory 走传统全文)。 */\n enabled: z.boolean().optional(),\n /** 后端 provider。默认 hash-bag(零依赖);设了 preset 自动走 openai-compatible。 */\n provider: z.enum([\"hash-bag\", \"openai-compatible\", \"openai\", \"local-minilm\"]).optional(),\n /** Preset 名(dashscope-v3 / openai-3-small / openai-3-large / zhipu-3 / ollama-nomic / ollama-bge-m3)。 */\n preset: z.string().optional(),\n /** Base URL(覆盖 preset 默认或自定义 provider 时填)。 */\n baseUrl: z.string().optional(),\n /** 模型名(覆盖 preset 默认或自定义 provider 时填)。 */\n model: z.string().optional(),\n /** 向量维度(用户根据模型官方说明调整;preset 给推荐默认,可覆盖)。\n * 设了此字段 → HTTP 请求带 dimensions 参数(MRL truncation);\n * 没设 → 走模型默认。\n * 启动期 muse 会 probe 一次校验实际维度,不匹配则降级 hash-bag + 提示修正。 */\n dim: z.number().int().positive().optional(),\n /** API key(${ENV_VAR} 或明文;Ollama 等本地端点可省)。 */\n apiKey: z.string().optional(),\n /** 检索 top-K(默认 5)。 */\n topK: z.number().int().positive().optional(),\n /** memory 数量低于此值时退化到全注入(默认 3,2026-06-07 R5 修订)。 */\n minMemoryCount: z.number().int().nonnegative().optional(),\n /** 注入 token 预算上限,超出按 trust 优先保留(默认 1500)。 */\n maxInjectTokens: z.number().int().positive().optional(),\n }).optional(),\n }).optional(),\n}).passthrough();\n\nexport type Settings = z.infer<typeof SettingsSchema>;\nexport type LLMConfig = z.infer<typeof LLMConfigSchema>;\nexport type ProviderConfig = z.infer<typeof ProviderConfigSchema>;\nexport type Permissions = z.infer<typeof PermissionsSchema>;\nexport type HookSpec = z.infer<typeof HookSpecSchema>;\nexport type HooksConfig = z.infer<typeof HooksConfigSchema>;\nexport type PreprocessSettings = z.infer<typeof PreprocessSettingsSchema>;\nexport type InputPreprocessSettings = z.infer<typeof InputPreprocessSettingsSchema>;\nexport type RequestPreprocessSettings = z.infer<typeof RequestPreprocessSettingsSchema>;\nexport type ResultPreprocessSettings = z.infer<typeof ResultPreprocessSettingsSchema>;\nexport type RenderPreprocessSettings = z.infer<typeof RenderPreprocessSettingsSchema>;\n","/**\n * ${ENV_VAR} 占位符递归展开。\n *\n * settings.json / models.local.json 都共用这套机制,避免把明文凭证落到可入 git 的文件。\n * 未定义的 env var → 空字符串(不抛错,让上层校验\"必填字段是否非空\"决定行为)。\n */\n\nconst ENV_PATTERN = /\\$\\{([A-Z_][A-Z0-9_]*)\\}/g;\n\nexport function expandEnvVars(value: unknown): unknown {\n if (typeof value === \"string\") {\n return value.replace(ENV_PATTERN, (_match, name) => process.env[name] ?? \"\");\n }\n if (Array.isArray(value)) {\n return value.map(expandEnvVars);\n }\n if (value && typeof value === \"object\") {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[k] = expandEnvVars(v);\n }\n return result;\n }\n return value;\n}\n"],"mappings":"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","names":["resolve","tool","resolve","homedir","resolve","readFile","stat","resolve","isAbsolute","dirname","z","z","isAbsolute","resolve","stat","readFile","dirname","readFile","writeFile","resolve","isAbsolute","z","z","isAbsolute","resolve","readFile","writeFile","z","z","truncate","execa","z","z","execa","cliArgs","result","out","z","z","DEFAULT_LIMIT","z","z","z","z","z","mkdir","readFile","writeFile","homedir","join","join","homedir","readFile","mkdir","writeFile","indexPath","readFile","mkdir","writeFile","z","z","z","mkdir","readdir","readFile","stat","existsSync","homedir","dirname","join","createHash","projectHash","createHash","join","homedir","mkdir","existsSync","readdir","stat","dirname","readFile","homedir","readFile","existsSync","statSync","homedir","dirname","join","resolve","resolve","existsSync","join","dirname","join","existsSync","readFile","readFile","writeFile","mkdir","unlink","existsSync","join","join","existsSync","readFile","mkdir","writeFile","execa","execa","existsSync","dirname","isAbsolute","join","resolve","process","styles","chalk","styles","resolve","tool","isAbsolute","dirname","existsSync","join","readFile","existsSync","homedir","join","resolve","z","ENV_PATTERN","existsSync","readFile","join","homedir"]}
|