cwtools-shared 0.1.0
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.
- package/dist/generated/mcpTools.d.ts +1112 -0
- package/dist/generated/mcpTools.js +1247 -0
- package/dist/host/diagnostics.d.ts +41 -0
- package/dist/host/diagnostics.js +18 -0
- package/dist/host/filesystem.d.ts +18 -0
- package/dist/host/filesystem.js +2 -0
- package/dist/host/hostServices.d.ts +49 -0
- package/dist/host/hostServices.js +2 -0
- package/dist/host/indexing.d.ts +54 -0
- package/dist/host/indexing.js +2 -0
- package/dist/host/lsp.d.ts +8 -0
- package/dist/host/lsp.js +27 -0
- package/dist/host/readiness.d.ts +11 -0
- package/dist/host/readiness.js +71 -0
- package/dist/host/vanillaCache.d.ts +12 -0
- package/dist/host/vanillaCache.js +56 -0
- package/dist/host/vsCodeHostServices.d.ts +27 -0
- package/dist/host/vsCodeHostServices.js +30 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +41 -0
- package/dist/knowledge/diagnosticRouting.d.ts +13 -0
- package/dist/knowledge/diagnosticRouting.js +57 -0
- package/dist/knowledge/gameKnowledge.d.ts +20 -0
- package/dist/knowledge/gameKnowledge.js +52 -0
- package/dist/knowledge/rules.d.ts +162 -0
- package/dist/knowledge/rules.js +1383 -0
- package/dist/knowledge/workflowHints.d.ts +11 -0
- package/dist/knowledge/workflowHints.js +31 -0
- package/dist/project/knowledge.d.ts +15 -0
- package/dist/project/knowledge.js +209 -0
- package/dist/project/profile.d.ts +45 -0
- package/dist/project/profile.js +177 -0
- package/dist/safety/localisation.d.ts +33 -0
- package/dist/safety/localisation.js +105 -0
- package/dist/safety/paths.d.ts +21 -0
- package/dist/safety/paths.js +122 -0
- package/dist/safety/writes.d.ts +3 -0
- package/dist/safety/writes.js +19 -0
- package/dist/tools/mcpSchema.d.ts +5 -0
- package/dist/tools/mcpSchema.js +19 -0
- package/dist/tools/names.d.ts +6 -0
- package/dist/tools/names.js +51 -0
- package/dist/tools/pdxBlock.d.ts +17 -0
- package/dist/tools/pdxBlock.js +140 -0
- package/dist/tools/registry.d.ts +10 -0
- package/dist/tools/registry.js +2 -0
- package/dist/tools/schema.d.ts +36 -0
- package/dist/tools/schema.js +21 -0
- package/dist/tools/symbols.d.ts +60 -0
- package/dist/tools/symbols.js +625 -0
- package/dist/tools/toolHandlers.d.ts +4 -0
- package/dist/tools/toolHandlers.js +291 -0
- package/package.json +24 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeWorkspaceRoot = normalizeWorkspaceRoot;
|
|
37
|
+
exports.isPathInsideOrEqual = isPathInsideOrEqual;
|
|
38
|
+
exports.resolveWorkspacePath = resolveWorkspacePath;
|
|
39
|
+
exports.isLocalisationRelativePath = isLocalisationRelativePath;
|
|
40
|
+
exports.isScratchRelativePath = isScratchRelativePath;
|
|
41
|
+
exports.validateLocalisationPath = validateLocalisationPath;
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
function normalizeWorkspaceRoot(workspaceRoot) {
|
|
44
|
+
return path.resolve(workspaceRoot);
|
|
45
|
+
}
|
|
46
|
+
function isPathInsideOrEqual(parent, child) {
|
|
47
|
+
const relative = path.relative(path.resolve(parent), path.resolve(child));
|
|
48
|
+
return relative === '' || (!!relative && !relative.startsWith('..') && !path.isAbsolute(relative));
|
|
49
|
+
}
|
|
50
|
+
function resolveWorkspacePath(workspaceRoot, inputPath) {
|
|
51
|
+
const root = normalizeWorkspaceRoot(workspaceRoot);
|
|
52
|
+
const trimmed = inputPath.trim();
|
|
53
|
+
if (!trimmed) {
|
|
54
|
+
return { ok: false, input: inputPath, workspaceRoot: root, reason: 'empty_path' };
|
|
55
|
+
}
|
|
56
|
+
const resolved = path.resolve(root, trimmed);
|
|
57
|
+
if (!isPathInsideOrEqual(root, resolved)) {
|
|
58
|
+
return { ok: false, input: inputPath, workspaceRoot: root, reason: 'outside_workspace' };
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
ok: true,
|
|
62
|
+
input: inputPath,
|
|
63
|
+
workspaceRoot: root,
|
|
64
|
+
resolvedPath: resolved,
|
|
65
|
+
relativePath: path.relative(root, resolved).replace(/\\/g, '/'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function isLocalisationRelativePath(relativePath) {
|
|
69
|
+
const normalized = relativePath.replace(/\\/g, '/').toLowerCase();
|
|
70
|
+
return normalized.startsWith('localisation/')
|
|
71
|
+
|| normalized.startsWith('localisation_synced/')
|
|
72
|
+
|| normalized.startsWith('localization/');
|
|
73
|
+
}
|
|
74
|
+
function isScratchRelativePath(relativePath) {
|
|
75
|
+
const parts = relativePath
|
|
76
|
+
.replace(/\\/g, '/')
|
|
77
|
+
.toLowerCase()
|
|
78
|
+
.split('/');
|
|
79
|
+
return parts.includes('.cwtools') || parts.includes('.cwtools-ai');
|
|
80
|
+
}
|
|
81
|
+
function validateLocalisationPath(workspaceRoot, inputPath) {
|
|
82
|
+
const resolution = resolveWorkspacePath(workspaceRoot, inputPath);
|
|
83
|
+
if (!resolution.ok || !resolution.resolvedPath || !resolution.relativePath) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
reason: 'outside_workspace',
|
|
87
|
+
message: `Path '${inputPath}' is outside the workspace root.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (path.extname(resolution.resolvedPath).toLowerCase() !== '.yml') {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
reason: 'not_yml',
|
|
94
|
+
resolvedPath: resolution.resolvedPath,
|
|
95
|
+
relativePath: resolution.relativePath,
|
|
96
|
+
message: 'write_localisation only works with .yml files.',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (isScratchRelativePath(resolution.relativePath)) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
reason: 'scratch_path',
|
|
103
|
+
resolvedPath: resolution.resolvedPath,
|
|
104
|
+
relativePath: resolution.relativePath,
|
|
105
|
+
message: 'Localisation files must not be written under .cwtools scratch or topic folders.',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (!isLocalisationRelativePath(resolution.relativePath)) {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
reason: 'not_localisation_directory',
|
|
112
|
+
resolvedPath: resolution.resolvedPath,
|
|
113
|
+
relativePath: resolution.relativePath,
|
|
114
|
+
message: 'Localisation files must be written under localisation/, localisation_synced/, or localization/.',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
resolvedPath: resolution.resolvedPath,
|
|
120
|
+
relativePath: resolution.relativePath,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureToolWriteAllowed = ensureToolWriteAllowed;
|
|
4
|
+
const schema_1 = require("../tools/schema");
|
|
5
|
+
const names_1 = require("../tools/names");
|
|
6
|
+
function ensureToolWriteAllowed(host, toolName) {
|
|
7
|
+
if (!(0, names_1.isMcpWriteToolName)(toolName))
|
|
8
|
+
return null;
|
|
9
|
+
if (host.readonlyMode) {
|
|
10
|
+
return (0, schema_1.toolDenied)('read_only', `${toolName} is disabled because the MCP server is running in read-only mode.`);
|
|
11
|
+
}
|
|
12
|
+
if (!host.writesEnabled) {
|
|
13
|
+
return (0, schema_1.toolDenied)('writes_disabled', `${toolName} requires --enable-writes.`);
|
|
14
|
+
}
|
|
15
|
+
if (host.allowedWriteTools && !host.allowedWriteTools.has(toolName)) {
|
|
16
|
+
return (0, schema_1.toolDenied)('tool_not_allowed', `${toolName} is not in the configured write-tool allowlist.`);
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { GeneratedMcpTool, McpToolSchema } from './schema';
|
|
2
|
+
export declare function getGeneratedMcpTools(): readonly GeneratedMcpTool[];
|
|
3
|
+
export declare function listMcpToolSchemas(): McpToolSchema[];
|
|
4
|
+
export declare function getMcpToolSchema(name: string): McpToolSchema | undefined;
|
|
5
|
+
export declare function getMcpToolRegistryMetadata(name: string): GeneratedMcpTool['registry'] | undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGeneratedMcpTools = getGeneratedMcpTools;
|
|
4
|
+
exports.listMcpToolSchemas = listMcpToolSchemas;
|
|
5
|
+
exports.getMcpToolSchema = getMcpToolSchema;
|
|
6
|
+
exports.getMcpToolRegistryMetadata = getMcpToolRegistryMetadata;
|
|
7
|
+
const mcpTools_1 = require("../generated/mcpTools");
|
|
8
|
+
function getGeneratedMcpTools() {
|
|
9
|
+
return mcpTools_1.GENERATED_MCP_TOOLS;
|
|
10
|
+
}
|
|
11
|
+
function listMcpToolSchemas() {
|
|
12
|
+
return mcpTools_1.GENERATED_MCP_TOOLS.map(entry => ({ ...entry.tool }));
|
|
13
|
+
}
|
|
14
|
+
function getMcpToolSchema(name) {
|
|
15
|
+
return mcpTools_1.GENERATED_MCP_TOOLS.find(entry => entry.tool.name === name)?.tool;
|
|
16
|
+
}
|
|
17
|
+
function getMcpToolRegistryMetadata(name) {
|
|
18
|
+
return mcpTools_1.GENERATED_MCP_TOOLS.find(entry => entry.registry.name === name)?.registry;
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const MCP_TOOL_NAMES: readonly ["query_types", "query_rules", "query_cwt_schema", "search_rule_capabilities", "explain_scope", "parse_pdx_fragment", "query_scope", "get_diagnostics", "analyze_diagnostic_error", "query_project_profile", "query_project_knowledge", "query_workspace_index", "explore_pdx_project", "query_localisation_index", "get_pdx_block", "get_completion_at", "document_symbols", "workspace_symbols", "query_definition", "query_definition_by_name", "query_references", "query_scripted_effects", "query_scripted_triggers", "query_enums", "query_static_modifiers", "query_variables", "get_entity_info", "query_shader_symbol", "query_shader_compile_unit", "query_shader_platform_variants", "query_shader_callers", "explain_shader_reachability", "validate_shader", "compare_shader_with_vanilla"];
|
|
2
|
+
export type McpToolName = typeof MCP_TOOL_NAMES[number];
|
|
3
|
+
export declare const MCP_WRITE_TOOL_NAMES: readonly [];
|
|
4
|
+
export declare const MCP_READONLY_TOOL_NAMES: readonly ["query_types", "query_rules", "query_cwt_schema", "search_rule_capabilities", "explain_scope", "parse_pdx_fragment", "query_scope", "get_diagnostics", "analyze_diagnostic_error", "query_project_profile", "query_project_knowledge", "query_workspace_index", "explore_pdx_project", "query_localisation_index", "get_pdx_block", "get_completion_at", "document_symbols", "workspace_symbols", "query_definition", "query_definition_by_name", "query_references", "query_scripted_effects", "query_scripted_triggers", "query_enums", "query_static_modifiers", "query_variables", "get_entity_info", "query_shader_symbol", "query_shader_compile_unit", "query_shader_platform_variants", "query_shader_callers", "explain_shader_reachability", "validate_shader", "compare_shader_with_vanilla"];
|
|
5
|
+
export declare function isMcpToolName(value: string): value is McpToolName;
|
|
6
|
+
export declare function isMcpWriteToolName(value: string): value is typeof MCP_WRITE_TOOL_NAMES[number];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MCP_READONLY_TOOL_NAMES = exports.MCP_WRITE_TOOL_NAMES = exports.MCP_TOOL_NAMES = void 0;
|
|
4
|
+
exports.isMcpToolName = isMcpToolName;
|
|
5
|
+
exports.isMcpWriteToolName = isMcpWriteToolName;
|
|
6
|
+
exports.MCP_TOOL_NAMES = [
|
|
7
|
+
'query_types',
|
|
8
|
+
'query_rules',
|
|
9
|
+
'query_cwt_schema',
|
|
10
|
+
'search_rule_capabilities',
|
|
11
|
+
'explain_scope',
|
|
12
|
+
'parse_pdx_fragment',
|
|
13
|
+
'query_scope',
|
|
14
|
+
'get_diagnostics',
|
|
15
|
+
'analyze_diagnostic_error',
|
|
16
|
+
'query_project_profile',
|
|
17
|
+
'query_project_knowledge',
|
|
18
|
+
'query_workspace_index',
|
|
19
|
+
'explore_pdx_project',
|
|
20
|
+
'query_localisation_index',
|
|
21
|
+
'get_pdx_block',
|
|
22
|
+
'get_completion_at',
|
|
23
|
+
'document_symbols',
|
|
24
|
+
'workspace_symbols',
|
|
25
|
+
'query_definition',
|
|
26
|
+
'query_definition_by_name',
|
|
27
|
+
'query_references',
|
|
28
|
+
'query_scripted_effects',
|
|
29
|
+
'query_scripted_triggers',
|
|
30
|
+
'query_enums',
|
|
31
|
+
'query_static_modifiers',
|
|
32
|
+
'query_variables',
|
|
33
|
+
'get_entity_info',
|
|
34
|
+
'query_shader_symbol',
|
|
35
|
+
'query_shader_compile_unit',
|
|
36
|
+
'query_shader_platform_variants',
|
|
37
|
+
'query_shader_callers',
|
|
38
|
+
'explain_shader_reachability',
|
|
39
|
+
'validate_shader',
|
|
40
|
+
'compare_shader_with_vanilla',
|
|
41
|
+
];
|
|
42
|
+
// The MCP surface is read-only by design: file writes go through the host agent's
|
|
43
|
+
// own environment (Codex / Claude Code), not through this server.
|
|
44
|
+
exports.MCP_WRITE_TOOL_NAMES = [];
|
|
45
|
+
exports.MCP_READONLY_TOOL_NAMES = exports.MCP_TOOL_NAMES;
|
|
46
|
+
function isMcpToolName(value) {
|
|
47
|
+
return exports.MCP_TOOL_NAMES.includes(value);
|
|
48
|
+
}
|
|
49
|
+
function isMcpWriteToolName(value) {
|
|
50
|
+
return exports.MCP_WRITE_TOOL_NAMES.includes(value);
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HostServices } from '../host/hostServices';
|
|
2
|
+
import { type SharedToolResult } from './schema';
|
|
3
|
+
export interface GetPdxBlockArgs {
|
|
4
|
+
file: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GetPdxBlockResult {
|
|
8
|
+
content: string;
|
|
9
|
+
truncated: boolean;
|
|
10
|
+
startLine?: number;
|
|
11
|
+
endLine?: number;
|
|
12
|
+
lineNumberBase: 1;
|
|
13
|
+
source: 'cwtools-lsp-symbols' | 'cwtools-node-block';
|
|
14
|
+
warnings?: string[];
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function getPdxBlockWithHost(host: HostServices, args: GetPdxBlockArgs): Promise<SharedToolResult<GetPdxBlockResult>>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPdxBlockWithHost = getPdxBlockWithHost;
|
|
4
|
+
const paths_1 = require("../safety/paths");
|
|
5
|
+
const schema_1 = require("./schema");
|
|
6
|
+
const symbols_1 = require("./symbols");
|
|
7
|
+
async function getPdxBlockWithHost(host, args) {
|
|
8
|
+
const resolution = (0, paths_1.resolveWorkspacePath)(host.workspaceRoot, args.file);
|
|
9
|
+
if (!resolution.ok || !resolution.resolvedPath) {
|
|
10
|
+
return (0, schema_1.toolDenied)('outside_workspace', `Path '${args.file}' is outside the workspace root.`);
|
|
11
|
+
}
|
|
12
|
+
const read = await host.filesystem.readTextFile(resolution.resolvedPath);
|
|
13
|
+
if (!read.exists) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
status: 'error',
|
|
17
|
+
source: 'cwtools-node-block',
|
|
18
|
+
error: { code: 'file_not_found', message: `File not found: ${args.file}` },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const content = read.hasBom ? read.content.slice(1) : read.content;
|
|
22
|
+
const lines = content.split(/\r?\n/);
|
|
23
|
+
const symbolRange = await resolveSymbolRange(host, resolution.resolvedPath, args.symbol);
|
|
24
|
+
const startLine = symbolRange?.startLine ?? findBlockStart(lines, args.symbol);
|
|
25
|
+
if (startLine === undefined) {
|
|
26
|
+
return {
|
|
27
|
+
ok: false,
|
|
28
|
+
status: 'error',
|
|
29
|
+
source: 'cwtools-node-block',
|
|
30
|
+
error: { code: 'symbol_not_found', message: `Symbol '${args.symbol}' not found in file.` },
|
|
31
|
+
data: {
|
|
32
|
+
content: `Error: Symbol '${args.symbol}' not found in file.`,
|
|
33
|
+
truncated: false,
|
|
34
|
+
lineNumberBase: 1,
|
|
35
|
+
source: 'cwtools-node-block',
|
|
36
|
+
error: `Symbol '${args.symbol}' not found in file.`,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const endLine = symbolRange?.endLine ?? findBlockEnd(lines, startLine);
|
|
41
|
+
const blockLines = lines.slice(startLine, endLine + 1);
|
|
42
|
+
const fullText = blockLines.join('\n');
|
|
43
|
+
const maxChars = 16000;
|
|
44
|
+
const truncated = fullText.length > maxChars;
|
|
45
|
+
const source = symbolRange?.source === 'cwtools-lsp-symbols' ? 'cwtools-lsp-symbols' : 'cwtools-node-block';
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
status: 'ready',
|
|
49
|
+
source,
|
|
50
|
+
data: {
|
|
51
|
+
content: truncated ? `${fullText.slice(0, maxChars)}\n... [Block truncated due to size]` : fullText,
|
|
52
|
+
truncated,
|
|
53
|
+
startLine: startLine + 1,
|
|
54
|
+
endLine: endLine + 1,
|
|
55
|
+
lineNumberBase: 1,
|
|
56
|
+
source,
|
|
57
|
+
warnings: source === 'cwtools-node-block'
|
|
58
|
+
? ['LSP document symbols were unavailable or did not contain this symbol; block boundaries were inferred in Node.']
|
|
59
|
+
: undefined,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function resolveSymbolRange(host, file, symbolName) {
|
|
64
|
+
const symbolsResult = await (0, symbols_1.documentSymbolsWithHost)(host, { file }).catch(() => undefined);
|
|
65
|
+
const symbol = symbolsResult?.data ? findSymbol(symbolsResult.data.symbols, symbolName) : undefined;
|
|
66
|
+
if (!symbol)
|
|
67
|
+
return undefined;
|
|
68
|
+
return {
|
|
69
|
+
startLine: symbol.range.startLine,
|
|
70
|
+
endLine: symbol.range.endLine,
|
|
71
|
+
source: symbolsResult.source,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function findSymbol(symbols, targetName) {
|
|
75
|
+
for (const symbol of symbols) {
|
|
76
|
+
if (symbol.name === targetName)
|
|
77
|
+
return symbol;
|
|
78
|
+
const child = symbol.children ? findSymbol(symbol.children, targetName) : undefined;
|
|
79
|
+
if (child)
|
|
80
|
+
return child;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
function findBlockStart(lines, symbol) {
|
|
85
|
+
const escaped = escapeRegExp(symbol);
|
|
86
|
+
const topLevelPattern = new RegExp(`^\\s*${escaped}\\s*=`);
|
|
87
|
+
const idPattern = new RegExp(`\\bid\\s*=\\s*"?${escaped}"?\\b`);
|
|
88
|
+
for (let index = 0; index < lines.length; index++) {
|
|
89
|
+
const line = lines[index] ?? '';
|
|
90
|
+
if (topLevelPattern.test(line))
|
|
91
|
+
return index;
|
|
92
|
+
if (idPattern.test(line)) {
|
|
93
|
+
for (let back = index; back >= 0; back--) {
|
|
94
|
+
if (/\w+\s*=\s*\{/.test(lines[back] ?? ''))
|
|
95
|
+
return back;
|
|
96
|
+
}
|
|
97
|
+
return index;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
function findBlockEnd(lines, startLine) {
|
|
103
|
+
let depth = 0;
|
|
104
|
+
let sawOpen = false;
|
|
105
|
+
for (let index = startLine; index < lines.length; index++) {
|
|
106
|
+
const counts = countBraces(lines[index] ?? '');
|
|
107
|
+
depth += counts.open - counts.close;
|
|
108
|
+
sawOpen || (sawOpen = counts.open > 0);
|
|
109
|
+
if (sawOpen && depth <= 0)
|
|
110
|
+
return index;
|
|
111
|
+
}
|
|
112
|
+
return startLine;
|
|
113
|
+
}
|
|
114
|
+
function countBraces(line) {
|
|
115
|
+
let open = 0;
|
|
116
|
+
let close = 0;
|
|
117
|
+
let inString = false;
|
|
118
|
+
let escaped = false;
|
|
119
|
+
for (let index = 0; index < line.length; index++) {
|
|
120
|
+
const char = line[index];
|
|
121
|
+
if (!inString && char === '#')
|
|
122
|
+
break;
|
|
123
|
+
if (char === '"' && !escaped) {
|
|
124
|
+
inString = !inString;
|
|
125
|
+
}
|
|
126
|
+
else if (!inString && char === '{') {
|
|
127
|
+
open++;
|
|
128
|
+
}
|
|
129
|
+
else if (!inString && char === '}') {
|
|
130
|
+
close++;
|
|
131
|
+
}
|
|
132
|
+
escaped = char === '\\' && !escaped;
|
|
133
|
+
if (char !== '\\')
|
|
134
|
+
escaped = false;
|
|
135
|
+
}
|
|
136
|
+
return { open, close };
|
|
137
|
+
}
|
|
138
|
+
function escapeRegExp(value) {
|
|
139
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
140
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ToolEffect = 'none' | 'memory' | 'workspace_read' | 'workspace_write' | 'network' | 'shell' | 'git' | 'media' | 'mcp';
|
|
2
|
+
export type ToolConcurrencyClass = 'parallel' | 'lsp-limited' | 'network-limited' | 'per-file-write' | 'global-exclusive' | 'interactive';
|
|
3
|
+
export interface ToolRegistryMetadata {
|
|
4
|
+
name: string;
|
|
5
|
+
isWrite: boolean;
|
|
6
|
+
isReadOnly: boolean;
|
|
7
|
+
effect: ToolEffect;
|
|
8
|
+
riskLevel: 0 | 1 | 2 | 3;
|
|
9
|
+
concurrencyClass: ToolConcurrencyClass;
|
|
10
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ToolRegistryMetadata } from './registry';
|
|
2
|
+
export type JsonObject = Record<string, unknown>;
|
|
3
|
+
export interface ToolDefinition {
|
|
4
|
+
type: 'function';
|
|
5
|
+
function: {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
parameters: JsonObject;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface McpToolSchema {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
inputSchema: JsonObject;
|
|
15
|
+
}
|
|
16
|
+
export interface GeneratedMcpTool {
|
|
17
|
+
tool: McpToolSchema;
|
|
18
|
+
registry: ToolRegistryMetadata;
|
|
19
|
+
}
|
|
20
|
+
export interface SharedToolError {
|
|
21
|
+
code: string;
|
|
22
|
+
message: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SharedToolResult<T = unknown> {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
status: 'ready' | 'partial' | 'success' | 'denied' | 'loading' | 'stale' | 'unavailable' | 'error';
|
|
27
|
+
source: string;
|
|
28
|
+
data?: T;
|
|
29
|
+
error?: SharedToolError;
|
|
30
|
+
warnings?: string[];
|
|
31
|
+
nextSteps?: string[];
|
|
32
|
+
vanillaCache?: import('../host/vanillaCache').VanillaCacheStatus;
|
|
33
|
+
readiness?: import('../host/readiness').LspReadiness;
|
|
34
|
+
}
|
|
35
|
+
export declare function toolUnavailable(tool: string, message: string, nextSteps?: string[]): SharedToolResult;
|
|
36
|
+
export declare function toolDenied(code: string, message: string): SharedToolResult;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toolUnavailable = toolUnavailable;
|
|
4
|
+
exports.toolDenied = toolDenied;
|
|
5
|
+
function toolUnavailable(tool, message, nextSteps = []) {
|
|
6
|
+
return {
|
|
7
|
+
ok: false,
|
|
8
|
+
status: 'unavailable',
|
|
9
|
+
source: 'cwtools-shared',
|
|
10
|
+
error: { code: 'unavailable', message },
|
|
11
|
+
nextSteps,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function toolDenied(code, message) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
status: 'denied',
|
|
18
|
+
source: 'cwtools-shared',
|
|
19
|
+
error: { code, message },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { HostServices } from '../host/hostServices';
|
|
2
|
+
import { type SharedToolResult } from './schema';
|
|
3
|
+
export interface DocumentSymbolInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
kind: string;
|
|
6
|
+
range: {
|
|
7
|
+
startLine: number;
|
|
8
|
+
endLine: number;
|
|
9
|
+
startColumn?: number;
|
|
10
|
+
endColumn?: number;
|
|
11
|
+
};
|
|
12
|
+
children?: DocumentSymbolInfo[];
|
|
13
|
+
_hasDeeper?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface WorkspaceSymbolInfo {
|
|
16
|
+
name: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
file: string;
|
|
19
|
+
line: number;
|
|
20
|
+
column?: number;
|
|
21
|
+
containerName?: string;
|
|
22
|
+
source?: string;
|
|
23
|
+
}
|
|
24
|
+
export type SymbolOrigin = 'workspace' | 'vanilla' | 'generated' | 'external';
|
|
25
|
+
export declare function getCompletionAtWithHost(host: HostServices, args: {
|
|
26
|
+
file: string;
|
|
27
|
+
line: number;
|
|
28
|
+
column: number;
|
|
29
|
+
limit?: number;
|
|
30
|
+
}): Promise<SharedToolResult>;
|
|
31
|
+
export declare function documentSymbolsWithHost(host: HostServices, args: {
|
|
32
|
+
file: string;
|
|
33
|
+
}): Promise<SharedToolResult<{
|
|
34
|
+
symbols: DocumentSymbolInfo[];
|
|
35
|
+
lineNumberBase: 0;
|
|
36
|
+
source: string;
|
|
37
|
+
warnings?: string[];
|
|
38
|
+
}>>;
|
|
39
|
+
export declare function workspaceSymbolsWithHost(host: HostServices, args: {
|
|
40
|
+
query: string;
|
|
41
|
+
limit?: number;
|
|
42
|
+
}): Promise<SharedToolResult<{
|
|
43
|
+
symbols: WorkspaceSymbolInfo[];
|
|
44
|
+
source: string;
|
|
45
|
+
warnings?: string[];
|
|
46
|
+
}>>;
|
|
47
|
+
export declare function queryDefinitionWithHost(host: HostServices, args: {
|
|
48
|
+
file: string;
|
|
49
|
+
line: number;
|
|
50
|
+
column: number;
|
|
51
|
+
}): Promise<SharedToolResult>;
|
|
52
|
+
export declare function queryDefinitionByNameWithHost(host: HostServices, args: {
|
|
53
|
+
symbolName: string;
|
|
54
|
+
}): Promise<SharedToolResult>;
|
|
55
|
+
export declare function queryReferencesWithHost(host: HostServices, args: {
|
|
56
|
+
identifier: string;
|
|
57
|
+
file?: string;
|
|
58
|
+
limit?: number;
|
|
59
|
+
}): Promise<SharedToolResult>;
|
|
60
|
+
export declare function inferDocumentSymbolsFromText(content: string): DocumentSymbolInfo[];
|