@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,62 @@
1
+ import { type PathMatcher } from './util/file_system.js';
2
+ import { MatchedConsecutiveLines } from './text_utils.js';
3
+ import { ProjectConfig, type ProjectLike } from './config/serena_config.js';
4
+ import { SolidLanguageServer } from '../solidlsp/ls.js';
5
+ import type { Language } from '../solidlsp/ls_config.js';
6
+ export interface ProjectSearchOptions {
7
+ pattern: string;
8
+ relative_path?: string;
9
+ context_lines_before?: number;
10
+ context_lines_after?: number;
11
+ paths_include_glob?: string;
12
+ paths_exclude_glob?: string;
13
+ }
14
+ export interface CreateLanguageServerOptions {
15
+ logLevel: number;
16
+ lsTimeout: number | null;
17
+ traceLspCommunication: boolean;
18
+ lsSpecificSettings: Record<string, unknown>;
19
+ }
20
+ export declare class Project implements ProjectLike {
21
+ readonly projectRoot: string;
22
+ readonly projectConfig: ProjectConfig;
23
+ readonly isNewlyCreated: boolean;
24
+ private readonly ignoredPatterns;
25
+ private readonly ignoreMatcher;
26
+ private readonly languageMatcher;
27
+ constructor(init: {
28
+ projectRoot: string;
29
+ projectConfig: ProjectConfig;
30
+ isNewlyCreated?: boolean;
31
+ });
32
+ static load(projectRoot: string, autogenerate?: boolean): Project;
33
+ get projectName(): string;
34
+ get project_name(): string;
35
+ get language(): Language;
36
+ pathToSerenaDataFolder(): string;
37
+ path_to_serena_data_folder(): string;
38
+ pathToProjectYml(): string;
39
+ path_to_project_yml(): string;
40
+ readFile(relativePath: string): string;
41
+ read_file(relativePath: string): string;
42
+ getIgnoreSpec(): PathMatcher;
43
+ get_ignore_spec(): PathMatcher;
44
+ isIgnoredPath(candidate: string, ignoreNonSourceFiles?: boolean): boolean;
45
+ is_ignored_path(candidate: string, ignore_non_source_files?: boolean): boolean;
46
+ isPathInProject(candidate: string): boolean;
47
+ is_path_in_project(candidate: string): boolean;
48
+ relativePathExists(relativePath: string): boolean;
49
+ relative_path_exists(relativePath: string): boolean;
50
+ validateRelativePath(relativePath: string): void;
51
+ validate_relative_path(relativePath: string): void;
52
+ gatherSourceFiles(relativePath?: string): string[];
53
+ gather_source_files(relativePath?: string): string[];
54
+ searchSourceFilesForPattern(options: ProjectSearchOptions): MatchedConsecutiveLines[];
55
+ search_source_files_for_pattern(pattern: string, relative_path?: string, context_lines_before?: number, context_lines_after?: number, paths_include_glob?: string, paths_exclude_glob?: string): MatchedConsecutiveLines[];
56
+ retrieveContentAroundLine(relativeFilePath: string, line: number, contextLinesBefore?: number, contextLinesAfter?: number): MatchedConsecutiveLines;
57
+ retrieve_content_around_line(relative_file_path: string, line: number, context_lines_before?: number, context_lines_after?: number): MatchedConsecutiveLines;
58
+ createLanguageServer(options: CreateLanguageServerOptions): SolidLanguageServer;
59
+ private ensureSerenaDataGitignore;
60
+ private _isIgnoredRelativePath;
61
+ private resolveLanguageMatcher;
62
+ }
@@ -0,0 +1,321 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import ignore from 'ignore';
5
+ import { createSerenaLogger } from './util/logging.js';
6
+ import { GitignoreParser, matchPath } from './util/file_system.js';
7
+ import { MatchedConsecutiveLines, searchFiles } from './text_utils.js';
8
+ import { DEFAULT_TOOL_TIMEOUT, ProjectConfig } from './config/serena_config.js';
9
+ import { SERENA_MANAGED_DIR_IN_HOME, SERENA_MANAGED_DIR_NAME } from './constants.js';
10
+ import { SolidLanguageServer } from '../solidlsp/ls.js';
11
+ import { getLanguageFilenameMatcher } from '../solidlsp/ls_config.js';
12
+ const { logger: log } = createSerenaLogger({ name: 'serena.project', emitToConsole: true, level: 'info' });
13
+ class IgnoreMatcher {
14
+ engine;
15
+ constructor(patterns) {
16
+ this.engine = ignore();
17
+ if (patterns.length > 0) {
18
+ this.engine.add(patterns);
19
+ }
20
+ }
21
+ ignores(candidate) {
22
+ if (!candidate) {
23
+ return false;
24
+ }
25
+ return this.engine.ignores(candidate);
26
+ }
27
+ }
28
+ function normalizePattern(pattern) {
29
+ return pattern.replace(/\\/g, '/');
30
+ }
31
+ function toPosixRelative(relativePath) {
32
+ const replaced = relativePath.split(path.sep).join('/');
33
+ if (replaced === '.' || replaced === './') {
34
+ return '';
35
+ }
36
+ return replaced.replace(/^\.\//u, '');
37
+ }
38
+ function ensureDirectoryExists(dirPath) {
39
+ fs.mkdirSync(dirPath, { recursive: true });
40
+ }
41
+ function safeStat(candidate) {
42
+ try {
43
+ return fs.statSync(candidate);
44
+ }
45
+ catch (error) {
46
+ if (error?.code === 'ENOENT') {
47
+ return null;
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ export class Project {
53
+ projectRoot;
54
+ projectConfig;
55
+ isNewlyCreated;
56
+ ignoredPatterns;
57
+ ignoreMatcher;
58
+ languageMatcher;
59
+ constructor(init) {
60
+ this.projectRoot = path.resolve(init.projectRoot);
61
+ this.projectConfig = init.projectConfig;
62
+ this.isNewlyCreated = init.isNewlyCreated ?? false;
63
+ this.ensureSerenaDataGitignore();
64
+ const patterns = new Set();
65
+ for (const pattern of this.projectConfig.ignoredPaths) {
66
+ if (pattern) {
67
+ patterns.add(normalizePattern(pattern));
68
+ }
69
+ }
70
+ if (this.projectConfig.ignoreAllFilesInGitignore) {
71
+ const parser = new GitignoreParser(this.projectRoot);
72
+ for (const spec of parser.getIgnoreSpecs()) {
73
+ log.debug(`Adding ${spec.patterns.length} patterns from ${spec.filePath} to ignored paths.`);
74
+ for (const pattern of spec.patterns) {
75
+ patterns.add(normalizePattern(pattern));
76
+ }
77
+ }
78
+ }
79
+ this.ignoredPatterns = Array.from(patterns);
80
+ this.ignoreMatcher = new IgnoreMatcher(this.ignoredPatterns);
81
+ this.languageMatcher = this.resolveLanguageMatcher(this.projectConfig.language);
82
+ }
83
+ static load(projectRoot, autogenerate = true) {
84
+ const resolvedRoot = path.resolve(projectRoot);
85
+ if (!fs.existsSync(resolvedRoot)) {
86
+ throw new Error(`Project root not found: ${resolvedRoot}`);
87
+ }
88
+ const projectConfig = ProjectConfig.load(resolvedRoot, autogenerate);
89
+ return new Project({ projectRoot: resolvedRoot, projectConfig });
90
+ }
91
+ get projectName() {
92
+ return this.projectConfig.projectName;
93
+ }
94
+ get project_name() {
95
+ return this.projectName;
96
+ }
97
+ get language() {
98
+ return this.projectConfig.language;
99
+ }
100
+ pathToSerenaDataFolder() {
101
+ return path.join(this.projectRoot, SERENA_MANAGED_DIR_NAME);
102
+ }
103
+ path_to_serena_data_folder() {
104
+ return this.pathToSerenaDataFolder();
105
+ }
106
+ pathToProjectYml() {
107
+ return path.join(this.projectRoot, ProjectConfig.relPathToProjectYml());
108
+ }
109
+ path_to_project_yml() {
110
+ return this.pathToProjectYml();
111
+ }
112
+ readFile(relativePath) {
113
+ const absolutePath = path.resolve(this.projectRoot, relativePath);
114
+ if (!fs.existsSync(absolutePath)) {
115
+ throw new Error(`File not found: ${absolutePath}`);
116
+ }
117
+ const encoding = this.projectConfig.encoding;
118
+ if (!Buffer.isEncoding(encoding)) {
119
+ throw new Error(`Unsupported file encoding '${encoding}' for ${absolutePath}`);
120
+ }
121
+ return fs.readFileSync(absolutePath, { encoding });
122
+ }
123
+ read_file(relativePath) {
124
+ return this.readFile(relativePath);
125
+ }
126
+ getIgnoreSpec() {
127
+ return this.ignoreMatcher;
128
+ }
129
+ get_ignore_spec() {
130
+ return this.getIgnoreSpec();
131
+ }
132
+ isIgnoredPath(candidate, ignoreNonSourceFiles = false) {
133
+ const absolutePath = path.isAbsolute(candidate)
134
+ ? path.resolve(candidate)
135
+ : path.resolve(this.projectRoot, candidate);
136
+ if (!absolutePath.startsWith(`${this.projectRoot}${path.sep}`) && absolutePath !== this.projectRoot) {
137
+ log.warn(`Path ${absolutePath} is not relative to the project root ${this.projectRoot} and will be ignored.`);
138
+ return true;
139
+ }
140
+ const relative = path.relative(this.projectRoot, absolutePath);
141
+ return this._isIgnoredRelativePath(relative, ignoreNonSourceFiles);
142
+ }
143
+ is_ignored_path(candidate, ignore_non_source_files = false) {
144
+ return this.isIgnoredPath(candidate, ignore_non_source_files);
145
+ }
146
+ isPathInProject(candidate) {
147
+ const absolutePath = path.isAbsolute(candidate)
148
+ ? path.resolve(candidate)
149
+ : path.resolve(this.projectRoot, candidate);
150
+ const relative = path.relative(this.projectRoot, absolutePath);
151
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
152
+ }
153
+ is_path_in_project(candidate) {
154
+ return this.isPathInProject(candidate);
155
+ }
156
+ relativePathExists(relativePath) {
157
+ const absolutePath = path.resolve(this.projectRoot, relativePath);
158
+ return fs.existsSync(absolutePath);
159
+ }
160
+ relative_path_exists(relativePath) {
161
+ return this.relativePathExists(relativePath);
162
+ }
163
+ validateRelativePath(relativePath) {
164
+ if (!this.isPathInProject(relativePath)) {
165
+ throw new Error(`${relativePath} points to path outside of the repository root; cannot access for safety reasons`);
166
+ }
167
+ if (this.isIgnoredPath(relativePath)) {
168
+ throw new Error(`Path ${relativePath} is ignored; cannot access for safety reasons`);
169
+ }
170
+ }
171
+ validate_relative_path(relativePath) {
172
+ this.validateRelativePath(relativePath);
173
+ }
174
+ gatherSourceFiles(relativePath = '') {
175
+ const startPath = path.resolve(this.projectRoot, relativePath);
176
+ if (!fs.existsSync(startPath)) {
177
+ throw new Error(`Relative path ${startPath} not found.`);
178
+ }
179
+ const stats = safeStat(startPath);
180
+ if (!stats) {
181
+ throw new Error(`Failed to stat path: ${startPath}`);
182
+ }
183
+ if (stats.isFile()) {
184
+ return [toPosixRelative(path.relative(this.projectRoot, startPath))];
185
+ }
186
+ const queue = [startPath];
187
+ const results = [];
188
+ while (queue.length > 0) {
189
+ const current = queue.shift();
190
+ if (!current) {
191
+ continue;
192
+ }
193
+ let entries;
194
+ try {
195
+ entries = fs.readdirSync(current, { withFileTypes: true });
196
+ }
197
+ catch (error) {
198
+ log.warn(`Skipping directory ${current} during source discovery`, error);
199
+ continue;
200
+ }
201
+ for (const entry of entries) {
202
+ const absoluteEntryPath = path.join(current, entry.name);
203
+ const entryStats = safeStat(absoluteEntryPath);
204
+ if (!entryStats) {
205
+ log.warn(`File ${absoluteEntryPath} not found (possibly symlink), skipping in gatherSourceFiles.`);
206
+ continue;
207
+ }
208
+ const relativeEntryPath = path.relative(this.projectRoot, absoluteEntryPath);
209
+ if (entryStats.isDirectory()) {
210
+ if (!this.isIgnoredPath(relativeEntryPath)) {
211
+ queue.push(absoluteEntryPath);
212
+ }
213
+ continue;
214
+ }
215
+ if (entryStats.isFile()) {
216
+ try {
217
+ if (!this.isIgnoredPath(relativeEntryPath, true)) {
218
+ results.push(toPosixRelative(relativeEntryPath));
219
+ }
220
+ }
221
+ catch (error) {
222
+ log.warn(`Skipping file ${absoluteEntryPath} during source discovery`, error);
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return results;
228
+ }
229
+ gather_source_files(relativePath = '') {
230
+ return this.gatherSourceFiles(relativePath);
231
+ }
232
+ searchSourceFilesForPattern(options) {
233
+ const { pattern, relative_path = '', context_lines_before = 0, context_lines_after = 0, paths_include_glob, paths_exclude_glob } = options;
234
+ const relativeFilePaths = this.gatherSourceFiles(relative_path);
235
+ return searchFiles(relativeFilePaths, pattern, {
236
+ rootPath: this.projectRoot,
237
+ contextLinesBefore: context_lines_before,
238
+ contextLinesAfter: context_lines_after,
239
+ pathsIncludeGlob: paths_include_glob ?? null,
240
+ pathsExcludeGlob: paths_exclude_glob ?? null
241
+ });
242
+ }
243
+ search_source_files_for_pattern(pattern, relative_path = '', context_lines_before = 0, context_lines_after = 0, paths_include_glob, paths_exclude_glob) {
244
+ return this.searchSourceFilesForPattern({
245
+ pattern,
246
+ relative_path,
247
+ context_lines_before,
248
+ context_lines_after,
249
+ paths_include_glob,
250
+ paths_exclude_glob
251
+ });
252
+ }
253
+ retrieveContentAroundLine(relativeFilePath, line, contextLinesBefore = 0, contextLinesAfter = 0) {
254
+ const fileContents = this.readFile(relativeFilePath);
255
+ return MatchedConsecutiveLines.fromFileContents({
256
+ fileContents,
257
+ line,
258
+ contextLinesBefore,
259
+ contextLinesAfter,
260
+ sourceFilePath: relativeFilePath
261
+ });
262
+ }
263
+ retrieve_content_around_line(relative_file_path, line, context_lines_before = 0, context_lines_after = 0) {
264
+ return this.retrieveContentAroundLine(relative_file_path, line, context_lines_before, context_lines_after);
265
+ }
266
+ createLanguageServer(options) {
267
+ const lsTimeout = options.lsTimeout === undefined ? DEFAULT_TOOL_TIMEOUT - 5 : options.lsTimeout;
268
+ return SolidLanguageServer.create({
269
+ codeLanguage: this.projectConfig.language,
270
+ traceLspCommunication: options.traceLspCommunication,
271
+ startIndependentLspProcess: true,
272
+ ignoredPaths: this.projectConfig.ignoredPaths
273
+ }, { level: options.logLevel }, this.projectRoot, {
274
+ timeout: lsTimeout,
275
+ solidlspSettings: {
276
+ lsSpecificSettings: options.lsSpecificSettings ?? {},
277
+ solidlspDir: SERENA_MANAGED_DIR_IN_HOME,
278
+ projectDataRelativePath: SERENA_MANAGED_DIR_NAME
279
+ }
280
+ });
281
+ }
282
+ ensureSerenaDataGitignore() {
283
+ const gitignorePath = path.join(this.pathToSerenaDataFolder(), '.gitignore');
284
+ if (fs.existsSync(gitignorePath)) {
285
+ return;
286
+ }
287
+ ensureDirectoryExists(path.dirname(gitignorePath));
288
+ log.info(`Creating .gitignore file in ${gitignorePath}`);
289
+ fs.writeFileSync(gitignorePath, `/${SolidLanguageServer.CACHE_FOLDER_NAME}\n`, {
290
+ encoding: 'utf-8'
291
+ });
292
+ }
293
+ _isIgnoredRelativePath(relativePath, ignoreNonSourceFiles = true) {
294
+ const normalizedRelative = toPosixRelative(path.normalize(relativePath));
295
+ const absolutePath = path.resolve(this.projectRoot, normalizedRelative);
296
+ if (!fs.existsSync(absolutePath)) {
297
+ log.warn(`File ${absolutePath} not found while evaluating ignore rules; treating as ignored.`);
298
+ return true;
299
+ }
300
+ const stats = fs.statSync(absolutePath);
301
+ if (stats.isFile() && ignoreNonSourceFiles) {
302
+ if (this.languageMatcher && !this.languageMatcher.isRelevantFilename(path.basename(absolutePath))) {
303
+ return true;
304
+ }
305
+ }
306
+ const parts = normalizedRelative.split('/');
307
+ if (parts.length > 0 && parts[0] === '.git') {
308
+ return true;
309
+ }
310
+ return matchPath(normalizedRelative, this.ignoreMatcher, this.projectRoot);
311
+ }
312
+ resolveLanguageMatcher(language) {
313
+ try {
314
+ return getLanguageFilenameMatcher(language);
315
+ }
316
+ catch (error) {
317
+ log.warn(`Failed to resolve filename matcher for language ${language}`, error);
318
+ return null;
319
+ }
320
+ }
321
+ }
@@ -0,0 +1,20 @@
1
+ import { PromptFactory, type CreateOnboardingPromptParams, type CreateSystemPromptParams } from './generated/generated_prompt_factory.js';
2
+ import type { PromptFactoryBaseOptions } from '../interprompt/prompt_factory.js';
3
+ export interface SerenaPromptFactoryOptions extends Partial<PromptFactoryBaseOptions> {
4
+ userPromptDir?: string;
5
+ internalPromptDir?: string;
6
+ }
7
+ export type CreateSystemPromptOptions = CreateSystemPromptParams;
8
+ export type CreateOnboardingPromptOptions = CreateOnboardingPromptParams;
9
+ export declare class SerenaPromptFactory extends PromptFactory {
10
+ private readonly searchDirectories;
11
+ constructor(options?: SerenaPromptFactoryOptions);
12
+ getPromptDirectories(): string[];
13
+ createSystemPrompt(options: CreateSystemPromptOptions): string;
14
+ listPromptTemplateNames(): string[];
15
+ getPromptTemplateParameters(name: string): string[];
16
+ renderPrompt(name: string, params: Record<string, unknown>): string;
17
+ hasPromptTemplate(name: string, langCode?: string): boolean;
18
+ listPromptListNames(): string[];
19
+ getPromptListByName(name: string): string[];
20
+ }
@@ -0,0 +1,42 @@
1
+ import fs from 'node:fs';
2
+ import { PROMPT_TEMPLATES_DIR_IN_USER_HOME, PROMPT_TEMPLATES_DIR_INTERNAL } from './constants.js';
3
+ import { PromptFactory } from './generated/generated_prompt_factory.js';
4
+ export class SerenaPromptFactory extends PromptFactory {
5
+ searchDirectories;
6
+ constructor(options = {}) {
7
+ const userPromptDir = options.userPromptDir ?? PROMPT_TEMPLATES_DIR_IN_USER_HOME;
8
+ const internalPromptDir = options.internalPromptDir ?? PROMPT_TEMPLATES_DIR_INTERNAL;
9
+ fs.mkdirSync(userPromptDir, { recursive: true });
10
+ const promptsDir = [userPromptDir, internalPromptDir];
11
+ super({
12
+ promptsDir,
13
+ langCode: options.langCode,
14
+ fallbackMode: options.fallbackMode
15
+ });
16
+ this.searchDirectories = [...promptsDir];
17
+ }
18
+ getPromptDirectories() {
19
+ return [...this.searchDirectories];
20
+ }
21
+ createSystemPrompt(options) {
22
+ return super.createSystemPrompt(options);
23
+ }
24
+ listPromptTemplateNames() {
25
+ return this.promptCollection.getPromptTemplateNames();
26
+ }
27
+ getPromptTemplateParameters(name) {
28
+ return this.promptCollection.getPromptTemplateParameters(name);
29
+ }
30
+ renderPrompt(name, params) {
31
+ return this.renderPromptTemplate(name, params);
32
+ }
33
+ hasPromptTemplate(name, langCode = this.langCode) {
34
+ return this.promptCollection.hasPromptTemplate(name, langCode);
35
+ }
36
+ listPromptListNames() {
37
+ return this.promptCollection.getPromptListNames();
38
+ }
39
+ getPromptListByName(name) {
40
+ return this.getPromptList(name).items;
41
+ }
42
+ }
@@ -0,0 +1,8 @@
1
+ description: All tools except InitialInstructionsTool for agent context
2
+ prompt: |
3
+ You are running in agent context where the system prompt is provided externally. You should use symbolic
4
+ tools when possible for code understanding and modification.
5
+ excluded_tools:
6
+ - initial_instructions
7
+
8
+ tool_description_overrides: {}
@@ -0,0 +1,28 @@
1
+ description: A configuration specific for chatgpt, which has a limit of 30 tools and requires short descriptions.
2
+ prompt: |
3
+ You are running in desktop app context where the tools give you access to the code base as well as some
4
+ access to the file system, if configured. You interact with the user through a chat interface that is separated
5
+ from the code base. As a consequence, if you are in interactive mode, your communication with the user should
6
+ involve high-level thinking and planning as well as some summarization of any code edits that you make.
7
+ For viewing the code edits the user will view them in a separate code editor window, and the back-and-forth
8
+ between the chat and the code editor should be minimized as well as facilitated by you.
9
+ If complex changes have been made, advise the user on how to review them in the code editor.
10
+ If complex relationships that the user asked for should be visualized or explained, consider creating
11
+ a diagram in addition to your text-based communication. Note that in the chat interface you have various rendering
12
+ options for text, html, and mermaid diagrams, as has been explained to you in your initial instructions.
13
+ excluded_tools: []
14
+ included_optional_tools:
15
+ - switch_modes
16
+
17
+ tool_description_overrides:
18
+ find_symbol: |
19
+ Retrieves symbols matching `name_path` in a file.
20
+ Use `depth > 0` to include children. `name_path` can be: "foo": any symbol named "foo"; "foo/bar": "bar" within "foo"; "/foo/bar": only top-level "foo/bar"
21
+ replace_regex: |
22
+ Replaces text using regular expressions. Preferred for smaller edits where symbol-level tools aren't appropriate.
23
+ Use wildcards (.*?) to match large sections efficiently: "beginning.*?end" instead of specifying exact content.
24
+ Essential for multi-line replacements.
25
+ search_for_pattern: |
26
+ Flexible pattern search across codebase. Prefer symbolic operations when possible.
27
+ Uses DOTALL matching. Use non-greedy quantifiers (.*?) to avoid over-matching.
28
+ Supports file filtering via globs and code-only restriction.
@@ -0,0 +1,27 @@
1
+ description: Non-symbolic editing tools and general shell tool are excluded
2
+ prompt: |
3
+ You are running in IDE assistant context where file operations, basic (line-based) edits and reads,
4
+ and shell commands are handled by your own, internal tools.
5
+ The initial instructions and the current config inform you on which tools are available to you,
6
+ and how to use them.
7
+ Don't attempt to use any excluded tools, instead rely on your own internal tools
8
+ for achieving the basic file or shell operations.
9
+
10
+ If serena's tools can be used for achieving your task,
11
+ you should prioritize them. In particular, it is important that you avoid reading entire source code files,
12
+ unless it is strictly necessary! Instead, for exploring and reading code in a token-efficient manner,
13
+ you should use serena's overview and symbolic search tools. The call of the read_file tool on an entire source code
14
+ file should only happen in exceptional cases, usually you should first explore the file (by itself or as part of exploring
15
+ the directory containing it) using the symbol_overview tool, and then make targeted reads using find_symbol and other symbolic tools.
16
+ For non-code files or for reads where you don't know the symbol's name path you can use the patterns searching tool,
17
+ using the read_file as a last resort.
18
+
19
+ excluded_tools:
20
+ - create_text_file
21
+ - read_file
22
+ - execute_shell_command
23
+ - prepare_for_new_conversation
24
+ - replace_regex
25
+
26
+
27
+ tool_description_overrides: {}
@@ -0,0 +1,11 @@
1
+ # See Serena's documentation for more details on concept of contexts.
2
+ description: Description of the context, not used in the code.
3
+ prompt: Prompt that will form part of the system prompt/initial instructions for agents started in this context.
4
+ excluded_tools: []
5
+
6
+ # several tools are excluded by default and have to be explicitly included by the user
7
+ included_optional_tools: []
8
+
9
+ # mapping of tool names to an override of their descriptions (the default description is the docstring of the Tool's apply method).
10
+ # Sometimes, tool descriptions are too long (e.g., for ChatGPT), or users may want to override them for another reason.
11
+ tool_description_overrides: {}
@@ -0,0 +1,17 @@
1
+ description: All tools included for desktop app context
2
+ prompt: |
3
+ You are running in desktop app context where the tools give you access to the code base as well as some
4
+ access to the file system, if configured. You interact with the user through a chat interface that is separated
5
+ from the code base. As a consequence, if you are in interactive mode, your communication with the user should
6
+ involve high-level thinking and planning as well as some summarization of any code edits that you make.
7
+ For viewing the code edits the user will view them in a separate code editor window, and the back-and-forth
8
+ between the chat and the code editor should be minimized as well as facilitated by you.
9
+ If complex changes have been made, advise the user on how to review them in the code editor.
10
+ If complex relationships that the user asked for should be visualized or explained, consider creating
11
+ a diagram in addition to your text-based communication. Note that in the chat interface you have various rendering
12
+ options for text, html, and mermaid diagrams, as has been explained to you in your initial instructions.
13
+ excluded_tools: []
14
+ included_optional_tools:
15
+ - switch_modes
16
+
17
+ tool_description_overrides: {}
@@ -0,0 +1,26 @@
1
+ description: Non-symbolic editing tools and general shell tool are excluded
2
+ prompt: |
3
+ You are running in IDE assistant context where file operations, basic (line-based) edits and reads,
4
+ and shell commands are handled by your own, internal tools.
5
+ The initial instructions and the current config inform you on which tools are available to you,
6
+ and how to use them.
7
+ Don't attempt to use any excluded tools, instead rely on your own internal tools
8
+ for achieving the basic file or shell operations.
9
+
10
+ If serena's tools can be used for achieving your task,
11
+ you should prioritize them. In particular, it is important that you avoid reading entire source code files,
12
+ unless it is strictly necessary! Instead, for exploring and reading code in a token-efficient manner,
13
+ you should use serena's overview and symbolic search tools.
14
+ Before reading a full file, it is usually best to first explore the file using the symbol_overview tool,
15
+ and then make targeted reads using find_symbol and other symbolic tools.
16
+ For non-code files or for reads where you don't know the symbol's name path, you can use the pattern searching tool,
17
+ and read full files only as a last resort.
18
+
19
+ excluded_tools:
20
+ - create_text_file
21
+ - read_file
22
+ - execute_shell_command
23
+ - prepare_for_new_conversation
24
+ - replace_regex
25
+
26
+ tool_description_overrides: {}
@@ -0,0 +1,8 @@
1
+ description: All tools except InitialInstructionsTool for agent context, uses OpenAI compatible tool definitions
2
+ prompt: |
3
+ You are running in agent context where the system prompt is provided externally. You should use symbolic
4
+ tools when possible for code understanding and modification.
5
+ excluded_tools:
6
+ - initial_instructions
7
+
8
+ tool_description_overrides: {}
@@ -0,0 +1,15 @@
1
+ description: JetBrains tools replace language server-based tools
2
+ prompt: |
3
+ You have access to the very powerful JetBrains tools for symbolic operations:
4
+ * `jet_brains_find_symbol` replaces `find_symbol`
5
+ * `jet_brains_find_referencing_symbols` replaces `find_referencing_symbols`
6
+ * `jet_brains_get_symbols_overview` replaces `get_symbols_overview`
7
+ excluded_tools:
8
+ - find_symbol
9
+ - find_referencing_symbols
10
+ - get_symbols_overview
11
+ - restart_language_server
12
+ included_optional_tools:
13
+ - jet_brains_find_symbol
14
+ - jet_brains_find_referencing_symbols
15
+ - jet_brains_get_symbols_overview