headlesscode 1.0.2

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 (232) hide show
  1. package/ATTRIBUTION.md +53 -0
  2. package/CODE_OF_CONDUCT.md +130 -0
  3. package/CONTRIBUTING.md +107 -0
  4. package/LICENSE +202 -0
  5. package/README.md +486 -0
  6. package/SECURITY.md +211 -0
  7. package/bin/headlesscode.mjs +83 -0
  8. package/package.json +63 -0
  9. package/shared/prompts/review-mode-prompt-short.md +93 -0
  10. package/shared/prompts/review-mode-prompt.md +281 -0
  11. package/shared/rules-code/rules.md +22 -0
  12. package/shared/stacks/cpp/rules.md +30 -0
  13. package/shared/stacks/fastapi/rules.md +30 -0
  14. package/shared/stacks/javascript/rules.md +37 -0
  15. package/shared/stacks/postgresql/rules.md +31 -0
  16. package/shared/stacks/python/rules.md +35 -0
  17. package/shared/stacks/react/rules.md +11 -0
  18. package/shared/stacks/typescript/rules.md +10 -0
  19. package/src/budget/budget.ts +221 -0
  20. package/src/budget/concurrency.ts +126 -0
  21. package/src/budget/cost.ts +309 -0
  22. package/src/budget/index.ts +8 -0
  23. package/src/checkpoints/cli.ts +256 -0
  24. package/src/checkpoints/service.ts +227 -0
  25. package/src/cli.ts +1535 -0
  26. package/src/cloud/docker-provider.ts +334 -0
  27. package/src/cloud/provider.ts +300 -0
  28. package/src/codeintel/call-graph.ts +78 -0
  29. package/src/codeintel/find-references.ts +123 -0
  30. package/src/codeintel/go-to-definition.ts +193 -0
  31. package/src/codeintel/handlers.ts +190 -0
  32. package/src/codeintel/import-graph.ts +173 -0
  33. package/src/codeintel/outline.ts +180 -0
  34. package/src/codeintel/position.ts +77 -0
  35. package/src/codeintel/program.ts +350 -0
  36. package/src/codeintel/rename-symbol.ts +213 -0
  37. package/src/codeintel/tools.ts +280 -0
  38. package/src/codemap/build.ts +135 -0
  39. package/src/codemap/cli.ts +190 -0
  40. package/src/codemap/extract.ts +339 -0
  41. package/src/codemap/files.ts +236 -0
  42. package/src/codemap/fingerprint.ts +65 -0
  43. package/src/codemap/flows.ts +62 -0
  44. package/src/codemap/html.ts +451 -0
  45. package/src/codemap/lock.ts +80 -0
  46. package/src/codemap/types.ts +101 -0
  47. package/src/codesearch/airunner-embedder.ts +185 -0
  48. package/src/codesearch/chunk.ts +339 -0
  49. package/src/codesearch/cli.ts +223 -0
  50. package/src/codesearch/embedder.ts +332 -0
  51. package/src/codesearch/files.ts +280 -0
  52. package/src/codesearch/index.ts +469 -0
  53. package/src/codesearch/ollama-embedder.ts +205 -0
  54. package/src/codesearch/search.ts +141 -0
  55. package/src/codesearch/types.ts +100 -0
  56. package/src/config/mode-models.ts +218 -0
  57. package/src/dashboard/aggregate.ts +364 -0
  58. package/src/dashboard/chat-thread.ts +141 -0
  59. package/src/dashboard/checkpoints.ts +124 -0
  60. package/src/dashboard/cli.ts +193 -0
  61. package/src/dashboard/codemap.ts +44 -0
  62. package/src/dashboard/files.ts +121 -0
  63. package/src/dashboard/page.ts +2803 -0
  64. package/src/dashboard/self-improvement-metrics.ts +282 -0
  65. package/src/dashboard/server.ts +1103 -0
  66. package/src/dashboard/session-launch.ts +310 -0
  67. package/src/dashboard/timeline.ts +273 -0
  68. package/src/dashboard/tool-exec.ts +107 -0
  69. package/src/dashboard/trend-cli.ts +141 -0
  70. package/src/dashboard/trend.ts +413 -0
  71. package/src/decision-proxy/cli.ts +261 -0
  72. package/src/decision-proxy/proxy.ts +569 -0
  73. package/src/deploy/gate-cli.ts +147 -0
  74. package/src/deploy/gate.ts +254 -0
  75. package/src/engine/condense.ts +512 -0
  76. package/src/engine/events.ts +428 -0
  77. package/src/engine/handoff.ts +71 -0
  78. package/src/engine/lazy-tools.ts +160 -0
  79. package/src/engine/local-explore.ts +653 -0
  80. package/src/engine/logger.ts +96 -0
  81. package/src/engine/loop.ts +5517 -0
  82. package/src/engine/parser.ts +347 -0
  83. package/src/engine/prompt.ts +860 -0
  84. package/src/engine/reports.ts +47 -0
  85. package/src/engine/stacks.ts +448 -0
  86. package/src/engine/types.ts +291 -0
  87. package/src/engine/usage.ts +186 -0
  88. package/src/github/app-auth.ts +161 -0
  89. package/src/github/cli.ts +448 -0
  90. package/src/github/installations.ts +133 -0
  91. package/src/github/pr.ts +321 -0
  92. package/src/github/provision.ts +118 -0
  93. package/src/github/push.ts +122 -0
  94. package/src/index-util.ts +50 -0
  95. package/src/index.ts +81 -0
  96. package/src/init/cli.ts +248 -0
  97. package/src/init/gitignore.ts +74 -0
  98. package/src/llm/ollama.ts +308 -0
  99. package/src/llm/openrouter.ts +868 -0
  100. package/src/llm/preflight.ts +367 -0
  101. package/src/llm/transcript-capture.ts +84 -0
  102. package/src/memory/embed.ts +110 -0
  103. package/src/memory/index.ts +22 -0
  104. package/src/memory/local.ts +259 -0
  105. package/src/memory/summarizer.ts +283 -0
  106. package/src/memory/types.ts +153 -0
  107. package/src/memory/uwuchat.ts +157 -0
  108. package/src/migrate/cli.ts +115 -0
  109. package/src/orchestrator/analyze-cli.ts +104 -0
  110. package/src/orchestrator/auto-split.ts +206 -0
  111. package/src/orchestrator/cleanup.ts +1003 -0
  112. package/src/orchestrator/cli.ts +3571 -0
  113. package/src/orchestrator/cost-estimate.ts +564 -0
  114. package/src/orchestrator/cost-history-cli.ts +242 -0
  115. package/src/orchestrator/cost-history.ts +397 -0
  116. package/src/orchestrator/git-sync.ts +250 -0
  117. package/src/orchestrator/index.ts +153 -0
  118. package/src/orchestrator/log-analysis.ts +0 -0
  119. package/src/orchestrator/merge-check.ts +108 -0
  120. package/src/orchestrator/pipeline.ts +411 -0
  121. package/src/orchestrator/resume.ts +1940 -0
  122. package/src/orchestrator/reviewer.ts +503 -0
  123. package/src/orchestrator/split.ts +296 -0
  124. package/src/orchestrator/state.ts +542 -0
  125. package/src/orchestrator/status.ts +697 -0
  126. package/src/orchestrator/verification-gate.ts +134 -0
  127. package/src/orchestrator/watch.ts +898 -0
  128. package/src/permissions/commands.ts +1083 -0
  129. package/src/permissions/config.ts +241 -0
  130. package/src/permissions/index.ts +12 -0
  131. package/src/permissions/protected-files.ts +96 -0
  132. package/src/permissions/store-protection.ts +272 -0
  133. package/src/project-store.ts +648 -0
  134. package/src/projects/cli.ts +382 -0
  135. package/src/qa/qa.ts +487 -0
  136. package/src/tools/browser/handler.ts +346 -0
  137. package/src/tools/browser/service.ts +406 -0
  138. package/src/tools/browser/smoke.ts +78 -0
  139. package/src/tools/browser/tool.ts +99 -0
  140. package/src/tools/executor.ts +2575 -0
  141. package/src/tools/language-detect.ts +183 -0
  142. package/src/tools/output-summarizer.ts +369 -0
  143. package/src/tools/run-tests.ts +302 -0
  144. package/src/tools/set-indentation-tool.ts +49 -0
  145. package/src/tools/test-selection.ts +160 -0
  146. package/src/vendor/tests/smoke.ts +103 -0
  147. package/src/vendor/zoo-code/VENDOR-NOTES.md +213 -0
  148. package/src/vendor/zoo-code/shim/anthropic.ts +71 -0
  149. package/src/vendor/zoo-code/shim/openai.d.ts +60 -0
  150. package/src/vendor/zoo-code/shim/os-name.ts +18 -0
  151. package/src/vendor/zoo-code/shim/strip-bom.ts +14 -0
  152. package/src/vendor/zoo-code/shim/vscode.ts +76 -0
  153. package/src/vendor/zoo-code/src/core/config/CustomModesManager.ts +1015 -0
  154. package/src/vendor/zoo-code/src/core/diff/strategies/multi-search-replace.ts +670 -0
  155. package/src/vendor/zoo-code/src/core/prompts/sections/capabilities.ts +46 -0
  156. package/src/vendor/zoo-code/src/core/prompts/sections/custom-instructions.ts +559 -0
  157. package/src/vendor/zoo-code/src/core/prompts/sections/index.ts +10 -0
  158. package/src/vendor/zoo-code/src/core/prompts/sections/markdown-formatting.ts +7 -0
  159. package/src/vendor/zoo-code/src/core/prompts/sections/modes.ts +35 -0
  160. package/src/vendor/zoo-code/src/core/prompts/sections/objective.ts +13 -0
  161. package/src/vendor/zoo-code/src/core/prompts/sections/rules.ts +95 -0
  162. package/src/vendor/zoo-code/src/core/prompts/sections/skills.ts +105 -0
  163. package/src/vendor/zoo-code/src/core/prompts/sections/system-info.ts +30 -0
  164. package/src/vendor/zoo-code/src/core/prompts/sections/tool-use-guidelines.ts +9 -0
  165. package/src/vendor/zoo-code/src/core/prompts/sections/tool-use.ts +7 -0
  166. package/src/vendor/zoo-code/src/core/prompts/system.ts +176 -0
  167. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/access_mcp_resource.ts +41 -0
  168. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_diff.ts +40 -0
  169. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/apply_patch.ts +61 -0
  170. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/ask_followup_question.ts +62 -0
  171. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/attempt_completion.ts +33 -0
  172. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/codebase_search.ts +43 -0
  173. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/converters.ts +109 -0
  174. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit.ts +48 -0
  175. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/edit_file.ts +72 -0
  176. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/execute_command.ts +54 -0
  177. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/generate_image.ts +51 -0
  178. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/index.ts +75 -0
  179. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/list_files.ts +41 -0
  180. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/mcp_server.ts +75 -0
  181. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/new_task.ts +39 -0
  182. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_command_output.ts +81 -0
  183. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/read_file.ts +169 -0
  184. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/run_slash_command.ts +31 -0
  185. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_files.ts +50 -0
  186. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/search_replace.ts +51 -0
  187. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/skill.ts +33 -0
  188. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/switch_mode.ts +31 -0
  189. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/update_todo_list.ts +54 -0
  190. package/src/vendor/zoo-code/src/core/prompts/tools/native-tools/write_to_file.ts +40 -0
  191. package/src/vendor/zoo-code/src/core/prompts/types.ts +12 -0
  192. package/src/vendor/zoo-code/src/i18n/index.ts +19 -0
  193. package/src/vendor/zoo-code/src/integrations/misc/extract-text.ts +81 -0
  194. package/src/vendor/zoo-code/src/services/checkpoints/RepoPerTaskCheckpointService.ts +15 -0
  195. package/src/vendor/zoo-code/src/services/checkpoints/ShadowCheckpointService.ts +553 -0
  196. package/src/vendor/zoo-code/src/services/checkpoints/excludes.ts +212 -0
  197. package/src/vendor/zoo-code/src/services/checkpoints/index.ts +3 -0
  198. package/src/vendor/zoo-code/src/services/checkpoints/types.ts +35 -0
  199. package/src/vendor/zoo-code/src/services/code-index/manager.ts +19 -0
  200. package/src/vendor/zoo-code/src/services/mcp/McpHub.ts +36 -0
  201. package/src/vendor/zoo-code/src/services/roo-config/index.ts +441 -0
  202. package/src/vendor/zoo-code/src/services/search/file-search.ts +143 -0
  203. package/src/vendor/zoo-code/src/services/skills/SkillsManager.ts +20 -0
  204. package/src/vendor/zoo-code/src/shared/globalFileNames.ts +9 -0
  205. package/src/vendor/zoo-code/src/shared/language.ts +43 -0
  206. package/src/vendor/zoo-code/src/shared/modes.ts +257 -0
  207. package/src/vendor/zoo-code/src/shared/tools.ts +385 -0
  208. package/src/vendor/zoo-code/src/utils/fs.ts +39 -0
  209. package/src/vendor/zoo-code/src/utils/globalContext.ts +22 -0
  210. package/src/vendor/zoo-code/src/utils/json-schema.ts +16 -0
  211. package/src/vendor/zoo-code/src/utils/logging.ts +21 -0
  212. package/src/vendor/zoo-code/src/utils/mcp-name.ts +190 -0
  213. package/src/vendor/zoo-code/src/utils/object.ts +18 -0
  214. package/src/vendor/zoo-code/src/utils/path.ts +94 -0
  215. package/src/vendor/zoo-code/src/utils/shell.ts +376 -0
  216. package/src/vendor/zoo-code/src/utils/text-normalization.ts +99 -0
  217. package/src/vendor/zoo-code/types/global-settings.ts +19 -0
  218. package/src/vendor/zoo-code/types/index.ts +22 -0
  219. package/src/vendor/zoo-code/types/message.ts +375 -0
  220. package/src/vendor/zoo-code/types/mode.ts +241 -0
  221. package/src/vendor/zoo-code/types/todo.ts +19 -0
  222. package/src/vendor/zoo-code/types/tool-params.ts +116 -0
  223. package/src/vendor/zoo-code/types/tool.ts +67 -0
  224. package/src/vendor/zoo-code/types/vscode.ts +84 -0
  225. package/src/vision/describe.ts +242 -0
  226. package/src/vision/tool.ts +91 -0
  227. package/src/watcher/cli.ts +369 -0
  228. package/src/watcher/github.ts +304 -0
  229. package/src/watcher/index.ts +59 -0
  230. package/src/watcher/state.ts +254 -0
  231. package/src/watcher/watch.ts +562 -0
  232. package/tsconfig.json +18 -0
