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,16 @@
1
+ /**
2
+ * SHIM — replaces zoo-code/src/utils/json-schema.ts.
3
+ *
4
+ * The original contains a 300-line zod-driven JSON Schema normalizer (and
5
+ * imports `zod/v4` types). The vendored `native-tools/mcp_server.ts` only uses
6
+ * `normalizeToolSchema` and `JsonSchema` to prepare MCP tool schemas. MCP
7
+ * servers are not wired in Phase 1, so this shim provides an identity
8
+ * normalization with a structural type. Needs adaptation when real MCP support
9
+ * lands.
10
+ */
11
+
12
+ export type JsonSchema = Record<string, unknown>
13
+
14
+ export function normalizeToolSchema(schema: Record<string, unknown>): Record<string, unknown> {
15
+ return schema
16
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * SHIM — console-backed logger replacing zoo-code/src/utils/logging.ts.
3
+ *
4
+ * The original wraps VS Code output channels; the headless harness logs to
5
+ * stdout/stderr instead.
6
+ */
7
+
8
+ export const logger = {
9
+ info: (message: string, meta?: unknown): void => {
10
+ console.log(`[headlesscode] ${message}`, meta ?? "")
11
+ },
12
+ warn: (message: string, meta?: unknown): void => {
13
+ console.warn(`[headlesscode] ${message}`, meta ?? "")
14
+ },
15
+ error: (message: string, meta?: unknown): void => {
16
+ console.error(`[headlesscode] ${message}`, meta ?? "")
17
+ },
18
+ debug: (message: string, meta?: unknown): void => {
19
+ console.debug(`[headlesscode] ${message}`, meta ?? "")
20
+ },
21
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Utilities for sanitizing MCP server and tool names to conform to
3
+ * API function name requirements across all providers.
4
+ */
5
+
6
+ /**
7
+ * Separator used between MCP prefix, server name, and tool name.
8
+ * We use "--" (double hyphen) because:
9
+ * 1. It's allowed by all providers (dashes are permitted in function names)
10
+ * 2. It won't conflict with underscores in sanitized server/tool names
11
+ * 3. It's unique enough to be a reliable delimiter for parsing
12
+ */
13
+ export const MCP_TOOL_SEPARATOR = "--"
14
+
15
+ /**
16
+ * Prefix for all MCP tool function names.
17
+ */
18
+ export const MCP_TOOL_PREFIX = "mcp"
19
+
20
+ /**
21
+ * Normalize a string for comparison by treating hyphens and underscores as equivalent.
22
+ * This is used to match tool names when models convert hyphens to underscores.
23
+ *
24
+ * @param name - The name to normalize
25
+ * @returns The normalized name with all hyphens converted to underscores
26
+ */
27
+ export function normalizeForComparison(name: string): string {
28
+ return name.replace(/-/g, "_")
29
+ }
30
+
31
+ /**
32
+ * Normalize an MCP tool name by converting underscore separators back to hyphens.
33
+ * This handles the case where models (especially Claude) convert hyphens to underscores
34
+ * in tool names when using native tool calling.
35
+ *
36
+ * For example: "mcp__server__tool" -> "mcp--server--tool"
37
+ *
38
+ * This function uses fuzzy matching - it treats hyphens and underscores as equivalent
39
+ * when normalizing the separator pattern.
40
+ *
41
+ * @param toolName - The tool name that may have underscore separators
42
+ * @returns The normalized tool name with hyphen separators
43
+ */
44
+ export function normalizeMcpToolName(toolName: string): string {
45
+ // Normalize for comparison to detect MCP tools regardless of separator style
46
+ const normalized = normalizeForComparison(toolName)
47
+
48
+ // Only normalize if it looks like an MCP tool (starts with mcp__)
49
+ if (normalized.startsWith("mcp__")) {
50
+ // Find the pattern: mcp{sep}server{sep}tool where sep is -- or __
51
+ // We need to convert the separators while preserving the rest
52
+
53
+ // First, try to parse assuming all separators are underscores
54
+ // Pattern: mcp__server__tool or mcp__server__tool_with_underscores
55
+ const parts = toolName.split(/__|--/)
56
+
57
+ if (parts.length >= 3 && parts[0].toLowerCase() === "mcp") {
58
+ // Reconstruct with proper -- separators
59
+ const serverName = parts[1]
60
+ const toolNamePart = parts.slice(2).join("--") // Rejoin in case tool name had separator
61
+ return `${MCP_TOOL_PREFIX}${MCP_TOOL_SEPARATOR}${serverName}${MCP_TOOL_SEPARATOR}${toolNamePart}`
62
+ }
63
+ }
64
+ return toolName
65
+ }
66
+
67
+ /**
68
+ * Check if a tool name is an MCP tool (starts with the MCP prefix and separator).
69
+ * Uses fuzzy matching to handle both hyphen and underscore separators.
70
+ *
71
+ * @param toolName - The tool name to check
72
+ * @returns true if the tool name starts with "mcp--" or "mcp__", false otherwise
73
+ */
74
+ export function isMcpTool(toolName: string): boolean {
75
+ const normalized = normalizeForComparison(toolName)
76
+ return normalized.startsWith(`${MCP_TOOL_PREFIX}__`)
77
+ }
78
+
79
+ /**
80
+ * Sanitize a name to be safe for use in API function names.
81
+ * This removes special characters and ensures the name starts correctly.
82
+ *
83
+ * Note: Hyphens are preserved since they are valid in function names.
84
+ * Models may convert hyphens to underscores, but we handle this with
85
+ * fuzzy matching when parsing tool names.
86
+ *
87
+ * @param name - The original name (e.g., MCP server name or tool name)
88
+ * @returns A sanitized name that conforms to API requirements
89
+ */
90
+ export function sanitizeMcpName(name: string): string {
91
+ if (!name) {
92
+ return "_"
93
+ }
94
+
95
+ // Replace spaces with underscores first
96
+ let sanitized = name.replace(/\s+/g, "_")
97
+
98
+ // Only allow alphanumeric, underscores, and hyphens
99
+ sanitized = sanitized.replace(/[^a-zA-Z0-9_\-]/g, "")
100
+
101
+ // Replace any double-hyphen sequences with single hyphen to avoid separator conflicts
102
+ sanitized = sanitized.replace(/--+/g, "-")
103
+
104
+ // Ensure the name starts with a letter or underscore
105
+ if (sanitized.length > 0 && !/^[a-zA-Z_]/.test(sanitized)) {
106
+ sanitized = "_" + sanitized
107
+ }
108
+
109
+ // If empty after sanitization, use a placeholder
110
+ if (!sanitized) {
111
+ sanitized = "_unnamed"
112
+ }
113
+
114
+ return sanitized
115
+ }
116
+
117
+ /**
118
+ * Build a full MCP tool function name from server and tool names.
119
+ * The format is: mcp--{sanitized_server_name}--{sanitized_tool_name}
120
+ *
121
+ * The total length is capped at 64 characters to conform to API limits.
122
+ *
123
+ * @param serverName - The MCP server name
124
+ * @param toolName - The tool name
125
+ * @returns A sanitized function name in the format mcp--serverName--toolName
126
+ */
127
+ export function buildMcpToolName(serverName: string, toolName: string): string {
128
+ const sanitizedServer = sanitizeMcpName(serverName)
129
+ const sanitizedTool = sanitizeMcpName(toolName)
130
+
131
+ // Build the full name: mcp--{server}--{tool}
132
+ const fullName = `${MCP_TOOL_PREFIX}${MCP_TOOL_SEPARATOR}${sanitizedServer}${MCP_TOOL_SEPARATOR}${sanitizedTool}`
133
+
134
+ // Truncate if necessary (max 64 chars for Gemini)
135
+ if (fullName.length > 64) {
136
+ return fullName.slice(0, 64)
137
+ }
138
+
139
+ return fullName
140
+ }
141
+
142
+ /**
143
+ * Parse an MCP tool function name back into server and tool names.
144
+ * This handles both hyphen and underscore separators using fuzzy matching.
145
+ *
146
+ * @param mcpToolName - The full MCP tool name (e.g., "mcp--weather--get_forecast" or "mcp__weather__get_forecast")
147
+ * @returns An object with serverName and toolName, or null if parsing fails
148
+ */
149
+ export function parseMcpToolName(mcpToolName: string): { serverName: string; toolName: string } | null {
150
+ // Normalize the name to handle both separator styles
151
+ const normalizedName = normalizeMcpToolName(mcpToolName)
152
+
153
+ const prefix = MCP_TOOL_PREFIX + MCP_TOOL_SEPARATOR
154
+ if (!normalizedName.startsWith(prefix)) {
155
+ return null
156
+ }
157
+
158
+ // Remove the "mcp--" prefix
159
+ const remainder = normalizedName.slice(prefix.length)
160
+
161
+ // Split on the separator to get server and tool names
162
+ const separatorIndex = remainder.indexOf(MCP_TOOL_SEPARATOR)
163
+ if (separatorIndex === -1) {
164
+ return null
165
+ }
166
+
167
+ const serverName = remainder.slice(0, separatorIndex)
168
+ const toolName = remainder.slice(separatorIndex + MCP_TOOL_SEPARATOR.length)
169
+
170
+ if (!serverName || !toolName) {
171
+ return null
172
+ }
173
+
174
+ return {
175
+ serverName,
176
+ toolName,
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Check if two tool names match using fuzzy comparison.
182
+ * Treats hyphens and underscores as equivalent.
183
+ *
184
+ * @param name1 - First tool name
185
+ * @param name2 - Second tool name
186
+ * @returns true if the names match (treating - and _ as equivalent)
187
+ */
188
+ export function toolNamesMatch(name1: string, name2: string): boolean {
189
+ return normalizeForComparison(name1) === normalizeForComparison(name2)
190
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Check if an object is empty (has no own enumerable properties)
3
+ * @param obj The object to check
4
+ * @returns true if the object is empty, false otherwise
5
+ */
6
+ export function isEmpty(obj: unknown): boolean {
7
+ if (!obj || typeof obj !== "object") {
8
+ return true
9
+ }
10
+
11
+ // Check if it's an array
12
+ if (Array.isArray(obj)) {
13
+ return obj.length === 0
14
+ }
15
+
16
+ // Check if it's an object with no own properties
17
+ return Object.keys(obj).length === 0
18
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SHIM — replaces zoo-code/src/utils/path.ts.
3
+ *
4
+ * The original file resolves the workspace root from `vscode.workspace`. The
5
+ * headless harness has no VS Code, so the workspace root comes from the
6
+ * `HEADLESSCODE_WORKSPACE_ROOT` environment variable (falling back to
7
+ * `process.cwd()`).
8
+ *
9
+ * This module also installs `String.prototype.toPosix()` exactly like the
10
+ * original (declaration merging + prototype assignment), which the vendored
11
+ * prompt sections (rules.ts, system-info.ts) rely on. Import it once for its
12
+ * side effect, e.g. from the harness entry point or the smoke test.
13
+ */
14
+
15
+ import * as path from "path"
16
+
17
+ function toPosixPath(p: string): string {
18
+ // Extended-Length Paths in Windows start with "\\?\" and must be left alone.
19
+ const isExtendedLengthPath = p.startsWith("\\\\?\\")
20
+ if (isExtendedLengthPath) {
21
+ return p
22
+ }
23
+ return p.replace(/\\/g, "/")
24
+ }
25
+
26
+ declare global {
27
+ interface String {
28
+ toPosix(): string
29
+ }
30
+ }
31
+
32
+ String.prototype.toPosix = function (this: string): string {
33
+ return toPosixPath(this)
34
+ }
35
+
36
+ function normalizePath(p: string): string {
37
+ let normalized = path.normalize(p)
38
+ if (normalized.length > 1 && (normalized.endsWith("/") || normalized.endsWith("\\"))) {
39
+ normalized = normalized.slice(0, -1)
40
+ }
41
+ return normalized
42
+ }
43
+
44
+ /** Safe path comparison that works across different platforms. */
45
+ export function arePathsEqual(path1?: string, path2?: string): boolean {
46
+ if (!path1 && !path2) {
47
+ return true
48
+ }
49
+ if (!path1 || !path2) {
50
+ return false
51
+ }
52
+ const normalized1 = normalizePath(path1)
53
+ const normalized2 = normalizePath(path2)
54
+ if (process.platform === "win32") {
55
+ return normalized1.toLowerCase() === normalized2.toLowerCase()
56
+ }
57
+ return normalized1 === normalized2
58
+ }
59
+
60
+ export function getReadablePath(cwd: string, relPath?: string): string {
61
+ if (relPath === undefined) {
62
+ return ""
63
+ }
64
+ const absolutePath = path.resolve(cwd, relPath)
65
+ if (arePathsEqual(path.normalize(absolutePath), path.normalize(cwd))) {
66
+ return path.basename(absolutePath).toPosix()
67
+ }
68
+ const normalizedRelPath = path.relative(cwd, absolutePath)
69
+ if (absolutePath.includes(cwd)) {
70
+ return normalizedRelPath.toPosix()
71
+ }
72
+ return absolutePath.toPosix()
73
+ }
74
+
75
+ export const toRelativePath = (filePath: string, cwd: string): string => {
76
+ const relativePath = path.relative(cwd, filePath).toPosix()
77
+ return filePath.endsWith("/") ? relativePath + "/" : relativePath
78
+ }
79
+
80
+ /**
81
+ * Headless workspace root. The original reads `vscode.workspace.workspaceFolders`;
82
+ * here we prefer the HEADLESSCODE_WORKSPACE_ROOT env var, then process.cwd().
83
+ */
84
+ export const getWorkspacePath = (defaultCwdPath = ""): string => {
85
+ const override = process.env.HEADLESSCODE_WORKSPACE_ROOT
86
+ if (override) {
87
+ return override
88
+ }
89
+ return process.cwd() || defaultCwdPath
90
+ }
91
+
92
+ export const getWorkspacePathForContext = (_contextPath?: string): string => {
93
+ return getWorkspacePath()
94
+ }