Files
my-pi/pi-tool-search/extensions/config.ts
T
云服务部-叶林立andDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 56cbc83296 refactor: 移除 context-mode,Chrome 快照改为直接返回
context-mode 的 ctx_execute 系工具以真实 shell 执行且权限为 allow,绕过了
bash 策略与 protectedWrites;其每轮注入、独立 MCP 子进程与 skills 也与组合包
提示词单一所有权冲突。大输出职责已由 pi-overflow(入口截断)与
pi-compaction(压力遮蔽)承担:
- 删除 context-mode 依赖、wrapper/过滤器、skills,以及 ctx_* 的权限、
  tools.jsonc、路由规则、tool-search 常驻与 4 个分组
- better-sqlite3@12 仅为 context-mode 传递依赖,随之移除根 allowScripts
- pi-chrome:按用户决定移除快照隐私规则与 .pi/chrome-context 临时文件机制,
  快照 JSON 直接作为工具结果返回、details 只留小型元数据,超长由 pi-overflow
  截断并用 overflow_query 提取;授权生命周期不变

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-21 20:45:33 -07:00

115 lines
4.0 KiB
TypeScript

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
const TOOL_SEARCH_DIR = join("my-pi", "tool-search");
/**
* Bundle-level `config/` is the single source of truth: the extension reads
* `config/tool-search.json` from inside the installed bundle (resolved
* relative to this source file), never deployed to or migrated from the
* agent directory.
*/
export function getToolSearchConfigPath(): string {
const override = process.env.PI_TOOL_SEARCH_CONFIG_PATH;
if (override) return override;
return fileURLToPath(new URL("../../config/tool-search.json", import.meta.url));
}
/** Disposable catalog cache under the agent dir's `my-pi/tool-search/` tree. */
export function getToolSearchCatalogPath(agentDir: string): string {
return join(agentDir, TOOL_SEARCH_DIR, "catalog-v1.json");
}
export const BUNDLE_TOOL_SEARCH_DEFAULTS = {
alwaysEnabled: [
"codegraph_explore",
"lsp_diagnostics",
"memory_search",
"session_search",
"memory_add",
"memory_replace",
"memory_remove",
"skill_manage",
"context_tree_query",
"overflow_query",
],
showToolSearchFooterStatus: false,
maxActiveGroups: 5,
maxToolsPerGroup: 8,
maxDynamicTools: 28,
groupOverrides: {},
} as const;
export interface ToolSearchConfig {
alwaysEnabled: string[];
showToolSearchFooterStatus: boolean;
maxActiveGroups: number;
maxToolsPerGroup: number;
maxDynamicTools: number;
groupOverrides: Record<string, string[]>;
}
function isObject(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
function positiveInteger(value: unknown, fallback: number): number {
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
}
function stringList(value: unknown): string[] {
if (!Array.isArray(value)) return [];
return [...new Set(value.filter((item): item is string => typeof item === "string" && item.length > 0))];
}
function readGroupOverrides(value: unknown): Record<string, string[]> {
if (!isObject(value)) return {};
const overrides: Record<string, string[]> = {};
for (const [groupId, names] of Object.entries(value)) {
const tools = stringList(names);
if (groupId.trim() && tools.length > 0) overrides[groupId] = tools;
}
return overrides;
}
export function bundleFallbackConfig(): ToolSearchConfig {
return {
alwaysEnabled: [...BUNDLE_TOOL_SEARCH_DEFAULTS.alwaysEnabled],
showToolSearchFooterStatus: BUNDLE_TOOL_SEARCH_DEFAULTS.showToolSearchFooterStatus,
maxActiveGroups: BUNDLE_TOOL_SEARCH_DEFAULTS.maxActiveGroups,
maxToolsPerGroup: BUNDLE_TOOL_SEARCH_DEFAULTS.maxToolsPerGroup,
maxDynamicTools: BUNDLE_TOOL_SEARCH_DEFAULTS.maxDynamicTools,
groupOverrides: {},
};
}
/**
* Read the Tool Search config. Defaults to the bundle-level
* `config/tool-search.json`; tests inject an explicit temp path. A missing,
* unreadable, or non-object file falls back to the bundle defaults.
*/
export function readToolSearchConfig(
configPath: string = getToolSearchConfigPath(),
): ToolSearchConfig {
const fallback = bundleFallbackConfig();
try {
const parsed: unknown = JSON.parse(readFileSync(configPath, "utf8"));
if (!isObject(parsed)) return fallback;
const config = parsed;
return {
alwaysEnabled: Array.isArray(config.alwaysEnabled) ? stringList(config.alwaysEnabled) : fallback.alwaysEnabled,
showToolSearchFooterStatus:
typeof config.showToolSearchFooterStatus === "boolean"
? config.showToolSearchFooterStatus
: fallback.showToolSearchFooterStatus,
maxActiveGroups: positiveInteger(config.maxActiveGroups, fallback.maxActiveGroups),
maxToolsPerGroup: positiveInteger(config.maxToolsPerGroup, fallback.maxToolsPerGroup),
maxDynamicTools: positiveInteger(config.maxDynamicTools, fallback.maxDynamicTools),
groupOverrides: readGroupOverrides(config.groupOverrides),
};
} catch {
return fallback;
}
}