feat: initial public release (MAESTRO)

This commit is contained in:
oss-sync
2026-06-03 05:08:00 +00:00
commit f5c7666f6b
823 changed files with 184150 additions and 0 deletions
+185
View File
@@ -0,0 +1,185 @@
// docs.ts — ツール詳細ドキュメント参照用ツール
//
// リポジトリ内 docs/tools/{name}.md を読み込んで返す。
// ワークスペース外の固定パスから読むため、Read ツールでは到達できない。
// Tool description にこのツールへのポインタを書いておくと、
// 詳細な使い方を必要に応じてエージェントが取得できる。
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { ToolDef } from '../../llm/openai-compat.js';
import type { ToolContext, ToolResult } from './core.js';
import { logger } from '../../logger.js';
type McpToolLookup = (serverId: string, toolName: string) => { description: string | null; input_schema: string | null } | null;
let _mcpLookup: McpToolLookup | null = null;
export function setMcpToolLookup(fn: McpToolLookup | null): void {
_mcpLookup = fn;
}
// dist/engine/tools/docs.js または src/engine/tools/docs.ts から
// リポジトリルートを解決し、docs/tools/ を指す
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
const DOCS_DIR = path.join(REPO_ROOT, 'docs', 'tools');
// 関連ツールが同じ doc を参照できるようエイリアスを定義
// キー・値ともに小文字
const TOOL_DOC_ALIASES: Record<string, string> = {
// checklist.md にまとめる
createchecklist: 'checklist',
checkitem: 'checklist',
getchecklist: 'checklist',
// searchknowledge.md にまとめる
listnamespaces: 'searchknowledge',
listdocuments: 'searchknowledge',
ingestdocument: 'searchknowledge',
ingeststatus: 'searchknowledge',
// x.ts ツールをまとめる
xuserposts: 'xsearch',
xpostdetail: 'xsearch',
xfetchcardmedia: 'xsearch',
// youtube.ts をまとめる
searchyoutube: 'getyoutubetranscript',
// maps.ts をまとめる
getdirections: 'searchplaces',
reversegeocode: 'searchplaces',
// office.ts をまとめる
readpdf: 'office',
readexcel: 'office',
readdocx: 'office',
readpptx: 'office',
pdftoimages: 'office',
splitexcelsheets: 'office',
splitdocxsections: 'office',
// pieces.ts をまとめる
getpiece: 'listpieces',
createpiece: 'listpieces',
updatepiece: 'listpieces',
// ms-learn.ts をまとめる
fetchmicrosoftlearn: 'searchmicrosoftlearn',
searchmicrosoftlearncache: 'searchmicrosoftlearn',
refreshmicrosoftlearncache: 'searchmicrosoftlearn',
// browser.ts: InteractiveBrowse / BrowseWithSession は browseweb.md にまとめる
interactivebrowse: 'browseweb',
browsewithsession: 'browseweb',
// ssh.ts をまとめる
sshexec: 'ssh-tools',
sshupload: 'ssh-tools',
sshdownload: 'ssh-tools',
sshlistconnections: 'ssh-tools',
// ssh-console.ts をまとめる
sshconsoleensure: 'ssh-console-tools',
sshconsolesend: 'ssh-console-tools',
sshconsolesnapshot: 'ssh-console-tools',
// slide.ts をまとめる
settheme: 'slide',
addslide: 'slide',
buildpptx: 'slide',
resetslides: 'slide',
// notes.ts をまとめる
searchnotes: 'notes',
readnote: 'notes',
writenote: 'notes',
};
const READ_TOOL_DOC_DEF: ToolDef = {
type: 'function',
function: {
name: 'ReadToolDoc',
description:
'ツールの詳細な使い方ドキュメントを読み込む。各ツールの description は概要のみで、詳細な手順や例が必要なときはこれを呼ぶ。'
+ 'docs/tools/{name}.md(リポジトリ内固定パス)を参照する。',
parameters: {
type: 'object',
properties: {
name: {
type: 'string',
description: '読みたいツール名(例: "BrowseWeb", "SearchKnowledge"',
},
},
required: ['name'],
},
},
};
export const TOOL_DEFS: Record<string, ToolDef> = {
ReadToolDoc: READ_TOOL_DOC_DEF,
};
export async function executeTool(
name: string,
input: Record<string, unknown>,
_ctx: ToolContext,
): Promise<ToolResult | null> {
if (name !== 'ReadToolDoc') return null;
const toolName = input['name'] as string | undefined;
if (!toolName || typeof toolName !== 'string') {
return { output: 'ReadToolDoc error: name パラメータが必要です', isError: true };
}
// MCP ツール名 (mcp__<serverId>__<toolName>) の場合はキャッシュから返す
if (toolName.startsWith('mcp__')) {
// Lazy-import to avoid a hard dependency on mcp module at module-load time.
const { parseToolName } = await import('../../mcp/tool-adapter.js');
const parsed = parseToolName(toolName);
if (!parsed) {
return { output: `ReadToolDoc: 不正な MCP ツール名 "${toolName}"`, isError: true };
}
if (!_mcpLookup) {
return { output: 'ReadToolDoc: MCP サブシステムが初期化されていません', isError: true };
}
const row = _mcpLookup(parsed.serverId, parsed.toolName);
if (!row) {
return { output: `ReadToolDoc: ${toolName} のキャッシュ情報がありません`, isError: false };
}
let schemaBlock = '';
if (row.input_schema) {
try {
const schema = JSON.parse(row.input_schema);
schemaBlock = `\n\n## Input schema\n\n\`\`\`json\n${JSON.stringify(schema, null, 2)}\n\`\`\``;
} catch {
schemaBlock = `\n\n## Input schema (raw)\n\n\`\`\`\n${row.input_schema}\n\`\`\``;
}
}
return {
output: `# ${toolName}\n\n${row.description ?? '(no description)'}${schemaBlock}`,
isError: false,
};
}
// パストラバーサル防止: 英数字とハイフン・アンダースコアのみ許可
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(toolName)) {
return { output: `ReadToolDoc error: 不正なツール名 "${toolName}"`, isError: true };
}
const lowerName = toolName.toLowerCase();
const resolvedName = TOOL_DOC_ALIASES[lowerName] ?? lowerName;
const docPath = path.join(DOCS_DIR, `${resolvedName}.md`);
try {
const content = await fs.promises.readFile(docPath, 'utf-8');
return { output: content, isError: false };
} catch (e: any) {
if (e.code === 'ENOENT') {
// 利用可能なドキュメント一覧を返す
try {
const files = await fs.promises.readdir(DOCS_DIR);
const available = files
.filter((f) => f.endsWith('.md'))
.map((f) => f.replace(/\.md$/, ''))
.sort();
return {
output: `ReadToolDoc: "${toolName}" のドキュメントは存在しません。\n利用可能なドキュメント:\n${available.map((n) => `- ${n}`).join('\n')}`,
isError: true,
};
} catch {
return { output: `ReadToolDoc: "${toolName}" のドキュメントは存在しません。`, isError: true };
}
}
logger.warn(`[ReadToolDoc] failed to read ${docPath}: ${e.message}`);
return { output: `ReadToolDoc error: ${e.message}`, isError: true };
}
}