@@ -0,0 +1,257 @@
1
+ import * as vscode from "../../shim/vscode"
2
+
3
+ import {
4
+ type GroupEntry,
5
+ type ModeConfig,
6
+ type CustomModePrompts,
7
+ type ToolGroup,
8
+ type PromptComponent,
9
+ DEFAULT_MODES,
10
+ } from "../../types"
11
+
12
+ import { addCustomInstructions } from "../core/prompts/sections/custom-instructions"
13
+
14
+ import { TOOL_GROUPS, ALWAYS_AVAILABLE_TOOLS } from "./tools"
15
+
16
+ export type Mode = string
17
+
18
+ // Helper to extract group name regardless of format
19
+ export function getGroupName(group: GroupEntry): ToolGroup {
20
+ if (typeof group === "string") {
21
+ return group
22
+ }
23
+
24
+ return group[0]
25
+ }
26
+
27
+ // Helper to get all tools for a mode
28
+ export function getToolsForMode(groups: readonly GroupEntry[]): string[] {
29
+ const tools = new Set<string>()
30
+
31
+ // Add tools from each group (excluding customTools which are opt-in only)
32
+ groups.forEach((group) => {
33
+ const groupName = getGroupName(group)
34
+ const groupConfig = TOOL_GROUPS[groupName]
35
+ groupConfig.tools.forEach((tool: string) => tools.add(tool))
36
+ })
37
+
38
+ // Always add required tools
39
+ ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))
40
+
41
+ return Array.from(tools)
42
+ }
43
+
44
+ // Main modes configuration as an ordered array
45
+ export const modes = DEFAULT_MODES
46
+
47
+ // Export the default mode slug
48
+ export const defaultModeSlug = modes[0].slug
49
+
50
+ // Helper functions
51
+ export function getModeBySlug(slug: string, customModes?: ModeConfig[]): ModeConfig | undefined {
52
+ // Check custom modes first
53
+ const customMode = customModes?.find((mode) => mode.slug === slug)
54
+ if (customMode) {
55
+ return customMode
56
+ }
57
+ // Then check built-in modes
58
+ return modes.find((mode) => mode.slug === slug)
59
+ }
60
+
61
+ export function getModeConfig(slug: string, customModes?: ModeConfig[]): ModeConfig {
62
+ const mode = getModeBySlug(slug, customModes)
63
+ if (!mode) {
64
+ throw new Error(`No mode found for slug: ${slug}`)
65
+ }
66
+ return mode
67
+ }
68
+
69
+ // Get all available modes, with custom modes overriding built-in modes
70
+ export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] {
71
+ if (!customModes?.length) {
72
+ return [...modes]
73
+ }
74
+
75
+ // Start with built-in modes
76
+ const allModes = [...modes]
77
+
78
+ // Process custom modes
79
+ customModes.forEach((customMode) => {
80
+ const index = allModes.findIndex((mode) => mode.slug === customMode.slug)
81
+ if (index !== -1) {
82
+ // Override existing mode
83
+ allModes[index] = customMode
84
+ } else {
85
+ // Add new mode
86
+ allModes.push(customMode)
87
+ }
88
+ })
89
+
90
+ return allModes
91
+ }
92
+
93
+ // Check if a mode is custom or an override
94
+ export function isCustomMode(slug: string, customModes?: ModeConfig[]): boolean {
95
+ return !!customModes?.some((mode) => mode.slug === slug)
96
+ }
97
+
98
+ /**
99
+ * Find a mode by its slug, don't fall back to built-in modes
100
+ */
101
+ export function findModeBySlug(slug: string, modes: readonly ModeConfig[] | undefined): ModeConfig | undefined {
102
+ return modes?.find((mode) => mode.slug === slug)
103
+ }
104
+
105
+ /**
106
+ * Get the mode selection based on the provided mode slug, prompt component, and custom modes.
107
+ * If a custom mode is found, it takes precedence over the built-in modes.
108
+ * If no custom mode is found, the built-in mode is used with partial merging from promptComponent.
109
+ * If neither is found, the default mode is used.
110
+ */
111
+ export function getModeSelection(mode: string, promptComponent?: PromptComponent, customModes?: ModeConfig[]) {
112
+ const customMode = findModeBySlug(mode, customModes)
113
+ const builtInMode = findModeBySlug(mode, modes)
114
+
115
+ // If we have a custom mode, use it entirely
116
+ if (customMode) {
117
+ return {
118
+ roleDefinition: customMode.roleDefinition || "",
119
+ baseInstructions: customMode.customInstructions || "",
120
+ description: customMode.description || "",
121
+ }
122
+ }
123
+
124
+ // Otherwise, use built-in mode as base and merge with promptComponent
125
+ const baseMode = builtInMode || modes[0] // fallback to default mode
126
+
127
+ return {
128
+ roleDefinition: promptComponent?.roleDefinition || baseMode.roleDefinition || "",
129
+ baseInstructions: promptComponent?.customInstructions || baseMode.customInstructions || "",
130
+ description: baseMode.description || "",
131
+ }
132
+ }
133
+
134
+ // Custom error class for file restrictions
135
+ export class FileRestrictionError extends Error {
136
+ constructor(mode: string, pattern: string, description: string | undefined, filePath: string, tool?: string) {
137
+ const toolInfo = tool ? `Tool '${tool}' in mode '${mode}'` : `This mode (${mode})`
138
+ super(
139
+ `${toolInfo} can only edit files matching pattern: ${pattern}${description ? ` (${description})` : ""}. Got: ${filePath}`,
140
+ )
141
+ this.name = "FileRestrictionError"
142
+ }
143
+ }
144
+
145
+ // Create the mode-specific default prompts
146
+ export const defaultPrompts: Readonly<CustomModePrompts> = Object.freeze(
147
+ Object.fromEntries(
148
+ modes.map((mode) => [
149
+ mode.slug,
150
+ {
151
+ roleDefinition: mode.roleDefinition,
152
+ whenToUse: mode.whenToUse,
153
+ customInstructions: mode.customInstructions,
154
+ description: mode.description,
155
+ },
156
+ ]),
157
+ ),
158
+ )
159
+
160
+ // Helper function to get all modes with their prompt overrides from extension state
161
+ export async function getAllModesWithPrompts(context: vscode.ExtensionContext): Promise<ModeConfig[]> {
162
+ const customModes = (await context.globalState.get<ModeConfig[]>("customModes")) || []
163
+ const customModePrompts = (await context.globalState.get<CustomModePrompts>("customModePrompts")) || {}
164
+
165
+ const allModes = getAllModes(customModes)
166
+ return allModes.map((mode) => ({
167
+ ...mode,
168
+ roleDefinition: customModePrompts[mode.slug]?.roleDefinition ?? mode.roleDefinition,
169
+ whenToUse: customModePrompts[mode.slug]?.whenToUse ?? mode.whenToUse,
170
+ customInstructions: customModePrompts[mode.slug]?.customInstructions ?? mode.customInstructions,
171
+ // description is not overridable via customModePrompts, so we keep the original
172
+ }))
173
+ }
174
+
175
+ // Helper function to get complete mode details with all overrides
176
+ export async function getFullModeDetails(
177
+ modeSlug: string,
178
+ customModes?: ModeConfig[],
179
+ customModePrompts?: CustomModePrompts,
180
+ options?: {
181
+ cwd?: string
182
+ globalCustomInstructions?: string
183
+ language?: string
184
+ },
185
+ ): Promise<ModeConfig> {
186
+ // First get the base mode config from custom modes or built-in modes
187
+ const baseMode = getModeBySlug(modeSlug, customModes) || modes.find((m) => m.slug === modeSlug) || modes[0]
188
+
189
+ // Check for any prompt component overrides
190
+ const promptComponent = customModePrompts?.[modeSlug]
191
+
192
+ // Get the base custom instructions
193
+ const baseCustomInstructions = promptComponent?.customInstructions || baseMode.customInstructions || ""
194
+ const baseWhenToUse = promptComponent?.whenToUse || baseMode.whenToUse || ""
195
+ const baseDescription = promptComponent?.description || baseMode.description || ""
196
+
197
+ // If we have cwd, load and combine all custom instructions
198
+ let fullCustomInstructions = baseCustomInstructions
199
+ if (options?.cwd) {
200
+ fullCustomInstructions = await addCustomInstructions(
201
+ baseCustomInstructions,
202
+ options.globalCustomInstructions || "",
203
+ options.cwd,
204
+ modeSlug,
205
+ { language: options.language },
206
+ )
207
+ }
208
+
209
+ // Return mode with any overrides applied
210
+ return {
211
+ ...baseMode,
212
+ roleDefinition: promptComponent?.roleDefinition || baseMode.roleDefinition,
213
+ whenToUse: baseWhenToUse,
214
+ description: baseDescription,
215
+ customInstructions: fullCustomInstructions,
216
+ }
217
+ }
218
+
219
+ // Helper function to safely get role definition
220
+ export function getRoleDefinition(modeSlug: string, customModes?: ModeConfig[]): string {
221
+ const mode = getModeBySlug(modeSlug, customModes)
222
+ if (!mode) {
223
+ console.warn(`No mode found for slug: ${modeSlug}`)
224
+ return ""
225
+ }
226
+ return mode.roleDefinition
227
+ }
228
+
229
+ // Helper function to safely get description
230
+ export function getDescription(modeSlug: string, customModes?: ModeConfig[]): string {
231
+ const mode = getModeBySlug(modeSlug, customModes)
232
+ if (!mode) {
233
+ console.warn(`No mode found for slug: ${modeSlug}`)
234
+ return ""
235
+ }
236
+ return mode.description ?? ""
237
+ }
238
+
239
+ // Helper function to safely get whenToUse
240
+ export function getWhenToUse(modeSlug: string, customModes?: ModeConfig[]): string {
241
+ const mode = getModeBySlug(modeSlug, customModes)
242
+ if (!mode) {
243
+ console.warn(`No mode found for slug: ${modeSlug}`)
244
+ return ""
245
+ }
246
+ return mode.whenToUse ?? ""
247
+ }
248
+
249
+ // Helper function to safely get custom instructions
250
+ export function getCustomInstructions(modeSlug: string, customModes?: ModeConfig[]): string {
251
+ const mode = getModeBySlug(modeSlug, customModes)
252
+ if (!mode) {
253
+ console.warn(`No mode found for slug: ${modeSlug}`)
254
+ return ""
255
+ }
256
+ return mode.customInstructions ?? ""
257
+ }
@@ -0,0 +1,385 @@
1
+ import { Anthropic } from "../../shim/anthropic"
2
+
3
+ import type { ClineAsk, ToolProgressStatus, ToolGroup, ToolName, GenerateImageParams } from "../../types"
4
+
5
+ export type ToolResponse = string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam>
6
+
7
+ export type AskApproval = (
8
+ type: ClineAsk,
9
+ partialMessage?: string,
10
+ progressStatus?: ToolProgressStatus,
11
+ forceApproval?: boolean,
12
+ ) => Promise<boolean>
13
+
14
+ export type HandleError = (action: string, error: Error) => Promise<void>
15
+
16
+ export type PushToolResult = (content: ToolResponse) => void
17
+
18
+ export type AskFinishSubTaskApproval = () => Promise<boolean>
19
+
20
+ export interface TextContent {
21
+ type: "text"
22
+ content: string
23
+ partial: boolean
24
+ }
25
+
26
+ export const toolParamNames = [
27
+ "command",
28
+ "path",
29
+ "content",
30
+ "regex",
31
+ "file_pattern",
32
+ "recursive",
33
+ "action",
34
+ "url",
35
+ "coordinate",
36
+ "text",
37
+ "server_name",
38
+ "tool_name",
39
+ "arguments",
40
+ "uri",
41
+ "question",
42
+ "result",
43
+ "diff",
44
+ "mode_slug",
45
+ "reason",
46
+ "line",
47
+ "mode",
48
+ "message",
49
+ "cwd",
50
+ "follow_up",
51
+ "task",
52
+ "size",
53
+ "query",
54
+ "args",
55
+ "skill", // skill tool parameter
56
+ "start_line",
57
+ "end_line",
58
+ "todos",
59
+ "prompt",
60
+ "image",
61
+ // read_file parameters (native protocol)
62
+ "operations", // search_and_replace parameter for multiple operations
63
+ "patch", // apply_patch parameter
64
+ "file_path", // search_replace and edit_file parameter
65
+ "old_string", // search_replace and edit_file parameter
66
+ "new_string", // search_replace and edit_file parameter
67
+ "replace_all", // edit tool parameter for replacing all occurrences
68
+ "expected_replacements", // edit_file parameter for multiple occurrences
69
+ "timeout", // execute_command parameter
70
+ "artifact_id", // read_command_output parameter
71
+ "search", // read_command_output parameter for grep-like search
72
+ "offset", // read_command_output and read_file parameter
73
+ "limit", // read_command_output and read_file parameter
74
+ // read_file indentation mode parameters
75
+ "indentation",
76
+ "anchor_line",
77
+ "max_levels",
78
+ "include_siblings",
79
+ "include_header",
80
+ "max_lines",
81
+ // read_file legacy format parameter (backward compatibility)
82
+ "files",
83
+ "line_ranges",
84
+ ] as const
85
+
86
+ export type ToolParamName = (typeof toolParamNames)[number]
87
+
88
+ /**
89
+ * Type map defining the native (typed) argument structure for each tool.
90
+ * Tools not listed here will fall back to `any` for backward compatibility.
91
+ */
92
+ export type NativeToolArgs = {
93
+ access_mcp_resource: { server_name: string; uri: string }
94
+ read_file: import("../../types").ReadFileToolParams
95
+ read_command_output: { artifact_id: string; search?: string; offset?: number; limit?: number }
96
+ attempt_completion: { result: string }
97
+ execute_command: { command: string; cwd?: string; timeout?: number | null }
98
+ apply_diff: { path: string; diff: string }
99
+ edit: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
100
+ search_and_replace: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
101
+ search_replace: { file_path: string; old_string: string; new_string: string }
102
+ edit_file: { file_path: string; old_string: string; new_string: string; expected_replacements?: number }
103
+ apply_patch: { patch: string }
104
+ list_files: { path: string; recursive?: boolean }
105
+ new_task: { mode: string; message: string; todos?: string }
106
+ ask_followup_question: {
107
+ question: string
108
+ follow_up: Array<{ text: string; mode?: string }>
109
+ }
110
+ codebase_search: { query: string; path?: string }
111
+ generate_image: GenerateImageParams
112
+ run_slash_command: { command: string; args?: string }
113
+ skill: { skill: string; args?: string }
114
+ search_files: { path: string; regex: string; file_pattern?: string | null }
115
+ switch_mode: { mode_slug: string; reason: string }
116
+ update_todo_list: { todos: string }
117
+ use_mcp_tool: { server_name: string; tool_name: string; arguments?: Record<string, unknown> }
118
+ write_to_file: { path: string; content: string }
119
+ // Add more tools as they are migrated to native protocol
120
+ }
121
+
122
+ /**
123
+ * Generic ToolUse interface that provides proper typing for both protocols.
124
+ *
125
+ * @template TName - The specific tool name, which determines the nativeArgs type
126
+ */
127
+ export interface ToolUse<TName extends ToolName = ToolName> {
128
+ type: "tool_use"
129
+ id?: string // Optional ID to track tool calls
130
+ name: TName
131
+ /**
132
+ * The original tool name as called by the model (e.g. an alias like "edit_file"),
133
+ * if it differs from the canonical tool name used for execution.
134
+ * Used to preserve tool names in API conversation history.
135
+ */
136
+ originalName?: string
137
+ // params is a partial record, allowing only some or none of the possible parameters to be used
138
+ params: Partial<Record<ToolParamName, string>>
139
+ partial: boolean
140
+ // nativeArgs is properly typed based on TName if it's in NativeToolArgs, otherwise never
141
+ nativeArgs?: TName extends keyof NativeToolArgs ? NativeToolArgs[TName] : never
142
+ /**
143
+ * Flag indicating whether the tool call used a legacy/deprecated format.
144
+ * Used for telemetry tracking to monitor migration from old formats.
145
+ */
146
+ usedLegacyFormat?: boolean
147
+ }
148
+
149
+ /**
150
+ * Represents a native MCP tool call from the model.
151
+ * In native mode, MCP tools are called directly with their prefixed name (e.g., "mcp_serverName_toolName")
152
+ * rather than through the use_mcp_tool wrapper. This type preserves the original tool name
153
+ * so it appears correctly in API conversation history.
154
+ */
155
+ export interface McpToolUse {
156
+ type: "mcp_tool_use"
157
+ id?: string // Tool call ID from the API
158
+ /** The original tool name from the API (e.g., "mcp_serverName_toolName") */
159
+ name: string
160
+ /** Extracted server name from the tool name */
161
+ serverName: string
162
+ /** Extracted tool name from the tool name */
163
+ toolName: string
164
+ /** Arguments passed to the MCP tool */
165
+ arguments: Record<string, unknown>
166
+ partial: boolean
167
+ }
168
+
169
+ export interface ExecuteCommandToolUse extends ToolUse<"execute_command"> {
170
+ name: "execute_command"
171
+ // Pick<Record<ToolParamName, string>, "command"> makes "command" required, but Partial<> makes it optional
172
+ params: Partial<Pick<Record<ToolParamName, string>, "command" | "cwd" | "timeout">>
173
+ }
174
+
175
+ export interface ReadFileToolUse extends ToolUse<"read_file"> {
176
+ name: "read_file"
177
+ params: Partial<
178
+ Pick<
179
+ Record<ToolParamName, string>,
180
+ | "args"
181
+ | "path"
182
+ | "start_line"
183
+ | "end_line"
184
+ | "mode"
185
+ | "offset"
186
+ | "limit"
187
+ | "indentation"
188
+ | "anchor_line"
189
+ | "max_levels"
190
+ | "include_siblings"
191
+ | "include_header"
192
+ >
193
+ >
194
+ }
195
+
196
+ export interface WriteToFileToolUse extends ToolUse<"write_to_file"> {
197
+ name: "write_to_file"
198
+ params: Partial<Pick<Record<ToolParamName, string>, "path" | "content">>
199
+ }
200
+
201
+ export interface CodebaseSearchToolUse extends ToolUse<"codebase_search"> {
202
+ name: "codebase_search"
203
+ params: Partial<Pick<Record<ToolParamName, string>, "query" | "path">>
204
+ }
205
+
206
+ export interface SearchFilesToolUse extends ToolUse<"search_files"> {
207
+ name: "search_files"
208
+ params: Partial<Pick<Record<ToolParamName, string>, "path" | "regex" | "file_pattern">>
209
+ }
210
+
211
+ export interface ListFilesToolUse extends ToolUse<"list_files"> {
212
+ name: "list_files"
213
+ params: Partial<Pick<Record<ToolParamName, string>, "path" | "recursive">>
214
+ }
215
+
216
+ export interface UseMcpToolToolUse extends ToolUse<"use_mcp_tool"> {
217
+ name: "use_mcp_tool"
218
+ params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "tool_name" | "arguments">>
219
+ }
220
+
221
+ export interface AccessMcpResourceToolUse extends ToolUse<"access_mcp_resource"> {
222
+ name: "access_mcp_resource"
223
+ params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "uri">>
224
+ }
225
+
226
+ export interface AskFollowupQuestionToolUse extends ToolUse<"ask_followup_question"> {
227
+ name: "ask_followup_question"
228
+ params: Partial<Pick<Record<ToolParamName, string>, "question" | "follow_up">>
229
+ }
230
+
231
+ export interface AttemptCompletionToolUse extends ToolUse<"attempt_completion"> {
232
+ name: "attempt_completion"
233
+ params: Partial<Pick<Record<ToolParamName, string>, "result">>
234
+ }
235
+
236
+ export interface SwitchModeToolUse extends ToolUse<"switch_mode"> {
237
+ name: "switch_mode"
238
+ params: Partial<Pick<Record<ToolParamName, string>, "mode_slug" | "reason">>
239
+ }
240
+
241
+ export interface NewTaskToolUse extends ToolUse<"new_task"> {
242
+ name: "new_task"
243
+ params: Partial<Pick<Record<ToolParamName, string>, "mode" | "message" | "todos">>
244
+ }
245
+
246
+ export interface RunSlashCommandToolUse extends ToolUse<"run_slash_command"> {
247
+ name: "run_slash_command"
248
+ params: Partial<Pick<Record<ToolParamName, string>, "command" | "args">>
249
+ }
250
+
251
+ export interface SkillToolUse extends ToolUse<"skill"> {
252
+ name: "skill"
253
+ params: Partial<Pick<Record<ToolParamName, string>, "skill" | "args">>
254
+ }
255
+
256
+ export interface GenerateImageToolUse extends ToolUse<"generate_image"> {
257
+ name: "generate_image"
258
+ params: Partial<Pick<Record<ToolParamName, string>, "prompt" | "path" | "image">>
259
+ }
260
+
261
+ // Define tool group configuration
262
+ export type ToolGroupConfig = {
263
+ tools: readonly string[]
264
+ alwaysAvailable?: boolean // Whether this group is always available and shouldn't show in prompts view
265
+ customTools?: readonly string[] // Opt-in only tools - only available when explicitly included via model's includedTools
266
+ }
267
+
268
+ export const TOOL_DISPLAY_NAMES: Record<ToolName, string> = {
269
+ execute_command: "run commands",
270
+ read_file: "read files",
271
+ read_command_output: "read command output",
272
+ write_to_file: "write files",
273
+ apply_diff: "apply changes",
274
+ edit: "edit files",
275
+ search_and_replace: "apply changes using search and replace",
276
+ search_replace: "apply single search and replace",
277
+ edit_file: "edit files using search and replace",
278
+ apply_patch: "apply patches using codex format",
279
+ search_files: "search files",
280
+ list_files: "list files",
281
+ use_mcp_tool: "use mcp tools",
282
+ access_mcp_resource: "access mcp resources",
283
+ ask_followup_question: "ask questions",
284
+ attempt_completion: "complete tasks",
285
+ switch_mode: "switch modes",
286
+ new_task: "create new task",
287
+ codebase_search: "codebase search",
288
+ update_todo_list: "update todo list",
289
+ run_slash_command: "run slash command",
290
+ skill: "load skill",
291
+ generate_image: "generate images",
292
+ custom_tool: "use custom tools",
293
+ } as const
294
+
295
+ // Define available tool groups.
296
+ export const TOOL_GROUPS: Record<ToolGroup, ToolGroupConfig> = {
297
+ read: {
298
+ tools: ["read_file", "search_files", "list_files", "codebase_search"],
299
+ },
300
+ edit: {
301
+ tools: ["apply_diff", "write_to_file", "generate_image"],
302
+ customTools: ["edit", "search_replace", "edit_file", "apply_patch"],
303
+ },
304
+ command: {
305
+ tools: ["execute_command", "read_command_output"],
306
+ },
307
+ mcp: {
308
+ tools: ["use_mcp_tool", "access_mcp_resource"],
309
+ },
310
+ modes: {
311
+ tools: ["switch_mode", "new_task"],
312
+ alwaysAvailable: true,
313
+ },
314
+ }
315
+
316
+ // Tools that are always available to all modes.
317
+ export const ALWAYS_AVAILABLE_TOOLS: ToolName[] = [
318
+ "ask_followup_question",
319
+ "attempt_completion",
320
+ "switch_mode",
321
+ "new_task",
322
+ "update_todo_list",
323
+ "run_slash_command",
324
+ "skill",
325
+ ] as const
326
+
327
+ /**
328
+ * Central registry of tool aliases.
329
+ * Maps alias name -> canonical tool name.
330
+ *
331
+ * This allows models to use alternative names for tools (e.g., "edit_file" instead of "apply_diff").
332
+ * When a model calls a tool by its alias, the system resolves it to the canonical name for execution,
333
+ * but preserves the alias in API conversation history for consistency.
334
+ *
335
+ * To add a new alias, simply add an entry here. No other files need to be modified.
336
+ */
337
+ export const TOOL_ALIASES: Record<string, ToolName> = {
338
+ write_file: "write_to_file",
339
+ search_and_replace: "edit",
340
+ } as const
341
+
342
+ export type DiffResult =
343
+ | { success: true; content: string; failParts?: DiffResult[] }
344
+ | ({
345
+ success: false
346
+ error?: string
347
+ details?: {
348
+ similarity?: number
349
+ threshold?: number
350
+ matchedRange?: { start: number; end: number }
351
+ searchContent?: string
352
+ bestMatch?: string
353
+ }
354
+ failParts?: DiffResult[]
355
+ } & ({ error: string } | { failParts: DiffResult[] }))
356
+
357
+ export interface DiffItem {
358
+ content: string
359
+ startLine?: number
360
+ }
361
+
362
+ export interface DiffStrategy {
363
+ /**
364
+ * Get the name of this diff strategy for analytics and debugging
365
+ * @returns The name of the diff strategy
366
+ */
367
+ getName(): string
368
+
369
+ /**
370
+ * Apply a diff to the original content
371
+ * @param originalContent The original file content
372
+ * @param diffContent The diff content in the strategy's format (string for legacy, DiffItem[] for new)
373
+ * @param startLine Optional line number where the search block starts. If not provided, searches the entire file.
374
+ * @param endLine Optional line number where the search block ends. If not provided, searches the entire file.
375
+ * @returns A DiffResult object containing either the successful result or error details
376
+ */
377
+ applyDiff(
378
+ originalContent: string,
379
+ diffContent: string | DiffItem[],
380
+ startLine?: number,
381
+ endLine?: number,
382
+ ): Promise<DiffResult>
383
+
384
+ getProgressStatus?(toolUse: ToolUse, result?: any): ToolProgressStatus
385
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * SHIM — minimal replacement for zoo-code/src/utils/fs.ts.
3
+ *
4
+ * The original exports a large set of fs helpers (mostly for the GUI layer).
5
+ * The vendored core only needs `fileExistsAtPath`, whose real implementation
6
+ * (`zoo-code/src/utils/fs.ts`) is existence-only, regardless of file vs
7
+ * directory:
8
+ *
9
+ * export async function fileExistsAtPath(filePath: string): Promise<boolean> {
10
+ * try {
11
+ * await fs.access(filePath)
12
+ * return true
13
+ * } catch {
14
+ * return false
15
+ * }
16
+ * }
17
+ *
18
+ * This must match that exactly. An earlier version of this shim narrowed it
19
+ * to `stats.isFile()`, which broke every caller that checks a DIRECTORY's
20
+ * existence — `CustomModesManager`'s `.roo/rules-<slug>/` folder check, and
21
+ * (found while vendoring checkpoints) `ShadowCheckpointService#initShadowGit`'s
22
+ * check for whether the shadow `.git` dir already exists. With the `isFile`
23
+ * version, both always returned false for existing directories, so
24
+ * `initShadowGit` always took the "create new repo" branch — silently
25
+ * re-initializing (and appending a redundant empty commit to) an
26
+ * already-initialized shadow repo on every session, corrupting the checkpoint
27
+ * history's meaning of "baseline".
28
+ */
29
+
30
+ import * as fs from "fs/promises"
31
+
32
+ export async function fileExistsAtPath(filePath: string): Promise<boolean> {
33
+ try {
34
+ await fs.access(filePath)
35
+ return true
36
+ } catch {
37
+ return false
38
+ }
39
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SHIM — replaces zoo-code/src/utils/globalContext.ts.
3
+ *
4
+ * The original resolves the extension's global storage directory from the VS
5
+ * Code ExtensionContext. Headless, we use `~/.roo` (the same directory Roo Code
6
+ * uses for global custom modes), creating it if needed.
7
+ */
8
+
9
+ import * as path from "path"
10
+ import * as os from "os"
11
+ import * as fs from "fs/promises"
12
+ import type { ExtensionContext } from "../../shim/vscode"
13
+
14
+ export async function ensureSettingsDirectoryExists(_context?: ExtensionContext): Promise<string> {
15
+ const dir = path.join(os.homedir(), ".roo")
16
+ try {
17
+ await fs.mkdir(dir, { recursive: true })
18
+ } catch {
19
+ // Ignore: read-only home dirs fall back to the path anyway.
20
+ }
21
+ return dir
22
+ }