@ryuenn3123/agentic-senior-core 6.10.0 → 6.11.1

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.
Files changed (24) hide show
  1. package/.agents/plugins/agentic-senior-core/.codex-plugin/plugin.json +1 -1
  2. package/.agents/plugins/agentic-senior-core/hooks/lib/known-stub-patterns.json +29 -0
  3. package/.agents/plugins/agentic-senior-core/hooks/lib/known-ui-slop-patterns.json +15 -0
  4. package/.agents/plugins/agentic-senior-core/hooks/post-edit-enforce.js +201 -32
  5. package/.agents/plugins/agentic-senior-core/hooks.json +23 -22
  6. package/.agents/plugins/agentic-senior-core/plugin.json +1 -1
  7. package/.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md +5 -1
  8. package/.agents/plugins/agentic-senior-core/skills/asc-add-feature/SKILL.md +6 -6
  9. package/.agents/plugins/agentic-senior-core/skills/asc-audit/SKILL.md +6 -0
  10. package/.agents/plugins/agentic-senior-core/skills/asc-bootstrap/SKILL.md +3 -0
  11. package/.agents/plugins/agentic-senior-core/skills/asc-debt/SKILL.md +15 -5
  12. package/.agents/plugins/agentic-senior-core/skills/asc-refactor/SKILL.md +7 -8
  13. package/.agents/plugins/agentic-senior-core/skills/asc-reference/SKILL.md +4 -10
  14. package/.agents/plugins/agentic-senior-core/skills/asc-review/SKILL.md +6 -5
  15. package/bin/agentic-senior-core.js +0 -8
  16. package/gemini-extension.json +1 -1
  17. package/lib/cli/commands/git-hook-generator.mjs +40 -2
  18. package/package.json +1 -3
  19. package/plugin.yaml +1 -1
  20. package/lib/cli/commands/mcp.mjs +0 -3
  21. package/scripts/mcp-server/constants.mjs +0 -57
  22. package/scripts/mcp-server/tool-registry.mjs +0 -204
  23. package/scripts/mcp-server/tools.mjs +0 -592
  24. package/scripts/mcp-server.mjs +0 -202
