@nogataka/smart-edit 0.0.14

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 (186) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +244 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +7 -0
  5. package/dist/devtools/generate_prompt_factory.d.ts +5 -0
  6. package/dist/devtools/generate_prompt_factory.js +114 -0
  7. package/dist/index.d.ts +34 -0
  8. package/dist/index.js +34 -0
  9. package/dist/interprompt/index.d.ts +2 -0
  10. package/dist/interprompt/index.js +1 -0
  11. package/dist/interprompt/jinja_template.d.ts +10 -0
  12. package/dist/interprompt/jinja_template.js +174 -0
  13. package/dist/interprompt/multilang_prompt.d.ts +54 -0
  14. package/dist/interprompt/multilang_prompt.js +302 -0
  15. package/dist/interprompt/prompt_factory.d.ts +16 -0
  16. package/dist/interprompt/prompt_factory.js +189 -0
  17. package/dist/interprompt/util/class_decorators.d.ts +1 -0
  18. package/dist/interprompt/util/class_decorators.js +1 -0
  19. package/dist/interprompt/util/index.d.ts +1 -0
  20. package/dist/interprompt/util/index.js +1 -0
  21. package/dist/serena/agent.d.ts +118 -0
  22. package/dist/serena/agent.js +675 -0
  23. package/dist/serena/agno.d.ts +111 -0
  24. package/dist/serena/agno.js +278 -0
  25. package/dist/serena/analytics.d.ts +24 -0
  26. package/dist/serena/analytics.js +119 -0
  27. package/dist/serena/cli.d.ts +9 -0
  28. package/dist/serena/cli.js +731 -0
  29. package/dist/serena/code_editor.d.ts +42 -0
  30. package/dist/serena/code_editor.js +239 -0
  31. package/dist/serena/config/context_mode.d.ts +41 -0
  32. package/dist/serena/config/context_mode.js +239 -0
  33. package/dist/serena/config/serena_config.d.ts +134 -0
  34. package/dist/serena/config/serena_config.js +718 -0
  35. package/dist/serena/constants.d.ts +18 -0
  36. package/dist/serena/constants.js +27 -0
  37. package/dist/serena/dashboard.d.ts +55 -0
  38. package/dist/serena/dashboard.js +472 -0
  39. package/dist/serena/generated/generated_prompt_factory.d.ts +27 -0
  40. package/dist/serena/generated/generated_prompt_factory.js +42 -0
  41. package/dist/serena/gui_log_viewer.d.ts +41 -0
  42. package/dist/serena/gui_log_viewer.js +436 -0
  43. package/dist/serena/mcp.d.ts +118 -0
  44. package/dist/serena/mcp.js +904 -0
  45. package/dist/serena/project.d.ts +62 -0
  46. package/dist/serena/project.js +321 -0
  47. package/dist/serena/prompt_factory.d.ts +20 -0
  48. package/dist/serena/prompt_factory.js +42 -0
  49. package/dist/serena/resources/config/contexts/agent.yml +8 -0
  50. package/dist/serena/resources/config/contexts/chatgpt.yml +28 -0
  51. package/dist/serena/resources/config/contexts/codex.yml +27 -0
  52. package/dist/serena/resources/config/contexts/context.template.yml +11 -0
  53. package/dist/serena/resources/config/contexts/desktop-app.yml +17 -0
  54. package/dist/serena/resources/config/contexts/ide-assistant.yml +26 -0
  55. package/dist/serena/resources/config/contexts/oaicompat-agent.yml +8 -0
  56. package/dist/serena/resources/config/internal_modes/jetbrains.yml +15 -0
  57. package/dist/serena/resources/config/modes/editing.yml +112 -0
  58. package/dist/serena/resources/config/modes/interactive.yml +11 -0
  59. package/dist/serena/resources/config/modes/mode.template.yml +7 -0
  60. package/dist/serena/resources/config/modes/no-onboarding.yml +8 -0
  61. package/dist/serena/resources/config/modes/onboarding.yml +16 -0
  62. package/dist/serena/resources/config/modes/one-shot.yml +15 -0
  63. package/dist/serena/resources/config/modes/planning.yml +15 -0
  64. package/dist/serena/resources/config/prompt_templates/simple_tool_outputs.yml +75 -0
  65. package/dist/serena/resources/config/prompt_templates/system_prompt.yml +66 -0
  66. package/dist/serena/resources/dashboard/dashboard.js +815 -0
  67. package/dist/serena/resources/dashboard/index.html +314 -0
  68. package/dist/serena/resources/dashboard/jquery.min.js +3 -0
  69. package/dist/serena/resources/dashboard/serena-icon-16.png +0 -0
  70. package/dist/serena/resources/dashboard/serena-icon-32.png +0 -0
  71. package/dist/serena/resources/dashboard/serena-icon-48.png +0 -0
  72. package/dist/serena/resources/dashboard/serena-logs-dark-mode.png +0 -0
  73. package/dist/serena/resources/dashboard/serena-logs.png +0 -0
  74. package/dist/serena/resources/project.template.yml +67 -0
  75. package/dist/serena/resources/serena_config.template.yml +85 -0
  76. package/dist/serena/symbol.d.ts +199 -0
  77. package/dist/serena/symbol.js +616 -0
  78. package/dist/serena/text_utils.d.ts +51 -0
  79. package/dist/serena/text_utils.js +267 -0
  80. package/dist/serena/tools/cmd_tools.d.ts +31 -0
  81. package/dist/serena/tools/cmd_tools.js +48 -0
  82. package/dist/serena/tools/config_tools.d.ts +53 -0
  83. package/dist/serena/tools/config_tools.js +176 -0
  84. package/dist/serena/tools/file_tools.d.ts +231 -0
  85. package/dist/serena/tools/file_tools.js +511 -0
  86. package/dist/serena/tools/index.d.ts +7 -0
  87. package/dist/serena/tools/index.js +7 -0
  88. package/dist/serena/tools/memory_tools.d.ts +60 -0
  89. package/dist/serena/tools/memory_tools.js +135 -0
  90. package/dist/serena/tools/symbol_tools.d.ts +165 -0
  91. package/dist/serena/tools/symbol_tools.js +362 -0
  92. package/dist/serena/tools/tools_base.d.ts +162 -0
  93. package/dist/serena/tools/tools_base.js +378 -0
  94. package/dist/serena/tools/workflow_tools.d.ts +35 -0
  95. package/dist/serena/tools/workflow_tools.js +161 -0
  96. package/dist/serena/util/class_decorators.d.ts +7 -0
  97. package/dist/serena/util/class_decorators.js +37 -0
  98. package/dist/serena/util/exception.d.ts +8 -0
  99. package/dist/serena/util/exception.js +53 -0
  100. package/dist/serena/util/file_system.d.ts +30 -0
  101. package/dist/serena/util/file_system.js +352 -0
  102. package/dist/serena/util/general.d.ts +11 -0
  103. package/dist/serena/util/general.js +42 -0
  104. package/dist/serena/util/git.d.ts +11 -0
  105. package/dist/serena/util/git.js +37 -0
  106. package/dist/serena/util/inspection.d.ts +45 -0
  107. package/dist/serena/util/inspection.js +221 -0
  108. package/dist/serena/util/logging.d.ts +46 -0
  109. package/dist/serena/util/logging.js +205 -0
  110. package/dist/serena/util/shell.d.ts +21 -0
  111. package/dist/serena/util/shell.js +95 -0
  112. package/dist/serena/util/thread.d.ts +23 -0
  113. package/dist/serena/util/thread.js +88 -0
  114. package/dist/serena/version.d.ts +1 -0
  115. package/dist/serena/version.js +23 -0
  116. package/dist/solidlsp/language_servers/autoload.d.ts +23 -0
  117. package/dist/solidlsp/language_servers/autoload.js +25 -0
  118. package/dist/solidlsp/language_servers/bash_language_server.d.ts +10 -0
  119. package/dist/solidlsp/language_servers/bash_language_server.js +64 -0
  120. package/dist/solidlsp/language_servers/clangd_language_server.d.ts +13 -0
  121. package/dist/solidlsp/language_servers/clangd_language_server.js +110 -0
  122. package/dist/solidlsp/language_servers/clojure_lsp.d.ts +13 -0
  123. package/dist/solidlsp/language_servers/clojure_lsp.js +137 -0
  124. package/dist/solidlsp/language_servers/common.d.ts +41 -0
  125. package/dist/solidlsp/language_servers/common.js +365 -0
  126. package/dist/solidlsp/language_servers/csharp_language_server.d.ts +21 -0
  127. package/dist/solidlsp/language_servers/csharp_language_server.js +694 -0
  128. package/dist/solidlsp/language_servers/dart_language_server.d.ts +10 -0
  129. package/dist/solidlsp/language_servers/dart_language_server.js +122 -0
  130. package/dist/solidlsp/language_servers/eclipse_jdtls.d.ts +24 -0
  131. package/dist/solidlsp/language_servers/eclipse_jdtls.js +671 -0
  132. package/dist/solidlsp/language_servers/erlang_language_server.d.ts +22 -0
  133. package/dist/solidlsp/language_servers/erlang_language_server.js +327 -0
  134. package/dist/solidlsp/language_servers/gopls.d.ts +12 -0
  135. package/dist/solidlsp/language_servers/gopls.js +59 -0
  136. package/dist/solidlsp/language_servers/intelephense.d.ts +13 -0
  137. package/dist/solidlsp/language_servers/intelephense.js +121 -0
  138. package/dist/solidlsp/language_servers/jedi_server.d.ts +18 -0
  139. package/dist/solidlsp/language_servers/jedi_server.js +234 -0
  140. package/dist/solidlsp/language_servers/kotlin_language_server.d.ts +19 -0
  141. package/dist/solidlsp/language_servers/kotlin_language_server.js +474 -0
  142. package/dist/solidlsp/language_servers/lua_ls.d.ts +18 -0
  143. package/dist/solidlsp/language_servers/lua_ls.js +319 -0
  144. package/dist/solidlsp/language_servers/nixd_language_server.d.ts +17 -0
  145. package/dist/solidlsp/language_servers/nixd_language_server.js +341 -0
  146. package/dist/solidlsp/language_servers/pyright_server.d.ts +19 -0
  147. package/dist/solidlsp/language_servers/pyright_server.js +180 -0
  148. package/dist/solidlsp/language_servers/r_language_server.d.ts +19 -0
  149. package/dist/solidlsp/language_servers/r_language_server.js +184 -0
  150. package/dist/solidlsp/language_servers/ruby_common.d.ts +10 -0
  151. package/dist/solidlsp/language_servers/ruby_common.js +136 -0
  152. package/dist/solidlsp/language_servers/ruby_lsp.d.ts +18 -0
  153. package/dist/solidlsp/language_servers/ruby_lsp.js +230 -0
  154. package/dist/solidlsp/language_servers/rust_analyzer.d.ts +13 -0
  155. package/dist/solidlsp/language_servers/rust_analyzer.js +96 -0
  156. package/dist/solidlsp/language_servers/solargraph.d.ts +18 -0
  157. package/dist/solidlsp/language_servers/solargraph.js +208 -0
  158. package/dist/solidlsp/language_servers/sourcekit_lsp.d.ts +24 -0
  159. package/dist/solidlsp/language_servers/sourcekit_lsp.js +449 -0
  160. package/dist/solidlsp/language_servers/terraform_ls.d.ts +13 -0
  161. package/dist/solidlsp/language_servers/terraform_ls.js +139 -0
  162. package/dist/solidlsp/language_servers/typescript_language_server.d.ts +20 -0
  163. package/dist/solidlsp/language_servers/typescript_language_server.js +237 -0
  164. package/dist/solidlsp/language_servers/vts_language_server.d.ts +13 -0
  165. package/dist/solidlsp/language_servers/vts_language_server.js +121 -0
  166. package/dist/solidlsp/language_servers/zls.d.ts +20 -0
  167. package/dist/solidlsp/language_servers/zls.js +254 -0
  168. package/dist/solidlsp/ls.d.ts +197 -0
  169. package/dist/solidlsp/ls.js +507 -0
  170. package/dist/solidlsp/ls_config.d.ts +43 -0
  171. package/dist/solidlsp/ls_config.js +157 -0
  172. package/dist/solidlsp/ls_exceptions.d.ts +5 -0
  173. package/dist/solidlsp/ls_exceptions.js +14 -0
  174. package/dist/solidlsp/ls_handler.d.ts +54 -0
  175. package/dist/solidlsp/ls_handler.js +406 -0
  176. package/dist/solidlsp/ls_request.d.ts +31 -0
  177. package/dist/solidlsp/ls_request.js +42 -0
  178. package/dist/solidlsp/ls_types.d.ts +7 -0
  179. package/dist/solidlsp/ls_types.js +8 -0
  180. package/dist/solidlsp/lsp_protocol_handler/server.d.ts +61 -0
  181. package/dist/solidlsp/lsp_protocol_handler/server.js +68 -0
  182. package/dist/solidlsp/util/subprocess_util.d.ts +6 -0
  183. package/dist/solidlsp/util/subprocess_util.js +11 -0
  184. package/dist/solidlsp/util/zip.d.ts +25 -0
  185. package/dist/solidlsp/util/zip.js +188 -0
  186. package/package.json +65 -0
