* feat: 第一版大重构 * fix: 修复类型问题 * chore: 更新版本到 1.3.2 * Add brave as alternative WebSearchTool * fix: 修正顺序 * fix: 修复对穷鬼模式的 auto dream 和 session memory 越过 * feat: 穷鬼模式去除 session-summary * feat: 创建 builtin-tools 包,搬运所有工具实现 将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/, 内部导入路径已更新为 src/ alias 模式。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/ - src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/ - 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock - tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射 - 新增 packages/builtin-tools/src 至 include Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀 所有包名及 import 路径统一添加 @claude-code-best/ 前缀: - builtin-tools → @claude-code-best/builtin-tools - mcp-client → @claude-code-best/mcp-client - agent-tools → @claude-code-best/agent-tools Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复 node 环境没有 bun 的问题 --------- Co-authored-by: Eric-Guo <eric.guocz@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
131 lines
5.1 KiB
TypeScript
131 lines
5.1 KiB
TypeScript
import { feature } from 'bun:bundle'
|
|
import { z } from 'zod/v4'
|
|
import { getKairosActive, setUserMsgOptIn } from '../bootstrap/state.js'
|
|
import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js'
|
|
import {
|
|
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
logEvent,
|
|
} from '../services/analytics/index.js'
|
|
import type { ToolUseContext } from '../Tool.js'
|
|
import { isBriefEntitled } from '@claude-code-best/builtin-tools/tools/BriefTool/BriefTool.js'
|
|
import { BRIEF_TOOL_NAME } from '@claude-code-best/builtin-tools/tools/BriefTool/prompt.js'
|
|
import type {
|
|
Command,
|
|
LocalJSXCommandContext,
|
|
LocalJSXCommandOnDone,
|
|
} from '../types/command.js'
|
|
import { lazySchema } from '../utils/lazySchema.js'
|
|
|
|
// Zod guards against fat-fingered GB pushes (same pattern as pollConfig.ts /
|
|
// cronScheduler.ts). A malformed config falls back to DEFAULT_BRIEF_CONFIG
|
|
// entirely rather than being partially trusted.
|
|
const briefConfigSchema = lazySchema(() =>
|
|
z.object({
|
|
enable_slash_command: z.boolean(),
|
|
}),
|
|
)
|
|
type BriefConfig = z.infer<ReturnType<typeof briefConfigSchema>>
|
|
|
|
const DEFAULT_BRIEF_CONFIG: BriefConfig = {
|
|
enable_slash_command: false,
|
|
}
|
|
|
|
// No TTL — this gate controls slash-command *visibility*, not a kill switch.
|
|
// CACHED_MAY_BE_STALE still has one background-update flip (first call kicks
|
|
// off fetch; second call sees fresh value), but no additional flips after that.
|
|
// The tool-availability gate (tengu_kairos_brief in isBriefEnabled) keeps its
|
|
// 5-min TTL because that one IS a kill switch.
|
|
function getBriefConfig(): BriefConfig {
|
|
const raw = getFeatureValue_CACHED_MAY_BE_STALE<unknown>(
|
|
'tengu_kairos_brief_config',
|
|
DEFAULT_BRIEF_CONFIG,
|
|
)
|
|
const parsed = briefConfigSchema().safeParse(raw)
|
|
return parsed.success ? parsed.data : DEFAULT_BRIEF_CONFIG
|
|
}
|
|
|
|
const brief = {
|
|
type: 'local-jsx',
|
|
name: 'brief',
|
|
description: 'Toggle brief-only mode',
|
|
isEnabled: () => {
|
|
if (feature('KAIROS') || feature('KAIROS_BRIEF')) {
|
|
return getBriefConfig().enable_slash_command
|
|
}
|
|
return false
|
|
},
|
|
immediate: true,
|
|
load: () =>
|
|
Promise.resolve({
|
|
async call(
|
|
onDone: LocalJSXCommandOnDone,
|
|
context: ToolUseContext & LocalJSXCommandContext,
|
|
): Promise<React.ReactNode> {
|
|
const current = context.getAppState().isBriefOnly
|
|
const newState = !current
|
|
|
|
// Entitlement check only gates the on-transition — off is always
|
|
// allowed so a user whose GB gate flipped mid-session isn't stuck.
|
|
if (newState && !isBriefEntitled()) {
|
|
logEvent('tengu_brief_mode_toggled', {
|
|
enabled: false,
|
|
gated: true,
|
|
source:
|
|
'slash_command' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
})
|
|
onDone('Brief tool is not enabled for your account', {
|
|
display: 'system',
|
|
})
|
|
return null
|
|
}
|
|
|
|
// Two-way: userMsgOptIn tracks isBriefOnly so the tool is available
|
|
// exactly when brief mode is on. This invalidates prompt cache on
|
|
// each toggle (tool list changes), but a stale tool list is worse —
|
|
// when /brief is enabled mid-session the model was previously left
|
|
// without the tool, emitting plain text the filter hides.
|
|
setUserMsgOptIn(newState)
|
|
|
|
context.setAppState(prev => {
|
|
if (prev.isBriefOnly === newState) return prev
|
|
return { ...prev, isBriefOnly: newState }
|
|
})
|
|
|
|
logEvent('tengu_brief_mode_toggled', {
|
|
enabled: newState,
|
|
gated: false,
|
|
source:
|
|
'slash_command' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
})
|
|
|
|
// The tool list change alone isn't a strong enough signal mid-session
|
|
// (model may keep emitting plain text from inertia, or keep calling a
|
|
// tool that just vanished). Inject an explicit reminder into the next
|
|
// turn's context so the transition is unambiguous.
|
|
// Skip when Kairos is active: isBriefEnabled() short-circuits on
|
|
// getKairosActive() so the tool never actually leaves the list, and
|
|
// the Kairos system prompt already mandates SendUserMessage.
|
|
// Inline <system-reminder> wrap — importing wrapInSystemReminder from
|
|
// utils/messages.ts pulls constants/xml.ts into the bridge SDK bundle
|
|
// via this module's import chain, tripping the excluded-strings check.
|
|
const metaMessages = getKairosActive()
|
|
? undefined
|
|
: [
|
|
`<system-reminder>\n${
|
|
newState
|
|
? `Brief mode is now enabled. Use the ${BRIEF_TOOL_NAME} tool for all user-facing output — plain text outside it is hidden from the user's view.`
|
|
: `Brief mode is now disabled. The ${BRIEF_TOOL_NAME} tool is no longer available — reply with plain text.`
|
|
}\n</system-reminder>`,
|
|
]
|
|
|
|
onDone(
|
|
newState ? 'Brief-only mode enabled' : 'Brief-only mode disabled',
|
|
{ display: 'system', metaMessages },
|
|
)
|
|
return null
|
|
},
|
|
}),
|
|
} satisfies Command
|
|
|
|
export default brief
|