hindsight 作为一款开源的 agent 记忆库实现方案,但是我部署以后发现他的 web-ui 没有中文版,想到未来估计会支持,就叫 AI 做了一个翻译的猴油脚本,有用这个记忆框架的可以先用着,等以后官方支持中文。
// ==UserScript==
// @name Hindsight 中文界面增强
// @namespace https://forest.example.local
// @version 0.6.1
// @description 将 Hindsight Control Plane 的常用英文界面翻译为更自然的简体中文。
// @author OpenClaw
// @match *://192.168.0.99:9999/*
// @match *://192.168.0.99:9999
// @match *://localhost:9999/*
// @match *://localhost:9999
// @match *://127.0.0.1:9999/*
// @match *://127.0.0.1:9999
// @include /^https?:\/\/(192\.168\.0\.99|localhost|127\.0\.0\.1):9999(\/.*)?$/
// @run-at document-start
// @grant unsafeWindow
// @noframes
// ==/UserScript==
(function () {
'use strict';
const DEBUG = false;
const ROOT_ATTR = 'data-hindsight-zh-active';
const ROOT_CLASS = 'hindsight-zh-ready';
const processedText = new WeakMap();
const processedElements = new WeakMap();
let scheduled = false;
let observerStarted = false;
const TEXT_MAP = new Map([
['Actions', '操作'],
['Add Document', '添加文档'],
['Add New Document', '添加新文档'],
['Add a new document to memory bank:', '向记忆库添加新文档:'],
['Add strategy', '添加策略'],
['Add Webhook', '添加 Webhook'],
['Add', '添加'],
['Audit Logs', '审计日志'],
['All actions', '全部操作'],
['All transports', '全部传输方式'],
['All time', '全部时间'],
['Any (incl. untagged)', '任意(含未分类)'],
['Any (strict)', '任意(严格)'],
['All (incl. untagged)', '全部(含未分类)'],
['All (strict)', '全部(严格)'],
['Background Operations', '后台操作'],
['Bank Configuration', '记忆库配置'],
['Applied automatically when no strategy is specified on a request.', '请求未指定策略时,自动使用此默认策略。'],
['All links between visible nodes are shown', '显示所有可见节点之间的关联'],
['Analyze memory recall with detailed trace information and retrieval methods.', '通过详细调用链路和检索方式,分析记忆召回过程。'],
['Are you sure you want to delete', '确定要删除'],
['Are you sure you want to delete the memory bank', '确定要删除记忆库'],
['Are you sure you want to reset all configuration overrides for', '确认要重置该记忆库的所有配置覆盖项吗?'],
['Attempts', '尝试次数'],
['Auto-refresh after consolidation', '整合完成后自动刷新'],
['Click a node to see details', '点击节点查看详情'],
['connections. Click a memory to view', '关联关系。点击记忆可查看'],
['Audit Logs', '审计日志'],
['Auto Refresh', '自动刷新'],
['Bank Configuration', '记忆库配置'],
['Bank configuration is disabled', '记忆库配置功能未启用'],
['causal', '因果关联'],
['Budget', '预算'],
['Cancel', '取消'],
['Canvas-rendered memory map with', '基于 Canvas 渲染的记忆地图,支持'],
['Chunk Text', '分块文本'],
['Chunk Size', '分块大小'],
['chunks', '仅分块(无 LLM)'],
['Clear', '清空'],
['Clear Observations', '清空观察结论'],
['Clearing...', '清空中...'],
['click to filter', '点击筛选'],
['Close', '关闭'],
['Collapse', '收起'],
['Consolidating...', '整合中...'],
['Consolidation', '整合'],
['Configuration', '详细配置'],
['connections. Click a memory to view', '关联关系。点击记忆可查看'],
['Constellation', '星图视图'],
['Constellation View', '星图视图'],
['Control how facts are synthesized into durable observations', '控制事实如何整合为可长期复用的观察结论。'],
['Created', '创建时间'],
['Created At', '创建时间'],
['Content *', '内容 *'],
['Context', '上下文'],
['Copy Directive', '复制指令'],
['Create a mental model by running a query. The content will be auto-generated and can be refreshed later.', '通过执行查询创建心智模型,内容自动生成,之后可随时刷新。'],
['Create Mental Model', '创建心智模型'],
['Create Webhook', '创建 Webhook'],
['Created', '创建时间'],
['Created At', '创建时间'],
['custom', '自定义规则'],
['Custom Headers', '自定义请求头'],
['Default (all_strict when tags set)', '默认(设置标签时采用 all_strict)'],
['Default (inherit)', '默认(继承)'],
['Delta mode applies minimal changes to the existing content. Falls back to a full rewrite on the first refresh and whenever the source query changes.', 'Delta 模式对现有内容进行最小化修改。首次刷新或源查询变更时,将回退为完全重写。'],
['Default extraction settings and named strategies. Pass a strategy name on retain requests to override defaults per-item.', '配置默认提取规则与命名策略。调用 retain 时可按策略名覆盖单条请求的默认设置。'],
['Default strategy', '默认策略'],
['Delete', '删除'],
['Directive Name', '指令名称'],
['Directive content', '指令内容'],
['Directive text', '指令文本'],
['Duration', '耗时'],
['Delete Bank', '删除记忆库'],
['Delete Directive', '删除指令'],
['Delete Document', '删除文档'],
['Delete Memory Bank', '删除记忆库'],
['Delete webhook', '删除 Webhook'],
['Directives', '指令'],
['Directive Details', '指令详情'],
['Discard', '放弃'],
['Display', '显示'],
['Document Deleted', '文档已删除'],
['Document ID', '文档 ID'],
['Documents', '文档'],
['drag to pan, hover to explore entity', '拖拽可平移,悬停可查看实体'],
['Duration', '耗时'],
['Edit webhook', '编辑 Webhook'],
['Enable automatic consolidation of facts into observations', '开启后,系统会自动把事实整合成观察结论。'],
['Enable Observations', '启用观察结论'],
['Enabled', '启用'],
['Empathetic', '更共情'],
['Empathy', '共情程度'],
['Entities', '实体'],
['Enter a question above to query the memory bank and generate a disposition-aware response.', '在上方输入问题,查询记忆库并生成符合记忆库画像的回复。'],
['Entity details', '实体详情'],
['entries', '条记录'],
['Error', '错误'],
['Event Date', '事件日期'],
['Event Types', '事件类型'],
['Experience', '经验经历'],
['Export Template', '导出模板'],
['Extraction Mode', '提取模式'],
['Failed at', '失败时间'],
['Full — regenerate from scratch each refresh', '完整模式——每次刷新都从头重新生成'],
['Delta — surgical edits, preserve unchanged content', 'Delta 模式——精细化编辑,保留未更改的内容'],
['Failed to copy:', '复制失败:'],
['Failed to export template', '导出模板失败'],
['Failed to fetch memory details:', '获取记忆详情失败:'],
['Filter mental models by name, query, or content...', '按名称、查询或内容筛选心智模型...'],
['First Seen', '首次出现'],
['Flexible', '更灵活'],
['General', '概览'],
['Cancel', '取消'],
['Create', '创建'],
['Upload Files', '上传文件'],
['Click to select files or drag and drop', '点击选择文件,或拖拽上传'],
['Upload ', '上传 '],
['Uploading...', '上传中...'],
['Adding...', '添加中...'],
['Add Document', '添加文档'],
['Override the bank\'s default extraction strategy for this document.', '覆盖此记忆库的默认提取策略。'],
['Strategy name (optional)...', '策略名称(可选)...'],
['Optional document identifier...', '可选文档标识...'],
['Optional context...', '上下文(可选)...'],
['Optional context about this document...', '文档上下文(可选)...'],
['Enter the document content...', '输入文档内容...'],
['Overview', '概览'],
['Options', '选项'],
['any — OR matching, includes untagged', 'any——或匹配,含无标签'],
['all — AND matching, includes untagged', 'all——与匹配,含无标签'],
['any_strict — OR matching, strict', 'any_strict——或匹配,严格'],
['all_strict — AND matching, strict', 'all_strict——与匹配,严格'],
['Graph', '关系图'],
['Hide panel', '隐藏侧栏'],
['High', '高'],
['ID', '标识符'],
['Source', '来源'],
['Tags', '标签'],
['Strategy', '策略'],
['Low', '低'],
['Mid', '中'],
['High-level purpose that guides what the bank should optimize for in reflect.', '定义记忆库在 reflect 时应优先追求的高层目标。'],
['How aggressively to extract facts. concise = selective, verbose = capture everything, verbatim = store chunks as-is (still extract entities/time), chunks = no LLM, custom = write your own rules.', '控制事实提取强度。concise = 选择性提取,verbose = 尽量全面提取,verbatim = 原样存储分块(仍提取实体/时间),chunks = 不使用 LLM,custom = 自定义提取规则。'],
['How detached vs empathic the agent should sound', '控制表达风格是更偏向克制理性,还是更富有共情。'],
['How literally vs flexibly to interpret instructions and evidence', '面对指令与证据时,是更按字面理解,还是更灵活解释。'],
['How skeptical vs trusting when evaluating claims', '在评估信息时,更偏向审慎质疑还是倾向相信。'],
['HTTP', 'HTTP'],
['ID', 'ID'],
['Index', '序号'],
['Items', '条目数'],
['Last Seen', '最近出现'],
['Links', '关联'],
['Literal', '更字面'],
['Literalism', '字面倾向'],
['LLM Batch Size', 'LLM 批处理大小'],
['Limited to 50 nodes for performance. Total:', '为保障性能,最多显示 50 个节点。总计:'],
['Loading...', '加载中...'],
['Loading memories...', '正在加载记忆...'],
['Manage bank settings, profile, and operations.', '统一管理记忆库的设置、画像和后台操作。'],
['Manage documents and retain new memories.', '管理文档内容,并将新信息写入记忆库。'],
['Manage webhook endpoints to receive event notifications from this memory bank.', '管理 Webhook 接收地址,用于订阅这个记忆库的事件通知。'],
['Match all selected tags', '匹配全部已选标签'],
['Match any selected tag', '匹配任意已选标签'],
['Max nodes', '最大节点数'],
['Max Observations Per Scope', '每个作用域的观察上限'],
['Memory Composition', '记忆构成'],
['Memory Details', '记忆详情'],
['Memory Units', '记忆单元数'],
['Mental model refreshed', '心智模型已刷新'],
['Mental Models', '心智模型'],
['Mentions', '提及次数'],
['Mentioned', '提及时间'],
['Metadata', '元数据'],
['Method', '方法'],
['memories without dates in Table View.', '条记忆在表格视图中无日期。'],
['Mission', '使命说明'],
['No memories have occurred_at dates.', '暂无设置发生时间的记忆。'],
['Other Mental Models', '其他心智模型'],
['No data for this period', '该时段暂无数据'],
['No data available', '暂无可用数据'],
['No documents found', '未找到文档'],
['No mental models match your filter', '没有符合筛选条件的心智模型'],
['No mental models yet. Create a mental model to generate and save a summary from your memories.', '暂无心智模型。创建后可从记忆中生成并保存可复用的摘要。'],
['No raw payload stored for this operation.', '该操作没有保存原始负载。'],
['No Timeline Data', '暂无时间轴数据'],
['No webhooks configured. Add a webhook to receive event notifications.', '尚未配置 Webhook。请添加以接收事件通知。'],
['No audit logs found', '未找到审计日志'],
['No bank selected', '尚未选择记忆库'],
['Nodes', '节点'],
['No — skip chunks (smaller prompt)', '否——跳过分块文本(提示词更短)'],
['Objective facts about the world received from external sources.', '来自外部来源的客观事实与背景信息。'],
['Observations', '观察结论'],
['Observations cleared successfully', '观察结论已成功清空'],
['Observations feature is not enabled', '观察结论功能未启用'],
['Observations Not Enabled', '观察结论功能未开启'],
['Observations consolidation is disabled on this server. Set', '当前服务器未开启观察结论整合能力。请设置'],
['Off', '关闭'],
['Occurred (end)', '发生时间(结束)'],
['Occurred (start)', '发生时间(开始)'],
['Original Text', '原始文本'],
['Overview statistics and background operations for this memory bank.', '查看记忆库的概览统计、后台任务与画像信息。'],
['Performance', '性能'],
['Please select a memory bank from the dropdown above to view its profile.', '请先从上方下拉框选择一个记忆库,再查看其画像信息。'],
['Query Parameters', '查询参数'],
['Recovering...', '恢复中...'],
['Refetch Entities', '重新获取实体'],
['Refine', '优化'],
['Recover Consolidation', '恢复整合'],
['Reflect', '深度思考'],
['Refresh timeout', '刷新超时'],
['Refresh webhooks', '刷新 Webhook'],
['Request Volume', '请求量'],
['Reset Configuration', '重置配置'],
['Resetting...', '重置中...'],
['Retain', '写入记忆'],
['Run Consolidation', '运行整合'],
["Run an agentic loop that autonomously gathers evidence and reasons through the lens of the bank's disposition to generate contextual responses.", '运行带自主搜证能力的思考流程,结合记忆库画像生成更贴合上下文的回答。'],
['Save Changes', '保存更改'],
['Saving...', '保存中...'],
['Select a memory bank from the dropdown above to get started.', '请先从上方的下拉列表中选择记忆库。'],
['Select a memory bank to view mental models.', '请先选择记忆库再查看心智模型。'],
['Show labels', '显示标签'],
['Show panel', '显示侧栏'],
['Signing secret', '签名密钥'],
['Size', '大小'],
['Size of text chunks for processing (characters)', '用于处理的文本分块大小(字符数)'],
['Skeptical', '更倾向审慎'],
['Skepticism', '怀疑程度'],
['Source Facts Max Tokens', '来源事实最大 Token 数'],
['Source Facts Max Tokens Per Observation', '每条观察的来源事实 Token 上限'],
['Source Query', '源查询语句'],
['Sources', '来源'],
['spatial label deconfliction. Scroll to zoom,', '空间标签避让。滚轮可缩放,'],
['Status', '状态'],
['Success', '成功'],
['Table', '列表视图'],
['Tags Match', '标签匹配方式'],
['Tag Groups', '标签分组'],
["The bank's own actions, interactions, and first-person experiences.", '记忆库自身的行为、互动过程及第一视角经历。'],
['This action cannot be undone. All memories, entities, documents, and the bank profile will be permanently deleted.', '此操作无法撤销。记忆、实体、文档以及记忆库画像都会被永久删除。'],
['This is a parent operation — the raw payload is stored on each sub-batch. Open a child operation to inspect its payload.', '这是一个父级操作;原始负载保存在各个子批次中,请打开子操作查看。'],
['This will delete all consolidated knowledge. Observations will be regenerated the next time consolidation runs.', '将清除所有已整合的观察结论;下次整合时会重新生成。'],
['Text', '文本'],
['Time', '时间'],
['Timeline', '时间轴'],
['Transport', '传输方式'],
['Upload Files', '上传文件'],
['Timeout (seconds)', '超时时间(秒)'],
['to enable per-bank configuration.', '后即可启用按记忆库单独配置。'],
['to enable.', '后启用。'],
['total memories', '记忆总数'],
['Traits that shape the reasoning and perspective', '这些特质共同影响推理方式和表达视角。'],
['Transport', '传输方式'],
['Trusting', '更倾向相信'],
['Skeptical', '更倾向怀疑'],
['Flexible', '更灵活'],
['Literal', '更字面'],
['Detached', '更疏离'],
['Empathetic', '更共情'],
['How skeptical vs trusting when evaluating claims', '评估信息时的怀疑与信任倾向'],
['How literally to interpret information', '对信息的解读方式(字面 vs 灵活)'],
['How much to weight emotional context', '对情绪背景的重视程度'],
['Restrict which MCP tools this bank exposes to agents', '限制此记忆库向 Agent 暴露的 MCP 工具'],
['When off, all tools are available. When on, only the selected tools can be invoked for this bank.', '关闭时所有工具可用。开启时仅可调用此处选择的工具。'],
['Provider-specific model settings', '提供商专属模型配置'],
['Gemini / Vertex AI', 'Gemini / Vertex AI'],
['Safety settings', '安全阈值配置'],
['When off, Gemini\'s default safety thresholds are used. When on, configure thresholds per harm category.', '关闭时使用 Gemini 默认安全阈值。开启后可按危害类别配置阈值。'],
['Learn more', '了解更多'],
['Models', '模型'],
['MCP Tools', 'MCP 工具'],
['Restrict tools', '限制工具'],
['Shape how the bank reasons and responds in reflect operations', '定义此记忆库在深度思考时的推理方式与响应风格'],
['Default', '默认'],
['Type', '类型'],
['Update Mental Model', '更新心智模型'],
['Update the webhook configuration.', '更新此 Webhook 的配置。'],
['Updated', '更新时间'],
['URL', '地址'],
['User-curated summaries generated from queries — reusable knowledge snapshots that can be refreshed as memories evolve.', '由查询生成并可人工维护的知识摘要快照,可随记忆变化反复刷新。'],
['View and explore different types of memories stored in this memory bank.', '浏览并深入查看记忆库中保存的各类记忆。'],
['View audit trail of all operations performed on this memory bank.', '查看记忆库全部操作的审计轨迹。'],
['View deliveries', '查看投递记录'],
['Webhook Deliveries', 'Webhook 投递记录'],
['Webhooks', 'Webhook'],
['Welcome to Hindsight', '欢迎使用 Hindsight'],
['World Facts', '世界事实'],
['Experience', '经验经历'],
['Observations', '观察结论'],
['Mental Models', '心智模型'],
['Filter by text or context (press Enter)...', '按文本或上下文筛选(回车确认)...'],
['Filter by tag…', '按标签筛选...'],
['total memories', '条记忆'],
['Mentioned', '提及次数'],
['Constellation', '星图视图'],
['Graph', '关系图'],
['Table', '表格视图'],
['Timeline', '时间轴'],
['Fullscreen', '全屏'],
['Hide panel', '收起面板'],
['Constellation View', '星图视图'],
['Canvas-rendered memory map with spatial label deconfliction. Scroll to zoom, drag to pan, hover to explore entity connections. Click a memory to view details.', '基于 Canvas 渲染的记忆地图,支持空间标签解冲突。滚轮缩放,拖拽平移,悬停查看实体关联。点击记忆查看详情。'],
['Color by', '颜色分类'],
['Link types', '关联类型'],
['semantic', '语义'],
['temporal', '时序'],
['entity', '实体'],
['causal', '因果'],
['Nodes:', '节点数:'],
['Links:', '连接数:'],
['Yes — include raw chunk text', '是——包含原始分块文本'],
['Ready to Recall', '准备召回'],
['Enter a query above to search through your memories. Use filters to narrow down by fact type, budget, and more.', '在上方输入查询词搜索记忆。使用筛选条件(类型、优先级等)缩小范围。'],
['What would you like to recall?', '你想要召回什么?'],
['Any (incl. untagged)', '任意(含未分类)'],
['All (incl. untagged)', '全部(含未分类)'],
['Any (strict)', '任意(严格)'],
['All (strict)', '全部(严格)'],
['Low', '低'],
['Mid', '中'],
['High', '高'],
['Ready to 深度思考', '准备深度思考'],
['Enter a question above to query the memory bank and generate a disposition-aware response.', '在上方输入问题,查询记忆库并生成符合记忆库画像的回复。'],
['Explore entities (people, organizations, places) mentioned in memories.', '探索记忆中提及的实体(人物、组织、地点等)。'],
['Relations', '关系图'],
['List', '列表'],
['No mental models', '暂无心智模型'],
['Memory store', '记忆存储'],
['Memories', '记忆'],
['Memory composition', '记忆构成'],
['Link types', '关联类型'],
['Temporal', '时序关联'],
['Semantic', '语义关联'],
['Entity', '实体关联'],
['Done', '已完成'],
['Pending', '等待中'],
['Failed', '已失败'],
['Last', '最近'],
['Activity', '活动'],
['Memories by ingested time', '按摄入时间排列的记忆'],
['All', '全部'],
['Processing', '处理中'],
['Completed', '已完成'],
['Cancelled', '已取消'],
['Showing', '显示'],
['Directives', '指令'],
['Hard rules that must be followed during reflect', '在深度思考时必须遵守的硬性规则'],
['No directives yet. Directives are hard rules that must be followed during reflect.', '暂无指令。指令是在深度思考时必须遵守的硬性规则。'],
['Delete Mental Model', '删除心智模型'],
['Consolidated knowledge synthesized from facts — patterns, preferences, and learnings that emerge from accumulated evidence.', '从事实中综合提炼的知识——从积累的证据中形成的规律、偏好与经验教训。'],
['Color by', '颜色分类'],
['Add Mental Model', '添加心智模型'],
['Dashboard', '仪表盘'],
['Chunks', '分块'],
['Budget', '优先级'],
['Include Source', '包含来源'],
['Include Tools', '包含工具'],
['Exclude mental models', '排除心智模型'],
['Exclude IDs', '排除 ID'],
['Observation', '观察结论'],
['Fact types:', '事实类型:'],
['World', '世界'],
['documents', '文档'],
['by ingested time', '按摄入时间'],
['Ingested', '摄入时间'],
['Occurred', '发生时间'],
['Operations', '操作'],
['Background Operations', '后台操作'],
['All types', '全部类型'],
['Override the bank\'s default extraction strategy for this document.', '覆盖此记忆库的默认提取策略。'],
['Process in background (async)', '后台异步处理'],
['Previous', '上一页'],
['What this bank should pay attention to during extraction. Steers the LLM without replacing the extraction rules.', '定义记忆库在提取时应关注的内容,用于引导 LLM 行为,但不替代提取规则本身。'],
['e.g. Always include technical decisions, API design choices, and architectural trade-offs.', '例如:始终关注技术决策、API 设计选择和架构权衡。'],
['Extract regular named entities (people, places, concepts) alongside entity labels. Disable to restrict extraction to entity labels only.', '提取常规命名实体(人物、地点、概念等)并附带实体标签。关闭后仅提取实体标签。'],
['Extracted per memory at retain time. Every field is optional — only filled when clearly applicable.', '在 retain 时为每条记忆提取。每个字段均为可选——仅在明确适用时填写。'],
['No entity labels defined.', '尚未定义实体标签。'],
['Add label', '添加标签'],
['What this bank should synthesise into durable observations. Replaces the built-in consolidation rules — leave blank to use the server default.', '定义记忆库应将哪些内容整合为可长期复用的观察结论。覆盖内置整合规则,留空则使用服务器默认值。'],
['Recall', '召回'],
['memories by ingested time', '按摄入时间的记忆'],
['memories by mentioned time', '按提及时间的记忆'],
['memories by occurred time', '按发生时间的记忆'],
['Create Directive', '创建指令'],
['Directive are hard rules that must be followed during reflect.', '指令是深度思考时必须遵守的硬性规则。'],
['Name *', '名称 *'],
['e.g., Competitor Policy', '例如:竞争策略'],
['Rule *', '规则 *'],
['e.g., Never mention competitor products directly.', '例如:不要直接提及竞品。'],
['Tags (optional)', '标签(可选)'],
['e.g., project-x, team-alpha (comma-separated)', '例如:项目-x, 团队-alpha(逗号分隔)'],
['Add Directive', '添加指令'],
['No Bank Selected', '尚未选择记忆库'],
['Select a memory bank to start reflecting.', '请先选择记忆库再开始深度思考。'],
['Reflecting...', '深度思考中...'],
['Budget:', '优先级:'],
['Tokens:', 'Token 数:'],
['Filter by tags (comma-separated)', '按标签筛选(用逗号分隔)'],
['Exclude mental models', '排除心智模型'],
['Exclude IDs:', '排除 ID:'],
['Reflecting on memories...', '正在从记忆中思考...'],
['Input tokens:', '输入 Token:'],
['Output tokens:', '输出 Token:'],
['Tool calls:', '工具调用:'],
['LLM calls:', 'LLM 调用:'],
['Answer', '回答'],
['Trace', '调用链'],
['JSON', 'JSON'],
['Hard rules injected into prompts that the agent must follow', '注入提示词中的硬性规则,Agent 必须遵守'],
['Directive saved to', '指令已保存至'],
['e.g., Always respond in formal English...', '例如:始终以正式英语回复...'],
['Observations Created', '观察结论已创建'],
['New observations learned during this reflection', '本次深度思考中新产生的观察结论'],
['Execution Trace', '执行调用链'],
['iteration', '次迭代'],
['Based on', '基于'],
['Directives', '指令'],
['Mental Models', '心智模型'],
['World', '世界'],
['Experience', '经验'],
['No observations created.', '未产生观察结论。'],
['No directives available for this bank.', '该记忆库暂无指令。'],
['No mental models match your filter.', '没有符合筛选条件的心智模型。'],
['Create your first mental model to synthesize knowledge from your memories.', '创建你的第一个心智模型,从记忆库中综合提炼知识。'],
['Token usage', 'Token 使用量'],
['per iteration', '每次迭代'],
['ms', '毫秒'],
['LLM calls', 'LLM 调用'],
['Tool calls', '工具调用'],
['Directives used', '使用的指令'],
['Directives created', '创建的指令'],
['No directives were used or created in this reflection.', '本次深度思考未使用或创建任何指令。'],
['Mental Models', '心智模型'],
['Observations', '观察结论'],
['World Facts', '世界事实'],
['Experience Facts', '经验事实'],
['Dispositional context', '画像上下文'],
['Based on facts retrieved from the memory bank.', '基于从记忆库中召回的事实。'],
['Loading...', '加载中...'],
['Close', '关闭'],
['Tokens', 'Token'],
['Max', '最大'],
['min', '分钟'],
['sec', '秒'],
['Reflecting', '深度思考中'],
['Save', '保存'],
['Cancel', '取消'],
['Delete', '删除'],
['Name', '名称'],
['Description', '描述'],
['Content', '内容'],
['Tags', '标签'],
['Created at', '创建时间'],
['Updated at', '更新时间'],
['Status', '状态'],
['Type', '类型'],
['ID', 'ID'],
['World fact', '世界事实'],
['Experience fact', '经验事实'],
['Memory', '记忆'],
['Entities', '实体'],
['Documents', '文档'],
['Operations', '操作'],
['Chunks', '分块'],
['Sources', '来源'],
['Metadata', '元数据'],
['Preview', '预览'],
['Copy', '复制'],
['Edit', '编辑'],
['View', '查看'],
['Delete', '删除'],
['Refresh', '刷新'],
['Reload', '重新加载'],
['Load more', '加载更多'],
['Show less', '收起更多'],
['Search', '搜索'],
['Filter', '筛选'],
['Sort by', '排序依据'],
['Date', '日期'],
['Relevance', '相关性'],
['Ascending', '升序'],
['Descending', '降序'],
['Previous', '上一页'],
['Next', '下一页'],
['Page', '页'],
['of', '/'],
['Results', '条结果'],
['No results found', '未找到结果'],
['Clear filters', '清除筛选'],
['Apply', '应用'],
['Reset', '重置'],
['Confirm', '确认'],
['Warning', '警告'],
['Info', '信息'],
['Success', '成功'],
['Error', '错误'],
['Required', '必填'],
['Optional', '可选'],
['Entities', '实体'],
['Relations', '关系'],
['Nodes', '节点'],
['Links', '链接'],
['Clusters', '聚类'],
['Timeline', '时间轴'],
['Entities by type', '按类型分类的实体'],
['Memory count', '记忆数量'],
['Fact types', '事实类型'],
['Document count', '文档数量'],
['Ingested', '摄入时间'],
['Occurred', '发生时间'],
['Mentioned', '提及时间'],
['by mentioned time', '按提及时间'],
['by occurred time', '按发生时间'],
['Memories over time', '记忆随时间变化'],
['Facts per day', '每日事实数'],
['Operations over time', '操作随时间变化'],
['World Facts', '世界事实'],
['Experience Facts', '经验事实'],
['All memories', '全部记忆'],
['Filtered', '已筛选'],
['Clear', '清除'],
['Memory details', '记忆详情'],
['Entity details', '实体详情'],
['Directive details', '指令详情'],
['Mental model details', '心智模型详情'],
['Observation details', '观察结论详情'],
['Document details', '文档详情'],
['No memory selected', '未选择记忆'],
['Select a memory to view its details.', '选择一个记忆以查看其详情。'],
['No entity selected', '未选择实体'],
['Select an entity to view its details.', '选择一个实体以查看其详情。'],
['Tags', '标签'],
['Fact type', '事实类型'],
['Occurred at', '发生于'],
['Ingested at', '摄入于'],
['Mentioned at', '提及于'],
['Source document', '来源文档'],
['Source chunk', '来源分块'],
['Related entities', '相关实体'],
['Related memories', '相关记忆'],
['Related documents', '相关文档'],
['First seen', '首次出现'],
['Last seen', '最近出现'],
['Mention count', '提及次数'],
['Entity type', '实体类型'],
['Label', '标签'],
['Value', '值'],
['Count', '数量'],
['Percentage', '百分比'],
['Total', '合计'],
['Average', '平均'],
['Min', '最小'],
['Max', '最大'],
['Sum', '总和'],
['Time range', '时间范围'],
['From', '从'],
['To', '到'],
['Today', '今天'],
['Yesterday', '昨天'],
['Last 7 days', '最近 7 天'],
['Last 30 days', '最近 30 天'],
['Last 90 days', '最近 90 天'],
['All time', '全部时间'],
['Custom range', '自定义范围'],
['January', '一月'],
['February', '二月'],
['March', '三月'],
['April', '四月'],
['May', '五月'],
['June', '六月'],
['July', '七月'],
['August', '八月'],
['September', '九月'],
['October', '十月'],
['November', '十一月'],
['December', '十二月'],
['Sun', '日'],
['Mon', '一'],
['Tue', '二'],
['Wed', '三'],
['Thu', '四'],
['Fri', '五'],
['Sat', '六'],
['Sunday', '星期日'],
['Monday', '星期一'],
['Tuesday', '星期二'],
['Wednesday', '星期三'],
['Thursday', '星期四'],
['Friday', '星期五'],
['Saturday', '星期六'],
['Jan', '1月'],
['Feb', '2月'],
['Mar', '3月'],
['Apr', '4月'],
['Jun', '6月'],
['Jul', '7月'],
['Aug', '8月'],
['Sep', '9月'],
['Oct', '10月'],
['Nov', '11月'],
['Dec', '12月'],
['Today', '今天'],
['Loading bank data...', '正在加载记忆库数据...'],
['No data available for this time range.', '该时间范围内暂无数据。'],
['Select a bank to view statistics.', '选择一个记忆库以查看统计信息。'],
['Total memories', '记忆总数'],
['Total entities', '实体总数'],
['Total documents', '文档总数'],
['Total operations', '操作总数'],
['Pending operations', '等待中的操作'],
['Failed operations', '失败的操作'],
['Completed operations', '已完成的操作'],
['Success rate', '成功率'],
['Average duration', '平均耗时'],
['Total duration', '总耗时'],
['Operations by status', '按状态分类的操作'],
['Operations by type', '按类型分类的操作'],
['Memories by fact type', '按事实类型分类的记忆'],
['Entities by type', '按类型分类的实体'],
['Memory timeline', '记忆时间线'],
['Activity feed', '活动动态'],
['Recent activity', '最近活动'],
['View all', '查看全部'],
['Show more', '显示更多'],
['Show less', '显示更少'],
['No recent activity', '暂无最近活动'],
['Load more', '加载更多'],
['End of results', '已加载全部'],
['Fetching more results...', '正在加载更多结果...'],
['Something went wrong', '出现错误'],
['Please try again', '请重试'],
['No more results', '没有更多结果了'],
['results per page', '条结果每页'],
['Go to page', '跳至页'],
['First page', '首页'],
['Last page', '末页'],
['Comma-separated — used to filter memories during recall/reflect', '逗号分隔——用于在召回/深度思考时过滤记忆'],
['Scopes', '作用域'],
['Combined', '合并'],
['Add tags above to preview observation scopes', '在上方添加标签以预览观察结论作用域'],
['source: slack', '来源: slack'],
['channel: engineering', '频道: engineering'],
['One key: value per line', '每行一个键值对'],
['Alice, Google, ML model', 'Alice, Google, ML 模型'],
['Comma-separated hints merged with auto-extracted entities', '逗号分隔的提示词,与自动提取的实体合并'],
['changes', '变更'],
['Number of facts sent to the LLM in a single consolidation call. Higher values reduce LLM calls at the cost of larger prompts. Leave blank to use the server default.', '单次整合调用中发送给 LLM 的事实数量。更高的数值可减少 LLM 调用次数,但代价是提示词更大。留空使用服务器默认值。'],
['Total token budget for source facts included with observations during consolidation. -1 = unlimited.', '整合时与观察结论一起包含的来源事实总 Token 预算。-1 = 无限制。'],
['Per-observation token cap for source facts during consolidation. Each observation gets at most this many tokens of source facts. -1 = unlimited.', '整合时每条观察的来源事实 Token 上限。每条观察最多获得此数量的来源事实 Token。-1 = 无限制。'],
['Maximum number of observations allowed per tag scope. When the limit is reached, only updates and deletes are allowed. Observations with no tags are not subject to this limit. -1 = unlimited.', '每个标签作用域允许的最大观察数量。达到上限后仅允许更新和删除。无标签的观察不受此限制。-1 = 无限制。'],
['Agent identity and purpose. Used as framing context in reflect.', '智能体身份与定位。作为深度思考时的框架上下文。'],
['Hermes Agent memory bank', 'Hermes Agent 记忆库'],
['consolidation', '整合'],
['Directives are hard rules that must be followed during reflect.', '指令是深度思考时必须遵守的硬性规则。'],
['Free Form Entities', '自由形式实体'],
['Entities are mentioned in your memories.', '记忆中被提及的实体。'],
['No entities found.', '未找到实体。'],
['Hindsight Control Plane', 'Hindsight 控制面板'],
[' operations', ' 个操作'],
['memory bank', '记忆库'],
['Tag (optional)', '标签(可选)'],
['记忆 by ingested time', '按摄入时间的记忆'],
['Create Directive', '创建指令'],
]);
const TITLE_MAP = new Map([
['Expand sidebar', '展开侧边栏'],
['Collapse sidebar', '收起侧边栏'],
['View on GitHub', '在 GitHub 上查看'],
['Switch to dark mode', '切换到深色模式'],
['Switch to light mode', '切换到浅色模式'],
['Logout', '退出登录'],
['Add document to current bank', '向当前记忆库添加文档'],
['Refresh observations', '刷新观察结论'],
['Hide panel', '隐藏面板'],
['Show panel', '显示面板'],
['Match any selected tag', '匹配任意已选标签'],
['Match all selected tags', '匹配全部已选标签']
]);
const PLACEHOLDER_MAP = new Map([
['Select a memory bank...', '请选择记忆库...'],
['Search memory banks...', '搜索记忆库...'],
['Enter bank ID...', '输入记忆库 ID...'],
['Enter the document content...', '输入文档内容...'],
['What would you like to reflect on?', '你想围绕什么内容进行深度思考?'],
['Filter by tags (comma-separated)', '按标签筛选(用逗号分隔)'],
['Filter by text or context (press Enter)...', '按文本或上下文筛选(回车执行)...'],
['Search documents (ID)...', '搜索文档(按 ID)...'],
['Filter by tag…', '按标签筛选…'],
['Optional context...', '上下文(可选)...'],
['Optional context about this document...', '文档上下文(可选)...'],
['Optional ID...', '可选 ID...'],
['Optional document identifier...', '可选文档标识...'],
['Strategy name (optional)...', '策略名称(可选)...'],
['Enter access key', '输入访问密钥'],
['tag1, tag2...', '例如:标签1, 标签2...'],
['model-a, model-b', '例如:model-a, model-b'],
['e.g. Observations are stable facts about people and projects. Always include preferences, skills, and recurring patterns. Ignore one-off events and ephemeral state.', '例如:观察结论应聚焦人物和项目的稳定事实,优先保留偏好、技能和长期规律,忽略一次性事件与短暂状态。'],
['e.g. You are a senior engineering assistant. Always ground answers in documented decisions and rationale. Ignore speculation. Be direct and precise.', '例如:你是一名资深工程助手。回答必须基于已记录的决策与依据,忽略猜测,表达直接且准确。'],
['e.g. Always include technical decisions, API design choices, and architectural trade-offs.', '例如:始终记录技术决策、API 设计选择和架构权衡。'],
['e.g., I am a PM for the engineering team. I help coordinate sprints and track project progress...', '例如:我是工程团队的项目经理,负责协调冲刺并跟踪项目进度...'],
['e.g., Competitor Policy', '例如:竞品策略'],
['e.g., Never mention competitor products directly.', '例如:绝不直接提及竞品名称。'],
['e.g., team-communication', '例如:team-communication'],
['e.g., Team Communication Preferences', '例如:团队沟通偏好'],
['e.g., How does the team prefer to communicate?', '例如:团队偏好怎样的沟通方式?'],
['e.g., Always respond in formal English...', '例如:始终使用正式英语回答...'],
['e.g. { "or": [{ "tags": ["user:alice"], "match": "all_strict" }, { "tags": ["shared"] }] }', '例如:[{ "or": [{ "tags": ["user:alice"], "match": "all_strict" }, { "tags": ["shared"] }] }]'],
['Exclude all mental models', '排除所有心智模型'],
['Exclude Mental Model IDs', '排除的心智模型 ID'],
['e.g., model-a, model-b (comma-separated)', '例如:model-a, model-b(逗号分隔)'],
['Tags scope the model during reflect and filter source memories during refresh (default all_strict: only memories carrying every listed tag are read). If no memories have these tags yet, refresh will produce empty content — backfill tags on memories, or adjust 标签匹配方式 / 标签分组 below.', '标签用于限定模型在 reflect 时的搜索范围,并在刷新时过滤源记忆(默认为 all_strict:仅读取包含所有列出标签的记忆)。如果尚无记忆包含这些标签,刷新将产生空内容——请为记忆补充标签,或调整下方的标签匹配方式 / 标签分组。'],
['Controls how the model\'s tags filter memories during refresh.', '控制模型的标签在刷新时如何过滤记忆。'],
['Compound boolean tag expressions for refresh filtering. Overrides flat tags when set.', '复合布尔标签表达式,用于刷新时的过滤。设置后覆盖普通标签。'],
['Override how the internal recall behaves when this model refreshes. Leave blank to inherit the bank/global default.', '覆盖此模型刷新时内部召回的行为。留空则继承记忆库或全局默认设置。'],
['Fact Types', '事实类型'],
['World', '世界观'],
['Experience', '经验'],
['Leave empty to include all types.', '留空则包含所有类型。'],
['Yes — include raw chunk text', '是——包含原始分块文本'],
['No — skip chunks (smaller prompt)', '否——跳过分块文本(提示词更短)'],
['Default (inherit)', '默认(继承)'],
['Token budget for facts returned by recall.', '召回返回事实的 Token 预算。'],
['Token budget for raw chunk text returned by recall.', '召回返回原始分块文本的 Token 预算。'],
['Directives are hard rules that must be followed during reflect.', '指令是深度思考时必须遵守的硬性规则。'],
['Name *', '名称 *'],
['Rule *', '规则 *'],
['Tags (optional)', '标签(可选)'],
['Extraction strategy', '提取策略'],
['Configure the default extraction rules and naming strategy. Pass a strategy name when calling retain to override the default for a single request.', '配置默认提取规则与命名策略。调用 retain 时可按策略名覆盖单条请求的默认设置。'],
['Extraction mode', '提取模式'],
['Controls how aggressively facts are extracted. concise = selective, verbose = thorough, verbatim = store chunks as-is (still extracts entities/dates), chunks = no LLM, custom = custom extraction rules.', '控制事实提取强度。concise = 选择性提取,verbose = 尽量全面提取,verbatim = 原样存储分块(仍提取实体/时间),chunks = 不使用 LLM,custom = 自定义提取规则。'],
['concise', '简洁'],
['verbose', '详细'],
['verbatim', '逐字'],
['chunks', '仅分块'],
['custom', '自定义'],
['Chunk size', '分块大小'],
['The size of text chunks used for processing (in characters).', '用于处理的文本分块大小(字符数)。'],
['Mission statement', '使命说明'],
['Free Form Entities', '自由形式实体'],
['Extract general named entities (people, places, concepts, etc.) with entity labels. When disabled, only entity labels are extracted.', '提取常规命名实体(人物、地点、概念等)并附带实体标签。关闭后仅提取实体标签。'],
['Entity-linked Tags', '实体关联标签'],
['Extract per-memory tags during retain. Each field is optional — only fill in when explicitly applicable.', '在 retain 时为每条记忆提取标签。每个字段均为可选——仅在明确适用时填写。'],
['No entity tags defined yet.', '尚未定义实体标签。'],
['Save changes', '保存更改'],
['Enable observations', '启用观察结论'],
['When enabled, the system automatically consolidates facts into reusable observations.', '开启后,系统会自动把事实整合成观察结论。'],
['LLM batch size', 'LLM 批处理大小'],
['Number of facts sent to the LLM in a single consolidation call. Higher values reduce LLM calls at the cost of larger prompts. Leave blank to use the server default.', '单次整合调用中发送给 LLM 的事实数量。更高数值可减少 LLM 调用次数,但代价是提示词更大。留空使用服务器默认值。'],
['Source facts max tokens', '来源事实最大 Token 数'],
['Total token budget for source facts included with observations during consolidation. -1 = unlimited.', '整合时与观察结论一起包含的来源事实总 Token 预算。-1 = 无限制。'],
['Per-observation source facts token cap', '每条观察的来源事实 Token 上限'],
['Per-observation token cap for source facts during consolidation. Each observation gets at most this many tokens of source facts. -1 = unlimited.', '整合时每条观察的来源事实 Token 上限。每条观察最多获得此数量的来源事实 Token。-1 = 无限制。'],
['Max observations per scope', '每个作用域的观察上限'],
['Maximum number of observations allowed per tag scope. When the limit is reached, only updates and deletes are allowed. Observations with no tags are not subject to this limit. -1 = unlimited.', '每个标签作用域允许的最大观察数量。达到上限后仅允许更新和删除。无标签的观察不受此限制。-1 = 无限制。'],
['Define how this memory bank reasons and responds during reflect.', '定义此记忆库在深度思考时的推理方式与响应风格。'],
['Agent identity and purpose. Used as framing context in reflect.', '智能体身份与定位。作为深度思考时的框架上下文。'],
['Skepticism', '怀疑程度'],
['Tendency to doubt versus trust when evaluating claims.', '评估信息时的怀疑与信任倾向。'],
['Literalness', '字面倾向'],
['How to interpret information (literal versus flexible).', '对信息的解读方式(字面 vs 灵活)。'],
['Empathy', '共情程度'],
['How much weight to give emotional context.', '对情绪背景的重视程度。'],
['Model', '模型'],
['Provider-specific model configuration.', '提供商专属模型配置。'],
['Safety settings', '安全阈值配置'],
['Configure safety thresholds.', '配置安全阈值。'],
['Configure a webhook endpoint to receive event notifications.', '配置 Webhook 端点以接收事件通知。'],
['Type', '类型'],
['URL *', '地址 *'],
['Method', '方法'],
['Timeout (seconds)', '超时时间(秒)'],
['Secret (optional)', '密钥(可选)'],
['Signing key', '签名密钥'],
['Custom headers', '自定义请求头'],
['Query parameters', '查询参数'],
['Event types', '事件类型'],
['Add Tag', '添加标签'],
['Add strategy', '添加策略'],
['Default', '默认'],
['Include only chunks (no LLM)', '仅分块(无 LLM)'],
['Default strategy', '默认策略'],
['When a request does not specify a strategy, this one is used automatically.', '当请求未指定策略时,会自动使用这里的默认策略。'],
['Add Webhook', '添加 Webhook'],
['consolidation.completed', '整合完成'],
['retain.completed', '记忆完成'],
['Disabled', '已禁用'],
['Default (all_strict when tags set)', '默认(设置标签时为 all_strict)'],
['field name', '字段名'],
['key: value', '例如:key: value'],
['Enter a query...', '输入查询词...'],
['Search memories...', '搜索记忆...'],
['Search entities...', '搜索实体...'],
['Search documents...', '搜索文档...'],
['Search...', '搜索...'],
['Type a question...', '输入问题...'],
['Enter directive name...', '输入指令名称...'],
['Enter rule...', '输入规则...'],
['Enter tags...', '输入标签...'],
['Enter description...', '输入描述...'],
['Enter content...', '输入内容...'],
['Enter URL...', '输入地址...'],
['Enter ID...', '输入 ID...'],
['Select date...', '选择日期...'],
['Select time...', '选择时间...'],
['user_alice, session_123, project_x', 'user_alice, session_123, project_x'],
]);
const ARIA_LABEL_MAP = new Map([
['Remove tag', '移除标签'],
['Close', '关闭']
]);
const EXACT_BLOCKLIST = new Set(['Hindsight', 'GitHub', 'JSON', 'HTTP', 'LLM', 'MCP', 'POST', 'GET']);
function log(...args) {
if (DEBUG) console.log('[Hindsight-ZH]', ...args);
}
function markActive() {
const root = document.documentElement;
if (!root) return;
root.setAttribute(ROOT_ATTR, '1');
root.classList.add(ROOT_CLASS);
root.setAttribute('lang', 'zh-CN');
}
function normalizeSpaces(str) {
return str.replace(/\s+/g, ' ').trim();
}
function decodeHtml(text) {
if (!text || !/[&][a-z#0-9]+;/i.test(text)) return text;
const textarea = document.createElement('textarea');
textarea.innerHTML = text;
return textarea.value;
}
function translateExact(text) {
const decoded = decodeHtml(text);
const normalized = normalizeSpaces(decoded);
if (!normalized || EXACT_BLOCKLIST.has(normalized)) return null;
return TEXT_MAP.get(normalized) || null;
}
function translateFragment(text) {
if (!text) return text;
let output = text;
for (const [from, to] of TEXT_MAP.entries()) {
if (from.length < 4) output = output === from ? to : output;
else if (output.includes(from)) output = output.split(from).join(to);
}
return output;
}
function processTextNode(node) {
if (!node || node.nodeType !== Node.TEXT_NODE) return false;
const parent = node.parentElement;
if (!parent || parent.closest('script, style, textarea, code, pre')) return false;
const raw = node.nodeValue;
if (!raw) return false;
if (processedText.get(node) === raw) return false;
const trimmed = raw.trim();
if (!trimmed) {
processedText.set(node, raw);
return false;
}
const exact = translateExact(trimmed);
if (exact) {
const next = raw.replace(trimmed, exact);
if (next !== raw) {
node.nodeValue = next;
processedText.set(node, next);
return true;
}
}
const replaced = translateFragment(raw);
processedText.set(node, replaced);
if (replaced !== raw) {
node.nodeValue = replaced;
return true;
}
return false;
}
function translateAttr(el, attrName, map, fallbackToTextMap = true) {
const value = el.getAttribute(attrName);
if (!value) return false;
const key = normalizeSpaces(decodeHtml(value));
const mapped = map.get(key) || (fallbackToTextMap ? TEXT_MAP.get(key) : null) || translateFragment(value);
if (mapped && mapped !== value) {
el.setAttribute(attrName, mapped);
return true;
}
return false;
}
function replaceKnownInputs(el) {
let changed = false;
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) {
changed = translateAttr(el, 'placeholder', PLACEHOLDER_MAP) || changed;
}
if (el instanceof HTMLButtonElement || (el instanceof HTMLInputElement && ['button', 'submit'].includes(el.type))) {
const value = el.getAttribute('value');
if (value) {
const mapped = TEXT_MAP.get(normalizeSpaces(value)) || translateFragment(value);
if (mapped && mapped !== value) {
el.setAttribute('value', mapped);
changed = true;
}
}
}
return changed;
}
function processElement(el) {
if (!(el instanceof HTMLElement)) return false;
if (el.closest('script, style, textarea, code, pre')) return false;
const fingerprint = [
el.getAttribute('title') || '',
el.getAttribute('placeholder') || '',
el.getAttribute('aria-label') || '',
el.getAttribute('value') || '',
el.childElementCount === 0 ? (el.textContent || '').trim() : ''
].join('||');
if (processedElements.get(el) === fingerprint) return false;
let changed = false;
changed = translateAttr(el, 'title', TITLE_MAP) || changed;
changed = translateAttr(el, 'placeholder', PLACEHOLDER_MAP) || changed;
const ariaLabel = el.getAttribute('aria-label');
if (ariaLabel) {
for (const [from, to] of ARIA_LABEL_MAP.entries()) {
if (ariaLabel.startsWith(from)) {
el.setAttribute('aria-label', ariaLabel.replace(from, to));
changed = true;
break;
}
}
}
changed = replaceKnownInputs(el) || changed;
const finalFingerprint = [
el.getAttribute('title') || '',
el.getAttribute('placeholder') || '',
el.getAttribute('aria-label') || '',
el.getAttribute('value') || '',
el.childElementCount === 0 ? (el.textContent || '').trim() : ''
].join('||');
processedElements.set(el, finalFingerprint);
return changed;
}
function walk(root) {
if (!root) return 0;
let count = 0;
if (root.nodeType === Node.TEXT_NODE) return processTextNode(root) ? 1 : 0;
if (root.nodeType === Node.ELEMENT_NODE && processElement(root)) count += 1;
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
let current = walker.currentNode;
while (current) {
if (current.nodeType === Node.TEXT_NODE) count += processTextNode(current) ? 1 : 0;
else if (current.nodeType === Node.ELEMENT_NODE) count += processElement(current) ? 1 : 0;
current = walker.nextNode();
}
return count;
}
function injectDebugBadge() {
if (document.getElementById('hindsight-zh-debug')) return;
const badge = document.createElement('div');
badge.id = 'hindsight-zh-debug';
badge.textContent = 'Hindsight 中文脚本已加载';
badge.style.cssText = [
'position:fixed','right:12px','bottom:12px','z-index:2147483647','background:#16a34a','color:#fff','padding:6px 10px','border-radius:999px','font-size:12px','font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif','box-shadow:0 4px 14px rgba(0,0,0,.18)','opacity:.92','pointer-events:none'
].join(';');
document.body.appendChild(badge);
setTimeout(() => badge.remove(), 2600);
}
function scheduleSweep(reason) {
if (scheduled) return;
scheduled = true;
requestAnimationFrame(() => {
scheduled = false;
const translated = walk(document.documentElement);
if (translated > 0) log(reason, translated);
});
}
function startObserver() {
if (observerStarted) return;
observerStarted = true;
const observer = new MutationObserver((mutations) => {
let shouldSweep = false;
for (const mutation of mutations) {
if (mutation.type === 'characterData') {
if (processTextNode(mutation.target)) shouldSweep = true;
continue;
}
if (mutation.type === 'attributes' && mutation.target instanceof HTMLElement) {
if (processElement(mutation.target)) shouldSweep = true;
}
if (mutation.addedNodes && mutation.addedNodes.length > 0) shouldSweep = true;
}
if (shouldSweep) scheduleSweep('mutation');
});
observer.observe(document.documentElement, {
subtree: true,
childList: true,
characterData: true,
attributes: true,
attributeFilter: ['title', 'placeholder', 'aria-label', 'value']
});
}
function boot() {
markActive();
walk(document.documentElement);
if (document.body) injectDebugBadge();
else document.addEventListener('DOMContentLoaded', injectDebugBadge, { once: true });
startObserver();
window.addEventListener('load', () => scheduleSweep('window.load'), { once: true });
setTimeout(() => scheduleSweep('600ms'), 600);
setTimeout(() => scheduleSweep('1800ms'), 1800);
setTimeout(() => scheduleSweep('3500ms'), 3500);
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, { once: true });
else boot();
})();
hindsight-zh.user.zip (17.7 KB)
4 个帖子 - 2 位参与者