@@ -1,592 +0,0 @@
1
- // @ts-check
2
- // @file-size-exception: Standalone MCP dispatcher intentionally keeps copied tool handlers together; Phase 3 adds bounded rule-validation handlers here.
3
-
4
- import { existsSync } from 'node:fs';
5
- import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
6
- import { spawn } from 'node:child_process';
7
- import { dirname, resolve, sep } from 'node:path';
8
- import { createRequire } from 'node:module';
9
- const requireCJS = createRequire(import.meta.url);
10
- const pathUtil = requireCJS('../../hooks/path-util.cjs');
11
- import {
12
- AVAILABLE_TEST_SUITES,
13
- DEFAULT_FETCH_MAX_CHARS,
14
- DEFAULT_FETCH_TIMEOUT_MS,
15
- DEFAULT_TREND_WINDOW_DAYS,
16
- INTERNAL_SCRIPT_PATHS,
17
- MAX_FETCH_MAX_CHARS,
18
- MAX_TREND_PACKAGES,
19
- PACKAGE_VERSION,
20
- REPOSITORY_ROOT,
21
- STATE_DIRECTORY,
22
- TEST_SUITE_ARGS,
23
- } from './constants.mjs';
24
-
25
- const RULES_DIRECTORY = resolve(REPOSITORY_ROOT, '.agent-context', 'rules');
26
- const RULE_SECTION_HEADING_PATTERN = /^##\s+([A-Z]+-\d{3,4}(?:-[A-Z])?):\s+(.+)$/gm;
27
- const RULE_ID_INPUT_PATTERN = /^[A-Z]+-\d{3,4}(?:-[A-Z])?$/;
28
-
29
- function buildCommandOutput(commandLabel, commandArguments, exitCode, stdoutContent, stderrContent) {
30
- const outputSections = [
31
- `Command: node ${commandArguments.join(' ')}`,
32
- `Exit code: ${exitCode}`,
33
- ];
34
-
35
- if (stdoutContent.trim().length > 0) {
36
- outputSections.push(`STDOUT:\n${stdoutContent.trimEnd()}`);
37
- }
38
-
39
- if (stderrContent.trim().length > 0) {
40
- outputSections.push(`STDERR:\n${stderrContent.trimEnd()}`);
41
- }
42
-
43
- return [
44
- `[${commandLabel}]`,
45
- outputSections.join('\n\n'),
46
- ].join('\n\n');
47
- }
48
-
49
- function buildJsonResult(payload, isError = false) {
50
- return {
51
- content: [
52
- {
53
- type: 'text',
54
- text: JSON.stringify(payload, null, 2),
55
- },
56
- ],
57
- isError,
58
- };
59
- }
60
-
61
- function normalizeRuleId(rawRuleId) {
62
- return typeof rawRuleId === 'string' ? rawRuleId.trim().toUpperCase() : '';
63
- }
64
-
65
- function normalizeRuleIdList(rawRuleIds) {
66
- if (!Array.isArray(rawRuleIds)) {
67
- return [];
68
- }
69
-
70
- return Array.from(new Set(rawRuleIds.map(normalizeRuleId).filter(Boolean)));
71
- }
72
-
73
- async function buildRuleSectionIndex() {
74
- const index = new Map();
75
- const filenames = (await readdir(RULES_DIRECTORY))
76
- .filter((filename) => filename.endsWith('.md') && !filename.endsWith('.candidate.md'))
77
- .sort();
78
-
79
- for (const filename of filenames) {
80
- const relativePath = `.agent-context/rules/${filename}`;
81
- const sourceText = await readFile(resolve(RULES_DIRECTORY, filename), 'utf8');
82
- const matches = [...sourceText.matchAll(RULE_SECTION_HEADING_PATTERN)];
83
-
84
- for (let matchIndex = 0; matchIndex < matches.length; matchIndex += 1) {
85
- const match = matches[matchIndex];
86
- const nextMatch = matches[matchIndex + 1];
87
- const sectionStart = match.index || 0;
88
- const sectionEnd = nextMatch?.index ?? sourceText.length;
89
- const ruleId = match[1];
90
- index.set(ruleId, {
91
- ruleId,
92
- title: match[2].trim(),
93
- path: relativePath,
94
- content: sourceText.slice(sectionStart, sectionEnd).trim(),
95
- });
96
- }
97
- }
98
-
99
- return index;
100
- }
101
-
102
- async function runLookupRuleTool(toolArguments = {}) {
103
- const ruleId = normalizeRuleId(toolArguments.ruleId);
104
- if (!RULE_ID_INPUT_PATTERN.test(ruleId)) {
105
- return buildJsonResult({
106
- error: 'ruleId must use the stable <PREFIX>-NNN format.',
107
- input: toolArguments.ruleId || null,
108
- }, true);
109
- }
110
-
111
- const ruleIndex = await buildRuleSectionIndex();
112
- const ruleEntry = ruleIndex.get(ruleId);
113
- if (!ruleEntry) {
114
- return buildJsonResult({
115
- error: `Unknown rule ID: ${ruleId}`,
116
- ruleId,
117
- knownRuleCount: ruleIndex.size,
118
- }, true);
119
- }
120
-
121
- return buildJsonResult({
122
- found: true,
123
- ...ruleEntry,
124
- });
125
- }
126
-
127
- async function runValidateAgainstRulesTool(toolArguments = {}) {
128
- const ruleIds = normalizeRuleIdList(toolArguments.ruleIds);
129
- const ruleIndex = await buildRuleSectionIndex();
130
- const invalidFormatIds = ruleIds.filter((ruleId) => !RULE_ID_INPUT_PATTERN.test(ruleId));
131
- const unknownRuleIds = ruleIds.filter((ruleId) => RULE_ID_INPUT_PATTERN.test(ruleId) && !ruleIndex.has(ruleId));
132
- const resolvedRules = ruleIds
133
- .filter((ruleId) => ruleIndex.has(ruleId))
134
- .map((ruleId) => {
135
- const ruleEntry = ruleIndex.get(ruleId);
136
- return {
137
- ruleId,
138
- title: ruleEntry.title,
139
- path: ruleEntry.path,
140
- };
141
- });
142
- const passed = ruleIds.length > 0 && invalidFormatIds.length === 0 && unknownRuleIds.length === 0;
143
-
144
- return buildJsonResult({
145
- passed,
146
- checkedAt: new Date().toISOString(),
147
- summary: typeof toolArguments.summary === 'string' ? toolArguments.summary.trim() || null : null,
148
- ruleCount: ruleIds.length,
149
- resolvedRules,
150
- invalidFormatIds,
151
- unknownRuleIds,
152
- }, !passed);
153
- }
154
-
155
- async function runAuditComplianceTool(toolArguments = {}) {
156
- const validationResult = await runValidateAgainstRulesTool(toolArguments);
157
- const validationPayload = JSON.parse(validationResult.content[0].text);
158
- const scope = typeof toolArguments.scope === 'string' ? toolArguments.scope.trim().toLowerCase() : '';
159
- const warnings = [];
160
-
161
- if (!scope) {
162
- warnings.push({
163
- kind: 'scope.missing',
164
- detail: 'Provide scope when checking whether cited rules match a changed boundary.',
165
- });
166
- }
167
-
168
- return buildJsonResult({
169
- auditName: 'mcp-audit-compliance',
170
- reportVersion: '1.0.0',
171
- generatedAt: new Date().toISOString(),
172
- scope: scope || null,
173
- passed: validationPayload.passed,
174
- failureCount: validationPayload.passed ? 0 : validationPayload.invalidFormatIds.length + validationPayload.unknownRuleIds.length,
175
- warnings,
176
- ruleValidation: validationPayload,
177
- }, !validationPayload.passed);
178
- }
179
-
180
- function normalizePlainText(rawText) {
181
- return rawText
182
- .replace(/<script[\s\S]*?<\/script>/gi, ' ')
183
- .replace(/<style[\s\S]*?<\/style>/gi, ' ')
184
- .replace(/<[^>]+>/g, ' ')
185
- .replace(/&nbsp;/gi, ' ')
186
- .replace(/&amp;/gi, '&')
187
- .replace(/&lt;/gi, '<')
188
- .replace(/&gt;/gi, '>')
189
- .replace(/\s+/g, ' ')
190
- .trim();
191
- }
192
-
193
- function extractQuerySnippets(textContent, queryText) {
194
- const normalizedQuery = String(queryText || '').trim().toLowerCase();
195
- if (!normalizedQuery) {
196
- return [];
197
- }
198
-
199
- const normalizedContent = String(textContent || '');
200
- const normalizedLowerContent = normalizedContent.toLowerCase();
201
- const snippets = [];
202
- let searchStartIndex = 0;
203
-
204
- while (snippets.length < 5) {
205
- const matchedIndex = normalizedLowerContent.indexOf(normalizedQuery, searchStartIndex);
206
- if (matchedIndex === -1) {
207
- break;
208
- }
209
-
210
- const contextRadius = 180;
211
- const snippetStart = Math.max(0, matchedIndex - contextRadius);
212
- const snippetEnd = Math.min(normalizedContent.length, matchedIndex + normalizedQuery.length + contextRadius);
213
- const prefix = snippetStart > 0 ? '...' : '';
214
- const suffix = snippetEnd < normalizedContent.length ? '...' : '';
215
- snippets.push(`${prefix}${normalizedContent.slice(snippetStart, snippetEnd).trim()}${suffix}`);
216
- searchStartIndex = matchedIndex + normalizedQuery.length;
217
- }
218
-
219
- return snippets;
220
- }
221
-
222
- async function fetchWithTimeout(targetUrl, timeoutMs) {
223
- const fetchController = new AbortController();
224
- const timeoutHandle = setTimeout(() => fetchController.abort(), timeoutMs);
225
-
226
- try {
227
- return await fetch(targetUrl, {
228
- signal: fetchController.signal,
229
- headers: {
230
- 'User-Agent': `agentic-senior-core/${PACKAGE_VERSION}`,
231
- },
232
- });
233
- } finally {
234
- clearTimeout(timeoutHandle);
235
- }
236
- }
237
-
238
- async function runResearchFetchTool(toolArguments = {}) {
239
- const targetUrl = String(toolArguments.url || '').trim();
240
- const queryText = typeof toolArguments.query === 'string' ? toolArguments.query.trim() : '';
241
- const maxCharsInput = Number(toolArguments.maxChars);
242
- const maxChars = Number.isFinite(maxCharsInput)
243
- ? Math.max(200, Math.min(MAX_FETCH_MAX_CHARS, Math.floor(maxCharsInput)))
244
- : DEFAULT_FETCH_MAX_CHARS;
245
-
246
- if (!/^https?:\/\//i.test(targetUrl)) {
247
- return buildJsonResult({
248
- error: 'Invalid url. Provide absolute HTTP/HTTPS URL.',
249
- input: targetUrl,
250
- }, true);
251
- }
252
-
253
- try {
254
- const startedAt = new Date().toISOString();
255
- const fetchResponse = await fetchWithTimeout(targetUrl, DEFAULT_FETCH_TIMEOUT_MS);
256
- const rawBody = await fetchResponse.text();
257
- const plainTextBody = normalizePlainText(rawBody);
258
- const querySnippets = queryText ? extractQuerySnippets(plainTextBody, queryText) : [];
259
- const selectedContent = querySnippets.length > 0
260
- ? querySnippets.join('\n\n')
261
- : plainTextBody.slice(0, maxChars);
262
-
263
- return buildJsonResult({
264
- source: {
265
- url: targetUrl,
266
- status: fetchResponse.status,
267
- ok: fetchResponse.ok,
268
- fetchedAt: new Date().toISOString(),
269
- requestedAt: startedAt,
270
- contentType: fetchResponse.headers.get('content-type') || null,
271
- },
272
- query: queryText || null,
273
- excerptCount: querySnippets.length,
274
- truncated: !queryText && plainTextBody.length > selectedContent.length,
275
- content: selectedContent,
276
- }, !fetchResponse.ok);
277
- } catch (error) {
278
- return buildJsonResult({
279
- error: error instanceof Error ? error.message : String(error),
280
- source: targetUrl,
281
- }, true);
282
- }
283
- }
284
-
285
- async function runTrendSnapshotTool(toolArguments = {}) {
286
- const packageInputs = Array.isArray(toolArguments.packages)
287
- ? toolArguments.packages.filter((packageName) => typeof packageName === 'string' && packageName.trim().length > 0)
288
- : [];
289
- const packageNames = Array.from(new Set(packageInputs.map((packageName) => packageName.trim()))).slice(0, MAX_TREND_PACKAGES);
290
- const windowDaysInput = Number(toolArguments.windowDays);
291
- const windowDays = Number.isFinite(windowDaysInput)
292
- ? Math.max(1, Math.min(3650, Math.floor(windowDaysInput)))
293
- : DEFAULT_TREND_WINDOW_DAYS;
294
-
295
- if (packageNames.length === 0) {
296
- return buildJsonResult({
297
- error: 'packages[] must include at least one package name.',
298
- }, true);
299
- }
300
-
301
- const nowTimestamp = Date.now();
302
- const windowStartTimestamp = nowTimestamp - (windowDays * 24 * 60 * 60 * 1000);
303
- const packageReports = [];
304
-
305
- for (const packageName of packageNames) {
306
- const registryUrl = `https://registry.npmjs.org/${encodeURIComponent(packageName)}`;
307
-
308
- try {
309
- const response = await fetchWithTimeout(registryUrl, DEFAULT_FETCH_TIMEOUT_MS);
310
- if (!response.ok) {
311
- packageReports.push({
312
- package: packageName,
313
- source: registryUrl,
314
- status: response.status,
315
- error: `Registry request failed with HTTP ${response.status}`,
316
- });
317
- continue;
318
- }
319
-
320
- const registryPayload = await response.json();
321
- const latestVersion = registryPayload?.['dist-tags']?.latest || null;
322
- const releaseTimes = Object.entries(registryPayload?.time || {})
323
- .filter(([versionName, publishedAt]) => {
324
- if (versionName === 'created' || versionName === 'modified') {
325
- return false;
326
- }
327
-
328
- return typeof publishedAt === 'string' && Number.isFinite(Date.parse(publishedAt));
329
- })
330
- .map(([versionName, publishedAt]) => ({
331
- version: versionName,
332
- publishedAt,
333
- publishedAtMs: Date.parse(publishedAt),
334
- }))
335
- .sort((leftEntry, rightEntry) => rightEntry.publishedAtMs - leftEntry.publishedAtMs);
336
-
337
- const releasesInWindow = releaseTimes.filter((releaseEntry) => releaseEntry.publishedAtMs >= windowStartTimestamp);
338
- const latestPublishedAt = latestVersion && typeof registryPayload?.time?.[latestVersion] === 'string'
339
- ? registryPayload.time[latestVersion]
340
- : registryPayload?.time?.modified || null;
341
-
342
- packageReports.push({
343
- package: packageName,
344
- source: registryUrl,
345
- latestVersion,
346
- latestPublishedAt,
347
- releasesInWindow: releasesInWindow.length,
348
- recentReleases: releasesInWindow.slice(0, 5).map((releaseEntry) => ({
349
- version: releaseEntry.version,
350
- publishedAt: releaseEntry.publishedAt,
351
- })),
352
- });
353
- } catch (error) {
354
- packageReports.push({
355
- package: packageName,
356
- source: registryUrl,
357
- error: error instanceof Error ? error.message : String(error),
358
- });
359
- }
360
- }
361
-
362
- const errorCount = packageReports.filter((packageReport) => typeof packageReport.error === 'string').length;
363
-
364
- return buildJsonResult({
365
- generatedAt: new Date().toISOString(),
366
- windowDays,
367
- packageCount: packageNames.length,
368
- errorCount,
369
- packages: packageReports,
370
- citation: {
371
- source: 'npm registry public API',
372
- fetchedAt: new Date().toISOString(),
373
- },
374
- }, errorCount > 0);
375
- }
376
-
377
- function resolveStatePath(relativeStatePath) {
378
- const normalizedRelativePath = String(relativeStatePath || '').replace(/\\/g, '/').replace(/^\/+/, '').trim();
379
- if (!normalizedRelativePath) {
380
- throw new Error('path is required and must be relative to .agent-context/state');
381
- }
382
-
383
- if (normalizedRelativePath === 'workflow-gate.json') {
384
- return {
385
- normalizedRelativePath,
386
- resolvedStatePath: pathUtil.getWorkflowGatePath(REPOSITORY_ROOT),
387
- };
388
- }
389
-
390
- const resolvedStatePath = resolve(STATE_DIRECTORY, normalizedRelativePath);
391
- const stateRootPrefix = `${STATE_DIRECTORY}${sep}`;
392
- if (resolvedStatePath !== STATE_DIRECTORY && !resolvedStatePath.startsWith(stateRootPrefix)) {
393
- throw new Error('path traversal is not allowed outside .agent-context/state');
394
- }
395
-
396
- return {
397
- normalizedRelativePath,
398
- resolvedStatePath,
399
- };
400
- }
401
-
402
- async function runStateReadTool(toolArguments = {}) {
403
- try {
404
- const { normalizedRelativePath, resolvedStatePath } = resolveStatePath(toolArguments.path);
405
- const fileContent = await readFile(resolvedStatePath, 'utf8');
406
-
407
- return buildJsonResult({
408
- path: normalizedRelativePath,
409
- readAt: new Date().toISOString(),
410
- bytes: Buffer.byteLength(fileContent, 'utf8'),
411
- content: fileContent,
412
- });
413
- } catch (error) {
414
- return buildJsonResult({
415
- error: error instanceof Error ? error.message : String(error),
416
- path: toolArguments.path || null,
417
- }, true);
418
- }
419
- }
420
-
421
- async function runStateWriteTool(toolArguments = {}) {
422
- const writeMode = toolArguments.mode === 'append' ? 'append' : 'overwrite';
423
- const contentToWrite = typeof toolArguments.content === 'string' ? toolArguments.content : '';
424
-
425
- if (typeof toolArguments.content !== 'string') {
426
- return buildJsonResult({
427
- error: 'content must be a string.',
428
- }, true);
429
- }
430
-
431
- try {
432
- const { normalizedRelativePath, resolvedStatePath } = resolveStatePath(toolArguments.path);
433
- await mkdir(dirname(resolvedStatePath), { recursive: true });
434
-
435
- if (writeMode === 'append') {
436
- await writeFile(resolvedStatePath, contentToWrite, { encoding: 'utf8', flag: 'a' });
437
- } else {
438
- await writeFile(resolvedStatePath, contentToWrite, 'utf8');
439
- }
440
-
441
- return buildJsonResult({
442
- path: normalizedRelativePath,
443
- wroteAt: new Date().toISOString(),
444
- mode: writeMode,
445
- bytesWritten: Buffer.byteLength(contentToWrite, 'utf8'),
446
- });
447
- } catch (error) {
448
- return buildJsonResult({
449
- error: error instanceof Error ? error.message : String(error),
450
- path: toolArguments.path || null,
451
- mode: writeMode,
452
- }, true);
453
- }
454
- }
455
-
456
- function runNodeCommand(commandLabel, commandArguments) {
457
- return new Promise((resolveResult) => {
458
- const childProcess = spawn(process.execPath, commandArguments, {
459
- cwd: REPOSITORY_ROOT,
460
- env: process.env,
461
- });
462
-
463
- let stdoutContent = '';
464
- let stderrContent = '';
465
-
466
- childProcess.stdout.on('data', (chunk) => {
467
- stdoutContent += chunk.toString('utf8');
468
- });
469
-
470
- childProcess.stderr.on('data', (chunk) => {
471
- stderrContent += chunk.toString('utf8');
472
- });
473
-
474
- childProcess.on('error', (error) => {
475
- resolveResult({
476
- content: [
477
- {
478
- type: 'text',
479
- text: `[${commandLabel}] Failed to start command: ${error.message}`,
480
- },
481
- ],
482
- isError: true,
483
- });
484
- });
485
-
486
- childProcess.on('close', (exitCode) => {
487
- const normalizedExitCode = typeof exitCode === 'number' ? exitCode : 1;
488
- resolveResult({
489
- content: [
490
- {
491
- type: 'text',
492
- text: buildCommandOutput(
493
- commandLabel,
494
- commandArguments,
495
- normalizedExitCode,
496
- stdoutContent,
497
- stderrContent
498
- ),
499
- },
500
- ],
501
- isError: normalizedExitCode !== 0,
502
- });
503
- });
504
- });
505
- }
506
-
507
- export async function executeToolCall(toolName, toolArguments = {}) {
508
- if (toolName === 'validate') {
509
- if (!existsSync(INTERNAL_SCRIPT_PATHS.validate)) {
510
- return buildJsonResult({
511
- error: 'validate tool is unavailable because scripts/validate.mjs is missing in this workspace.',
512
- }, true);
513
- }
514
-
515
- return runNodeCommand('validate', ['./scripts/validate.mjs']);
516
- }
517
-
518
- if (toolName === 'test') {
519
- if (AVAILABLE_TEST_SUITES.length === 0) {
520
- return buildJsonResult({
521
- error: 'test tool is unavailable because the managed test suites are not present in this workspace.',
522
- }, true);
523
- }
524
-
525
- const defaultSuite = AVAILABLE_TEST_SUITES[0];
526
- const requestedSuite = typeof toolArguments.suite === 'string'
527
- ? toolArguments.suite
528
- : defaultSuite;
529
- const selectedSuite = AVAILABLE_TEST_SUITES.includes(requestedSuite)
530
- ? requestedSuite
531
- : defaultSuite;
532
- return runNodeCommand(`test:${selectedSuite}`, TEST_SUITE_ARGS[selectedSuite]);
533
- }
534
-
535
- if (toolName === 'release_gate') {
536
- if (!existsSync(INTERNAL_SCRIPT_PATHS.release_gate)) {
537
- return buildJsonResult({
538
- error: 'release_gate tool is unavailable because scripts/release-gate.mjs is missing in this workspace.',
539
- }, true);
540
- }
541
-
542
- return runNodeCommand('release_gate', ['./scripts/release-gate.mjs']);
543
- }
544
-
545
- if (toolName === 'forbidden_content_check') {
546
- if (!existsSync(INTERNAL_SCRIPT_PATHS.forbidden_content_check)) {
547
- return buildJsonResult({
548
- error: 'forbidden_content_check tool is unavailable because scripts/forbidden-content-check.mjs is missing in this workspace.',
549
- }, true);
550
- }
551
-
552
- return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
553
- }
554
-
555
- if (toolName === 'lookup_rule') {
556
- return runLookupRuleTool(toolArguments);
557
- }
558
-
559
- if (toolName === 'validate_against_rules') {
560
- return runValidateAgainstRulesTool(toolArguments);
561
- }
562
-
563
- if (toolName === 'audit_compliance') {
564
- return runAuditComplianceTool(toolArguments);
565
- }
566
-
567
- if (toolName === 'research_fetch') {
568
- return runResearchFetchTool(toolArguments);
569
- }
570
-
571
- if (toolName === 'trend_snapshot') {
572
- return runTrendSnapshotTool(toolArguments);
573
- }
574
-
575
- if (toolName === 'state_read') {
576
- return runStateReadTool(toolArguments);
577
- }
578
-
579
- if (toolName === 'state_write') {
580
- return runStateWriteTool(toolArguments);
581
- }
582
-
583
- return {
584
- content: [
585
- {
586
- type: 'text',
587
- text: `Unknown tool: ${toolName}`,
588
- },
589
- ],
590
- isError: true,
591
- };
592
- }