@@ -0,0 +1,135 @@
1
+ import { z } from 'zod';
2
+ import { Tool, ToolMarkerCanEdit } from './tools_base.js';
3
+ function bindFunction(manager, candidates) {
4
+ for (const key of candidates) {
5
+ const candidate = Reflect.get(manager, key);
6
+ if (typeof candidate === 'function') {
7
+ return candidate.bind(manager);
8
+ }
9
+ }
10
+ throw new Error(`Memories manager does not implement required method: ${candidates.join(' or ')}`);
11
+ }
12
+ function stringifyUnknown(value) {
13
+ if (value === undefined || value === null) {
14
+ return 'null';
15
+ }
16
+ if (typeof value === 'string') {
17
+ return value;
18
+ }
19
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
20
+ return value.toString();
21
+ }
22
+ if (typeof value === 'symbol') {
23
+ return value.toString();
24
+ }
25
+ if (typeof value === 'function') {
26
+ return '[function]';
27
+ }
28
+ if (typeof value === 'object') {
29
+ try {
30
+ return JSON.stringify(value);
31
+ }
32
+ catch {
33
+ return Object.prototype.toString.call(value);
34
+ }
35
+ }
36
+ return 'unknown';
37
+ }
38
+ function isIterable(value) {
39
+ return typeof value === 'object' && value !== null && Symbol.iterator in value;
40
+ }
41
+ async function callListMemories(manager) {
42
+ const listFn = bindFunction(manager, ['listMemories', 'list_memories']);
43
+ const raw = await listFn();
44
+ if (!raw) {
45
+ return [];
46
+ }
47
+ if (Array.isArray(raw)) {
48
+ return raw.map((entry) => stringifyUnknown(entry));
49
+ }
50
+ if (isIterable(raw)) {
51
+ const result = [];
52
+ for (const entry of raw) {
53
+ result.push(stringifyUnknown(entry));
54
+ }
55
+ return result;
56
+ }
57
+ return [stringifyUnknown(raw)];
58
+ }
59
+ async function callSaveMemory(manager, name, content) {
60
+ const saveFn = bindFunction(manager, ['saveMemory', 'save_memory']);
61
+ const result = await Promise.resolve(saveFn(name, content));
62
+ return stringifyUnknown(result);
63
+ }
64
+ async function callLoadMemory(manager, name) {
65
+ const loadFn = bindFunction(manager, ['loadMemory', 'load_memory']);
66
+ const result = await Promise.resolve(loadFn(name));
67
+ return typeof result === 'string' ? result : stringifyUnknown(result);
68
+ }
69
+ async function callDeleteMemory(manager, name) {
70
+ const deleteFn = bindFunction(manager, ['deleteMemory', 'delete_memory']);
71
+ const result = await Promise.resolve(deleteFn(name));
72
+ return stringifyUnknown(result);
73
+ }
74
+ export class WriteMemoryTool extends Tool {
75
+ static markers = new Set([ToolMarkerCanEdit]);
76
+ static description = "Writes a named markdown memory entry to Serena's project-specific memory store.";
77
+ static inputSchema = z.object({
78
+ memory_name: z.string().min(1, 'memory_name must not be empty'),
79
+ content: z.string(),
80
+ max_answer_chars: z
81
+ .number()
82
+ .int()
83
+ .gte(-1, 'max_answer_chars must be -1 or a positive integer')
84
+ .optional()
85
+ });
86
+ async apply(args) {
87
+ const { memory_name, content, max_answer_chars = -1 } = args;
88
+ let limit = max_answer_chars;
89
+ if (limit === -1) {
90
+ limit = this.agent.serenaConfig.defaultMaxToolAnswerChars;
91
+ }
92
+ if (limit <= 0) {
93
+ throw new Error(`max_answer_chars must be positive or -1; got ${limit}`);
94
+ }
95
+ if (content.length > limit) {
96
+ throw new Error(`Content for ${memory_name} is too long. Max length is ${limit} characters. Please make the content shorter.`);
97
+ }
98
+ const response = await callSaveMemory(this.memoriesManager, memory_name, content);
99
+ return this._limitLength(response, max_answer_chars);
100
+ }
101
+ }
102
+ export class ReadMemoryTool extends Tool {
103
+ static description = "Reads the content of a memory file from Serena's project-specific memory store.";
104
+ static inputSchema = z.object({
105
+ memory_file_name: z.string().min(1, 'memory_file_name must not be empty'),
106
+ max_answer_chars: z
107
+ .number()
108
+ .int()
109
+ .gte(-1, 'max_answer_chars must be -1 or a positive integer')
110
+ .optional()
111
+ });
112
+ async apply(args) {
113
+ const { memory_file_name } = args;
114
+ return callLoadMemory(this.memoriesManager, memory_file_name);
115
+ }
116
+ }
117
+ export class ListMemoriesTool extends Tool {
118
+ static description = "Lists the available memories in Serena's project-specific memory store as a JSON array.";
119
+ async apply(_args = {}) {
120
+ const memories = await callListMemories(this.memoriesManager);
121
+ return JSON.stringify(memories);
122
+ }
123
+ }
124
+ export class DeleteMemoryTool extends Tool {
125
+ static markers = new Set([ToolMarkerCanEdit]);
126
+ static description = "Deletes a memory file from Serena's project-specific memory store.";
127
+ static inputSchema = z.object({
128
+ memory_file_name: z.string().min(1, 'memory_file_name must not be empty')
129
+ });
130
+ async apply(args) {
131
+ const { memory_file_name } = args;
132
+ const response = await callDeleteMemory(this.memoriesManager, memory_file_name);
133
+ return response;
134
+ }
135
+ }
@@ -0,0 +1,165 @@
1
+ import { z } from 'zod';
2
+ import { Tool } from './tools_base.js';
3
+ interface GetSymbolsOverviewInput {
4
+ relative_path: string;
5
+ max_answer_chars?: number;
6
+ }
7
+ interface FindSymbolInput {
8
+ name_path: string;
9
+ depth?: number;
10
+ relative_path?: string;
11
+ include_body?: boolean;
12
+ include_kinds?: number[];
13
+ exclude_kinds?: number[];
14
+ substring_matching?: boolean;
15
+ max_answer_chars?: number;
16
+ }
17
+ interface FindReferencingSymbolsInput {
18
+ name_path: string;
19
+ relative_path: string;
20
+ include_kinds?: number[];
21
+ exclude_kinds?: number[];
22
+ max_answer_chars?: number;
23
+ }
24
+ interface ReplaceSymbolBodyInput {
25
+ name_path: string;
26
+ relative_path: string;
27
+ body: string;
28
+ }
29
+ interface InsertSymbolInput {
30
+ name_path: string;
31
+ relative_path: string;
32
+ body: string;
33
+ }
34
+ export declare class RestartLanguageServerTool extends Tool {
35
+ static readonly markers: Set<"optional">;
36
+ static readonly description = "Restarts the language server. Use only on explicit user request or if the server hangs.";
37
+ apply(): Promise<string>;
38
+ }
39
+ export declare class GetSymbolsOverviewTool extends Tool {
40
+ static readonly markers: Set<"symbolic-read">;
41
+ static readonly description = "Returns a JSON array describing the top-level symbols in a file.";
42
+ static readonly inputSchema: z.ZodObject<{
43
+ relative_path: z.ZodString;
44
+ max_answer_chars: z.ZodOptional<z.ZodNumber>;
45
+ }, "strip", z.ZodTypeAny, {
46
+ relative_path: string;
47
+ max_answer_chars?: number | undefined;
48
+ }, {
49
+ relative_path: string;
50
+ max_answer_chars?: number | undefined;
51
+ }>;
52
+ apply(args: GetSymbolsOverviewInput): Promise<string>;
53
+ }
54
+ export declare class FindSymbolTool extends Tool {
55
+ static readonly markers: Set<"symbolic-read">;
56
+ static readonly description = "Finds symbols that match the given name path, optionally restricting by location or symbol kind.";
57
+ static readonly inputSchema: z.ZodObject<{
58
+ name_path: z.ZodString;
59
+ depth: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
60
+ relative_path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
61
+ include_body: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
62
+ include_kinds: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>>;
63
+ exclude_kinds: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>>;
64
+ substring_matching: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
65
+ max_answer_chars: z.ZodOptional<z.ZodNumber>;
66
+ }, "strip", z.ZodTypeAny, {
67
+ relative_path: string;
68
+ depth: number;
69
+ include_body: boolean;
70
+ include_kinds: number[];
71
+ exclude_kinds: number[];
72
+ substring_matching: boolean;
73
+ name_path: string;
74
+ max_answer_chars?: number | undefined;
75
+ }, {
76
+ name_path: string;
77
+ relative_path?: string | undefined;
78
+ max_answer_chars?: number | undefined;
79
+ depth?: number | undefined;
80
+ include_body?: boolean | undefined;
81
+ include_kinds?: number[] | undefined;
82
+ exclude_kinds?: number[] | undefined;
83
+ substring_matching?: boolean | undefined;
84
+ }>;
85
+ apply(args: FindSymbolInput): Promise<string>;
86
+ }
87
+ export declare class FindReferencingSymbolsTool extends Tool {
88
+ static readonly markers: Set<"symbolic-read">;
89
+ static readonly description = "Finds symbols referencing the specified target and returns metadata including snippets.";
90
+ static readonly inputSchema: z.ZodObject<{
91
+ name_path: z.ZodString;
92
+ relative_path: z.ZodString;
93
+ include_kinds: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>>;
94
+ exclude_kinds: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>>;
95
+ max_answer_chars: z.ZodOptional<z.ZodNumber>;
96
+ }, "strip", z.ZodTypeAny, {
97
+ relative_path: string;
98
+ include_kinds: number[];
99
+ exclude_kinds: number[];
100
+ name_path: string;
101
+ max_answer_chars?: number | undefined;
102
+ }, {
103
+ relative_path: string;
104
+ name_path: string;
105
+ max_answer_chars?: number | undefined;
106
+ include_kinds?: number[] | undefined;
107
+ exclude_kinds?: number[] | undefined;
108
+ }>;
109
+ apply(args: FindReferencingSymbolsInput): Promise<string>;
110
+ }
111
+ export declare class ReplaceSymbolBodyTool extends Tool {
112
+ static readonly markers: Set<"symbolic-edit">;
113
+ static readonly description = "Replaces the body of the specified symbol.";
114
+ static readonly inputSchema: z.ZodObject<{
115
+ name_path: z.ZodString;
116
+ relative_path: z.ZodString;
117
+ body: z.ZodString;
118
+ }, "strip", z.ZodTypeAny, {
119
+ relative_path: string;
120
+ name_path: string;
121
+ body: string;
122
+ }, {
123
+ relative_path: string;
124
+ name_path: string;
125
+ body: string;
126
+ }>;
127
+ apply(args: ReplaceSymbolBodyInput): Promise<string>;
128
+ }
129
+ export declare class InsertAfterSymbolTool extends Tool {
130
+ static readonly markers: Set<"symbolic-edit">;
131
+ static readonly description = "Inserts content immediately after the specified symbol.";
132
+ static readonly inputSchema: z.ZodObject<{
133
+ name_path: z.ZodString;
134
+ relative_path: z.ZodString;
135
+ body: z.ZodString;
136
+ }, "strip", z.ZodTypeAny, {
137
+ relative_path: string;
138
+ name_path: string;
139
+ body: string;
140
+ }, {
141
+ relative_path: string;
142
+ name_path: string;
143
+ body: string;
144
+ }>;
145
+ apply(args: InsertSymbolInput): Promise<string>;
146
+ }
147
+ export declare class InsertBeforeSymbolTool extends Tool {
148
+ static readonly markers: Set<"symbolic-edit">;
149
+ static readonly description = "Inserts content immediately before the specified symbol.";
150
+ static readonly inputSchema: z.ZodObject<{
151
+ name_path: z.ZodString;
152
+ relative_path: z.ZodString;
153
+ body: z.ZodString;
154
+ }, "strip", z.ZodTypeAny, {
155
+ relative_path: string;
156
+ name_path: string;
157
+ body: string;
158
+ }, {
159
+ relative_path: string;
160
+ name_path: string;
161
+ body: string;
162
+ }>;
163
+ apply(args: InsertSymbolInput): Promise<string>;
164
+ }
165
+ export {};
@@ -0,0 +1,362 @@
1
+ /* eslint-disable @typescript-eslint/unbound-method */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { SUCCESS_RESULT, Tool, ToolMarkerOptional, ToolMarkerSymbolicEdit, ToolMarkerSymbolicRead } from './tools_base.js';
6
+ function isEditorSymbolMethod(value) {
7
+ return typeof value === 'function';
8
+ }
9
+ function isRecord(value) {
10
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
11
+ }
12
+ function maybeCall(target, names, ...args) {
13
+ for (const name of names) {
14
+ const candidate = Reflect.get(target, name);
15
+ if (typeof candidate === 'function') {
16
+ return candidate.apply(target, args);
17
+ }
18
+ }
19
+ throw new Error(`Required method not implemented. Tried: ${names.join(', ')}`);
20
+ }
21
+ function sanitizeSymbolDict(source) {
22
+ const symbolDict = { ...source };
23
+ const location = symbolDict.location;
24
+ if (isRecord(location)) {
25
+ const relativePath = typeof location.relative_path === 'string'
26
+ ? location.relative_path
27
+ : typeof location.relativePath === 'string'
28
+ ? location.relativePath
29
+ : undefined;
30
+ if (relativePath !== undefined) {
31
+ symbolDict.relative_path = relativePath;
32
+ }
33
+ }
34
+ delete symbolDict.location;
35
+ delete symbolDict.name;
36
+ return symbolDict;
37
+ }
38
+ function normalizeSymbolKinds(values) {
39
+ if (!values || values.length === 0) {
40
+ return undefined;
41
+ }
42
+ return values.map((value) => {
43
+ if (!Number.isInteger(value)) {
44
+ throw new Error(`Symbol kind must be an integer, got ${value}`);
45
+ }
46
+ if (value < 1 || value > 26) {
47
+ throw new RangeError(`Unsupported symbol kind value: ${value}`);
48
+ }
49
+ return value;
50
+ });
51
+ }
52
+ function symbolRepresentationToDict(symbol, options = {}) {
53
+ if (!isRecord(symbol)) {
54
+ throw new Error('Symbol retriever returned a non-object value.');
55
+ }
56
+ const camelCase = symbol.toDict;
57
+ const snakeCase = symbol.to_dict;
58
+ if (typeof camelCase === 'function' || typeof snakeCase === 'function') {
59
+ const callable = (camelCase ?? snakeCase);
60
+ const payload = { ...options };
61
+ if (payload.include_body !== undefined && payload.includeBody === undefined) {
62
+ payload.includeBody = payload.include_body;
63
+ }
64
+ if (payload.includeBody !== undefined && payload.include_body === undefined) {
65
+ payload.include_body = payload.includeBody;
66
+ }
67
+ const result = callable.call(symbol, payload);
68
+ if (!isRecord(result)) {
69
+ throw new Error('Symbol to_dict returned a non-object value.');
70
+ }
71
+ return { ...result };
72
+ }
73
+ return { ...symbol };
74
+ }
75
+ async function getSymbolOverview(retriever, relativePath) {
76
+ const raw = await Promise.resolve(maybeCall(retriever, ['getSymbolOverview', 'get_symbol_overview'], relativePath));
77
+ if (Array.isArray(raw)) {
78
+ return raw.map((entry) => {
79
+ if (!isRecord(entry)) {
80
+ throw new Error('Symbol overview entry must be an object.');
81
+ }
82
+ return { ...entry };
83
+ });
84
+ }
85
+ if (isRecord(raw)) {
86
+ const entries = raw[relativePath];
87
+ if (!entries) {
88
+ return [];
89
+ }
90
+ if (!Array.isArray(entries)) {
91
+ throw new Error('Symbol overview response must contain a list of entries.');
92
+ }
93
+ return entries.map((entry) => {
94
+ if (!isRecord(entry)) {
95
+ throw new Error('Symbol overview entry must be an object.');
96
+ }
97
+ return { ...entry };
98
+ });
99
+ }
100
+ throw new Error('Symbol overview response has an unexpected format.');
101
+ }
102
+ async function findSymbols(retriever, namePath, options) {
103
+ const payload = {
104
+ includeBody: options.includeBody,
105
+ include_body: options.includeBody,
106
+ includeKinds: options.includeKinds,
107
+ include_kinds: options.includeKinds,
108
+ excludeKinds: options.excludeKinds,
109
+ exclude_kinds: options.excludeKinds,
110
+ substringMatching: options.substringMatching,
111
+ substring_matching: options.substringMatching
112
+ };
113
+ if (options.withinRelativePath && options.withinRelativePath.length > 0) {
114
+ payload.withinRelativePath = options.withinRelativePath;
115
+ payload.within_relative_path = options.withinRelativePath;
116
+ }
117
+ const raw = await Promise.resolve(maybeCall(retriever, ['findByName', 'find_by_name'], namePath, payload));
118
+ if (!Array.isArray(raw)) {
119
+ throw new Error('find_by_name returned a non-array value.');
120
+ }
121
+ const result = [];
122
+ for (const entry of raw) {
123
+ result.push(entry);
124
+ }
125
+ return result;
126
+ }
127
+ async function findReferencingSymbols(retriever, namePath, relativePath, options) {
128
+ const payload = {
129
+ includeKinds: options.includeKinds,
130
+ include_kinds: options.includeKinds,
131
+ excludeKinds: options.excludeKinds,
132
+ exclude_kinds: options.excludeKinds,
133
+ includeBody: false,
134
+ include_body: false
135
+ };
136
+ const raw = await Promise.resolve(maybeCall(retriever, ['findReferencingSymbols', 'find_referencing_symbols'], namePath, relativePath, payload));
137
+ if (!Array.isArray(raw)) {
138
+ throw new Error('find_referencing_symbols returned a non-array value.');
139
+ }
140
+ return raw.map((entry) => {
141
+ if (!isRecord(entry) || typeof entry.line !== 'number' || !('symbol' in entry)) {
142
+ throw new Error('Reference entry must include a symbol and numeric line.');
143
+ }
144
+ return {
145
+ symbol: entry.symbol,
146
+ line: entry.line
147
+ };
148
+ });
149
+ }
150
+ async function resolveContentAroundLine(project, relativePath, line) {
151
+ const method = project.retrieveContentAroundLine ?? project.retrieve_content_around_line;
152
+ if (typeof method !== 'function') {
153
+ throw new Error('Project does not support retrieving content around a line.');
154
+ }
155
+ const result = await Promise.resolve(Reflect.apply(method, project, [
156
+ relativePath,
157
+ line,
158
+ 1,
159
+ 1
160
+ ]));
161
+ if (typeof result === 'string') {
162
+ return result;
163
+ }
164
+ if (isRecord(result)) {
165
+ const formatter = result.toDisplayString ?? result.to_display_string;
166
+ if (typeof formatter === 'function') {
167
+ const formattedResult = await Promise.resolve(Reflect.apply(formatter, result, []));
168
+ if (typeof formattedResult === 'string') {
169
+ return formattedResult;
170
+ }
171
+ }
172
+ }
173
+ throw new Error('Content around line must provide a string or toDisplayString() result.');
174
+ }
175
+ async function callEditor(editor, names, namePath, relativePath, body) {
176
+ const firstCandidate = Reflect.get(editor, names[0]);
177
+ if (isEditorSymbolMethod(firstCandidate)) {
178
+ await Promise.resolve(Reflect.apply(firstCandidate, editor, [namePath, relativePath, body]));
179
+ return;
180
+ }
181
+ const secondCandidate = Reflect.get(editor, names[1]);
182
+ if (isEditorSymbolMethod(secondCandidate)) {
183
+ await Promise.resolve(Reflect.apply(secondCandidate, editor, [namePath, relativePath, body]));
184
+ return;
185
+ }
186
+ throw new Error(`Code editor does not implement ${names.join(' / ')}.`);
187
+ }
188
+ function getSymbolRetriever(raw) {
189
+ if (!isRecord(raw)) {
190
+ throw new Error('Language server symbol retriever must be an object.');
191
+ }
192
+ return raw;
193
+ }
194
+ export class RestartLanguageServerTool extends Tool {
195
+ static markers = new Set([ToolMarkerOptional]);
196
+ static description = 'Restarts the language server. Use only on explicit user request or if the server hangs.';
197
+ async apply() {
198
+ await Promise.resolve(this.agent.resetLanguageServer());
199
+ return SUCCESS_RESULT;
200
+ }
201
+ }
202
+ export class GetSymbolsOverviewTool extends Tool {
203
+ static markers = new Set([ToolMarkerSymbolicRead]);
204
+ static description = 'Returns a JSON array describing the top-level symbols in a file.';
205
+ static inputSchema = z.object({
206
+ relative_path: z.string().min(1, 'relative_path must not be empty'),
207
+ max_answer_chars: z
208
+ .number()
209
+ .int()
210
+ .gte(-1, 'max_answer_chars must be -1 or a positive integer')
211
+ .optional()
212
+ });
213
+ async apply(args) {
214
+ const { relative_path, max_answer_chars = -1 } = args;
215
+ const projectRoot = this.getProjectRoot();
216
+ const filePath = path.join(projectRoot, relative_path);
217
+ if (!fs.existsSync(filePath)) {
218
+ throw new Error(`File or directory ${relative_path} does not exist in the project.`);
219
+ }
220
+ const stats = fs.statSync(filePath);
221
+ if (stats.isDirectory()) {
222
+ throw new Error(`Expected a file path, but got a directory path: ${relative_path}.`);
223
+ }
224
+ const retriever = getSymbolRetriever(this.createLanguageServerSymbolRetriever());
225
+ const entries = await getSymbolOverview(retriever, relative_path);
226
+ const serialized = entries.map((entry) => sanitizeSymbolDict(symbolRepresentationToDict(entry)));
227
+ return this._limitLength(JSON.stringify(serialized), max_answer_chars);
228
+ }
229
+ }
230
+ export class FindSymbolTool extends Tool {
231
+ static markers = new Set([ToolMarkerSymbolicRead]);
232
+ static description = 'Finds symbols that match the given name path, optionally restricting by location or symbol kind.';
233
+ static inputSchema = z.object({
234
+ name_path: z.string().min(1, 'name_path must not be empty'),
235
+ depth: z
236
+ .number()
237
+ .int()
238
+ .min(0, 'depth must be non-negative')
239
+ .optional()
240
+ .default(0),
241
+ relative_path: z.string().optional().default(''),
242
+ include_body: z.boolean().optional().default(false),
243
+ include_kinds: z.array(z.number().int()).optional().default([]),
244
+ exclude_kinds: z.array(z.number().int()).optional().default([]),
245
+ substring_matching: z.boolean().optional().default(false),
246
+ max_answer_chars: z
247
+ .number()
248
+ .int()
249
+ .gte(-1, 'max_answer_chars must be -1 or a positive integer')
250
+ .optional()
251
+ });
252
+ async apply(args) {
253
+ const { name_path, depth = 0, relative_path = '', include_body = false, include_kinds = [], exclude_kinds = [], substring_matching = false, max_answer_chars = -1 } = args;
254
+ const retriever = getSymbolRetriever(this.createLanguageServerSymbolRetriever());
255
+ const symbols = await findSymbols(retriever, name_path, {
256
+ includeBody: include_body,
257
+ includeKinds: normalizeSymbolKinds(include_kinds),
258
+ excludeKinds: normalizeSymbolKinds(exclude_kinds),
259
+ substringMatching: substring_matching,
260
+ withinRelativePath: relative_path
261
+ });
262
+ const serialized = symbols.map((symbol) => sanitizeSymbolDict(symbolRepresentationToDict(symbol, {
263
+ depth,
264
+ kind: true,
265
+ location: true,
266
+ include_body: include_body,
267
+ includeBody: include_body
268
+ })));
269
+ return this._limitLength(JSON.stringify(serialized), max_answer_chars);
270
+ }
271
+ }
272
+ export class FindReferencingSymbolsTool extends Tool {
273
+ static markers = new Set([ToolMarkerSymbolicRead]);
274
+ static description = 'Finds symbols referencing the specified target and returns metadata including snippets.';
275
+ static inputSchema = z.object({
276
+ name_path: z.string().min(1, 'name_path must not be empty'),
277
+ relative_path: z.string().min(1, 'relative_path must not be empty'),
278
+ include_kinds: z.array(z.number().int()).optional().default([]),
279
+ exclude_kinds: z.array(z.number().int()).optional().default([]),
280
+ max_answer_chars: z
281
+ .number()
282
+ .int()
283
+ .gte(-1, 'max_answer_chars must be -1 or a positive integer')
284
+ .optional()
285
+ });
286
+ async apply(args) {
287
+ const { name_path, relative_path, include_kinds = [], exclude_kinds = [], max_answer_chars = -1 } = args;
288
+ const retriever = getSymbolRetriever(this.createLanguageServerSymbolRetriever());
289
+ const references = await findReferencingSymbols(retriever, name_path, relative_path, {
290
+ includeKinds: normalizeSymbolKinds(include_kinds),
291
+ excludeKinds: normalizeSymbolKinds(exclude_kinds)
292
+ });
293
+ const project = this.project;
294
+ const serialized = [];
295
+ for (const reference of references) {
296
+ const dict = sanitizeSymbolDict(symbolRepresentationToDict(reference.symbol, {
297
+ depth: 0,
298
+ include_body: false,
299
+ includeBody: false,
300
+ kind: true,
301
+ location: true
302
+ }));
303
+ const relativePath = typeof dict.relative_path === 'string'
304
+ ? dict.relative_path
305
+ : typeof dict.relativePath === 'string'
306
+ ? dict.relativePath
307
+ : null;
308
+ if (!relativePath) {
309
+ throw new Error('Referencing symbol is missing a relative path.');
310
+ }
311
+ const content = await resolveContentAroundLine(project, relativePath, reference.line);
312
+ dict.content_around_reference = content;
313
+ serialized.push(dict);
314
+ }
315
+ return this._limitLength(JSON.stringify(serialized), max_answer_chars);
316
+ }
317
+ }
318
+ export class ReplaceSymbolBodyTool extends Tool {
319
+ static markers = new Set([ToolMarkerSymbolicEdit]);
320
+ static description = 'Replaces the body of the specified symbol.';
321
+ static inputSchema = z.object({
322
+ name_path: z.string().min(1, 'name_path must not be empty'),
323
+ relative_path: z.string().min(1, 'relative_path must not be empty'),
324
+ body: z.string()
325
+ });
326
+ async apply(args) {
327
+ const { name_path, relative_path, body } = args;
328
+ const editor = this.createCodeEditor();
329
+ await callEditor(editor, ['replaceBody', 'replace_body'], name_path, relative_path, body);
330
+ return SUCCESS_RESULT;
331
+ }
332
+ }
333
+ export class InsertAfterSymbolTool extends Tool {
334
+ static markers = new Set([ToolMarkerSymbolicEdit]);
335
+ static description = 'Inserts content immediately after the specified symbol.';
336
+ static inputSchema = z.object({
337
+ name_path: z.string().min(1, 'name_path must not be empty'),
338
+ relative_path: z.string().min(1, 'relative_path must not be empty'),
339
+ body: z.string()
340
+ });
341
+ async apply(args) {
342
+ const { name_path, relative_path, body } = args;
343
+ const editor = this.createCodeEditor();
344
+ await callEditor(editor, ['insertAfterSymbol', 'insert_after_symbol'], name_path, relative_path, body);
345
+ return SUCCESS_RESULT;
346
+ }
347
+ }
348
+ export class InsertBeforeSymbolTool extends Tool {
349
+ static markers = new Set([ToolMarkerSymbolicEdit]);
350
+ static description = 'Inserts content immediately before the specified symbol.';
351
+ static inputSchema = z.object({
352
+ name_path: z.string().min(1, 'name_path must not be empty'),
353
+ relative_path: z.string().min(1, 'relative_path must not be empty'),
354
+ body: z.string()
355
+ });
356
+ async apply(args) {
357
+ const { name_path, relative_path, body } = args;
358
+ const editor = this.createCodeEditor();
359
+ await callEditor(editor, ['insertBeforeSymbol', 'insert_before_symbol'], name_path, relative_path, body);
360
+ return SUCCESS_RESULT;
361
+ }
362
+ }