patchwork-os 0.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (721) hide show
  1. package/LICENSE +21 -0
  2. package/README.bridge.md +352 -0
  3. package/README.md +72 -0
  4. package/deploy/README.md +172 -0
  5. package/deploy/bootstrap-new-vps.sh +364 -0
  6. package/deploy/claude-ide-bridge.service.template +67 -0
  7. package/deploy/claude-ide-bridge@.service +31 -0
  8. package/deploy/ecosystem.config.js.example +36 -0
  9. package/deploy/install-vps-service.sh +240 -0
  10. package/deploy/nginx-claude-bridge.conf.template +129 -0
  11. package/dist/activityLog.d.ts +112 -0
  12. package/dist/activityLog.js +399 -0
  13. package/dist/activityLog.js.map +1 -0
  14. package/dist/activityTypes.d.ts +28 -0
  15. package/dist/activityTypes.js +9 -0
  16. package/dist/activityTypes.js.map +1 -0
  17. package/dist/adapters/base.d.ts +78 -0
  18. package/dist/adapters/base.js +14 -0
  19. package/dist/adapters/base.js.map +1 -0
  20. package/dist/adapters/claude.d.ts +18 -0
  21. package/dist/adapters/claude.js +276 -0
  22. package/dist/adapters/claude.js.map +1 -0
  23. package/dist/adapters/gemini.d.ts +17 -0
  24. package/dist/adapters/gemini.js +218 -0
  25. package/dist/adapters/gemini.js.map +1 -0
  26. package/dist/adapters/grok.d.ts +7 -0
  27. package/dist/adapters/grok.js +21 -0
  28. package/dist/adapters/grok.js.map +1 -0
  29. package/dist/adapters/index.d.ts +5 -0
  30. package/dist/adapters/index.js +37 -0
  31. package/dist/adapters/index.js.map +1 -0
  32. package/dist/adapters/local.d.ts +7 -0
  33. package/dist/adapters/local.js +22 -0
  34. package/dist/adapters/local.js.map +1 -0
  35. package/dist/adapters/openai.d.ts +22 -0
  36. package/dist/adapters/openai.js +284 -0
  37. package/dist/adapters/openai.js.map +1 -0
  38. package/dist/adapters/sse.d.ts +13 -0
  39. package/dist/adapters/sse.js +58 -0
  40. package/dist/adapters/sse.js.map +1 -0
  41. package/dist/analyticsAggregator.d.ts +28 -0
  42. package/dist/analyticsAggregator.js +133 -0
  43. package/dist/analyticsAggregator.js.map +1 -0
  44. package/dist/analyticsPrefs.d.ts +9 -0
  45. package/dist/analyticsPrefs.js +50 -0
  46. package/dist/analyticsPrefs.js.map +1 -0
  47. package/dist/analyticsSend.d.ts +12 -0
  48. package/dist/analyticsSend.js +34 -0
  49. package/dist/analyticsSend.js.map +1 -0
  50. package/dist/approvalHttp.d.ts +46 -0
  51. package/dist/approvalHttp.js +370 -0
  52. package/dist/approvalHttp.js.map +1 -0
  53. package/dist/approvalQueue.d.ts +49 -0
  54. package/dist/approvalQueue.js +84 -0
  55. package/dist/approvalQueue.js.map +1 -0
  56. package/dist/automation.d.ts +675 -0
  57. package/dist/automation.js +1038 -0
  58. package/dist/automation.js.map +1 -0
  59. package/dist/bridge.d.ts +85 -0
  60. package/dist/bridge.js +1535 -0
  61. package/dist/bridge.js.map +1 -0
  62. package/dist/bridgeLockDiscovery.d.ts +11 -0
  63. package/dist/bridgeLockDiscovery.js +49 -0
  64. package/dist/bridgeLockDiscovery.js.map +1 -0
  65. package/dist/bridgeToken.d.ts +22 -0
  66. package/dist/bridgeToken.js +114 -0
  67. package/dist/bridgeToken.js.map +1 -0
  68. package/dist/bridgeToolsRules.d.ts +20 -0
  69. package/dist/bridgeToolsRules.js +79 -0
  70. package/dist/bridgeToolsRules.js.map +1 -0
  71. package/dist/ccPermissions.d.ts +59 -0
  72. package/dist/ccPermissions.js +163 -0
  73. package/dist/ccPermissions.js.map +1 -0
  74. package/dist/claudeDriver.d.ts +129 -0
  75. package/dist/claudeDriver.js +459 -0
  76. package/dist/claudeDriver.js.map +1 -0
  77. package/dist/claudeMdPatch.d.ts +29 -0
  78. package/dist/claudeMdPatch.js +164 -0
  79. package/dist/claudeMdPatch.js.map +1 -0
  80. package/dist/claudeOrchestrator.d.ts +171 -0
  81. package/dist/claudeOrchestrator.js +591 -0
  82. package/dist/claudeOrchestrator.js.map +1 -0
  83. package/dist/commands/install.d.ts +1 -0
  84. package/dist/commands/install.js +158 -0
  85. package/dist/commands/install.js.map +1 -0
  86. package/dist/commands/marketplace.d.ts +11 -0
  87. package/dist/commands/marketplace.js +120 -0
  88. package/dist/commands/marketplace.js.map +1 -0
  89. package/dist/commands/patchworkInit.d.ts +14 -0
  90. package/dist/commands/patchworkInit.js +155 -0
  91. package/dist/commands/patchworkInit.js.map +1 -0
  92. package/dist/commands/task.d.ts +14 -0
  93. package/dist/commands/task.js +289 -0
  94. package/dist/commands/task.js.map +1 -0
  95. package/dist/commands/tokenEfficiency.d.ts +9 -0
  96. package/dist/commands/tokenEfficiency.js +211 -0
  97. package/dist/commands/tokenEfficiency.js.map +1 -0
  98. package/dist/commands/tools.d.ts +28 -0
  99. package/dist/commands/tools.js +326 -0
  100. package/dist/commands/tools.js.map +1 -0
  101. package/dist/commitIssueLinkLog.d.ts +77 -0
  102. package/dist/commitIssueLinkLog.js +142 -0
  103. package/dist/commitIssueLinkLog.js.map +1 -0
  104. package/dist/companions/registry.d.ts +12 -0
  105. package/dist/companions/registry.js +71 -0
  106. package/dist/companions/registry.js.map +1 -0
  107. package/dist/config.d.ts +105 -0
  108. package/dist/config.js +720 -0
  109. package/dist/config.js.map +1 -0
  110. package/dist/crypto.d.ts +16 -0
  111. package/dist/crypto.js +34 -0
  112. package/dist/crypto.js.map +1 -0
  113. package/dist/dashboard.d.ts +12 -0
  114. package/dist/dashboard.js +149 -0
  115. package/dist/dashboard.js.map +1 -0
  116. package/dist/decisionTraceLog.d.ts +77 -0
  117. package/dist/decisionTraceLog.js +147 -0
  118. package/dist/decisionTraceLog.js.map +1 -0
  119. package/dist/errors.d.ts +32 -0
  120. package/dist/errors.js +34 -0
  121. package/dist/errors.js.map +1 -0
  122. package/dist/extensionClient.d.ts +279 -0
  123. package/dist/extensionClient.js +1253 -0
  124. package/dist/extensionClient.js.map +1 -0
  125. package/dist/fileLock.d.ts +36 -0
  126. package/dist/fileLock.js +121 -0
  127. package/dist/fileLock.js.map +1 -0
  128. package/dist/fp/activityAnalytics.d.ts +39 -0
  129. package/dist/fp/activityAnalytics.js +111 -0
  130. package/dist/fp/activityAnalytics.js.map +1 -0
  131. package/dist/fp/async.d.ts +48 -0
  132. package/dist/fp/async.js +60 -0
  133. package/dist/fp/async.js.map +1 -0
  134. package/dist/fp/automationInterpreter.d.ts +37 -0
  135. package/dist/fp/automationInterpreter.js +523 -0
  136. package/dist/fp/automationInterpreter.js.map +1 -0
  137. package/dist/fp/automationProgram.d.ts +89 -0
  138. package/dist/fp/automationProgram.js +29 -0
  139. package/dist/fp/automationProgram.js.map +1 -0
  140. package/dist/fp/automationState.d.ts +135 -0
  141. package/dist/fp/automationState.js +206 -0
  142. package/dist/fp/automationState.js.map +1 -0
  143. package/dist/fp/automationUtils.d.ts +31 -0
  144. package/dist/fp/automationUtils.js +61 -0
  145. package/dist/fp/automationUtils.js.map +1 -0
  146. package/dist/fp/brandedTypes.d.ts +32 -0
  147. package/dist/fp/brandedTypes.js +41 -0
  148. package/dist/fp/brandedTypes.js.map +1 -0
  149. package/dist/fp/commandDescription.d.ts +18 -0
  150. package/dist/fp/commandDescription.js +125 -0
  151. package/dist/fp/commandDescription.js.map +1 -0
  152. package/dist/fp/extensionSnapshot.d.ts +10 -0
  153. package/dist/fp/extensionSnapshot.js +14 -0
  154. package/dist/fp/extensionSnapshot.js.map +1 -0
  155. package/dist/fp/index.d.ts +8 -0
  156. package/dist/fp/index.js +9 -0
  157. package/dist/fp/index.js.map +1 -0
  158. package/dist/fp/interpreterContext.d.ts +69 -0
  159. package/dist/fp/interpreterContext.js +56 -0
  160. package/dist/fp/interpreterContext.js.map +1 -0
  161. package/dist/fp/policyParser.d.ts +16 -0
  162. package/dist/fp/policyParser.js +334 -0
  163. package/dist/fp/policyParser.js.map +1 -0
  164. package/dist/fp/result.d.ts +38 -0
  165. package/dist/fp/result.js +57 -0
  166. package/dist/fp/result.js.map +1 -0
  167. package/dist/fp/tokenBucket.d.ts +27 -0
  168. package/dist/fp/tokenBucket.js +36 -0
  169. package/dist/fp/tokenBucket.js.map +1 -0
  170. package/dist/index.d.ts +2 -0
  171. package/dist/index.js +1465 -0
  172. package/dist/index.js.map +1 -0
  173. package/dist/instructionsUtils.d.ts +17 -0
  174. package/dist/instructionsUtils.js +38 -0
  175. package/dist/instructionsUtils.js.map +1 -0
  176. package/dist/lockfile.d.ts +16 -0
  177. package/dist/lockfile.js +172 -0
  178. package/dist/lockfile.js.map +1 -0
  179. package/dist/logger.d.ts +16 -0
  180. package/dist/logger.js +68 -0
  181. package/dist/logger.js.map +1 -0
  182. package/dist/oauth.d.ts +105 -0
  183. package/dist/oauth.js +880 -0
  184. package/dist/oauth.js.map +1 -0
  185. package/dist/orchestrator/childBridgeClient.d.ts +33 -0
  186. package/dist/orchestrator/childBridgeClient.js +321 -0
  187. package/dist/orchestrator/childBridgeClient.js.map +1 -0
  188. package/dist/orchestrator/childBridgeRegistry.d.ts +67 -0
  189. package/dist/orchestrator/childBridgeRegistry.js +297 -0
  190. package/dist/orchestrator/childBridgeRegistry.js.map +1 -0
  191. package/dist/orchestrator/index.d.ts +3 -0
  192. package/dist/orchestrator/index.js +3 -0
  193. package/dist/orchestrator/index.js.map +1 -0
  194. package/dist/orchestrator/orchestratorBridge.d.ts +32 -0
  195. package/dist/orchestrator/orchestratorBridge.js +412 -0
  196. package/dist/orchestrator/orchestratorBridge.js.map +1 -0
  197. package/dist/orchestrator/orchestratorConfig.d.ts +11 -0
  198. package/dist/orchestrator/orchestratorConfig.js +85 -0
  199. package/dist/orchestrator/orchestratorConfig.js.map +1 -0
  200. package/dist/orchestrator/orchestratorTools.d.ts +16 -0
  201. package/dist/orchestrator/orchestratorTools.js +272 -0
  202. package/dist/orchestrator/orchestratorTools.js.map +1 -0
  203. package/dist/patchworkCli.d.ts +15 -0
  204. package/dist/patchworkCli.js +41 -0
  205. package/dist/patchworkCli.js.map +1 -0
  206. package/dist/patchworkConfig.d.ts +28 -0
  207. package/dist/patchworkConfig.js +30 -0
  208. package/dist/patchworkConfig.js.map +1 -0
  209. package/dist/plugin.d.ts +106 -0
  210. package/dist/plugin.js +31 -0
  211. package/dist/plugin.js.map +1 -0
  212. package/dist/pluginLoader.d.ts +44 -0
  213. package/dist/pluginLoader.js +357 -0
  214. package/dist/pluginLoader.js.map +1 -0
  215. package/dist/pluginWatcher.d.ts +24 -0
  216. package/dist/pluginWatcher.js +139 -0
  217. package/dist/pluginWatcher.js.map +1 -0
  218. package/dist/preToolUseHook.d.ts +10 -0
  219. package/dist/preToolUseHook.js +57 -0
  220. package/dist/preToolUseHook.js.map +1 -0
  221. package/dist/probe.d.ts +35 -0
  222. package/dist/probe.js +143 -0
  223. package/dist/probe.js.map +1 -0
  224. package/dist/prompts.d.ts +27 -0
  225. package/dist/prompts.js +1680 -0
  226. package/dist/prompts.js.map +1 -0
  227. package/dist/quickTaskPresets.d.ts +64 -0
  228. package/dist/quickTaskPresets.js +156 -0
  229. package/dist/quickTaskPresets.js.map +1 -0
  230. package/dist/recipes/compiler.d.ts +44 -0
  231. package/dist/recipes/compiler.js +140 -0
  232. package/dist/recipes/compiler.js.map +1 -0
  233. package/dist/recipes/installer.d.ts +25 -0
  234. package/dist/recipes/installer.js +62 -0
  235. package/dist/recipes/installer.js.map +1 -0
  236. package/dist/recipes/parser.d.ts +18 -0
  237. package/dist/recipes/parser.js +160 -0
  238. package/dist/recipes/parser.js.map +1 -0
  239. package/dist/recipes/scheduler.d.ts +45 -0
  240. package/dist/recipes/scheduler.js +110 -0
  241. package/dist/recipes/scheduler.js.map +1 -0
  242. package/dist/recipes/schema.d.ts +71 -0
  243. package/dist/recipes/schema.js +11 -0
  244. package/dist/recipes/schema.js.map +1 -0
  245. package/dist/recipesHttp.d.ts +63 -0
  246. package/dist/recipesHttp.js +183 -0
  247. package/dist/recipesHttp.js.map +1 -0
  248. package/dist/resources.d.ts +33 -0
  249. package/dist/resources.js +266 -0
  250. package/dist/resources.js.map +1 -0
  251. package/dist/riskTier.d.ts +40 -0
  252. package/dist/riskTier.js +142 -0
  253. package/dist/riskTier.js.map +1 -0
  254. package/dist/runLog.d.ts +90 -0
  255. package/dist/runLog.js +143 -0
  256. package/dist/runLog.js.map +1 -0
  257. package/dist/server.d.ts +160 -0
  258. package/dist/server.js +1244 -0
  259. package/dist/server.js.map +1 -0
  260. package/dist/sessionCheckpoint.d.ts +37 -0
  261. package/dist/sessionCheckpoint.js +123 -0
  262. package/dist/sessionCheckpoint.js.map +1 -0
  263. package/dist/streamableHttp.d.ts +86 -0
  264. package/dist/streamableHttp.js +702 -0
  265. package/dist/streamableHttp.js.map +1 -0
  266. package/dist/telemetry.d.ts +18 -0
  267. package/dist/telemetry.js +95 -0
  268. package/dist/telemetry.js.map +1 -0
  269. package/dist/tools/activityLog.d.ts +140 -0
  270. package/dist/tools/activityLog.js +204 -0
  271. package/dist/tools/activityLog.js.map +1 -0
  272. package/dist/tools/auditDependencies.d.ts +67 -0
  273. package/dist/tools/auditDependencies.js +298 -0
  274. package/dist/tools/auditDependencies.js.map +1 -0
  275. package/dist/tools/batchLsp.d.ts +262 -0
  276. package/dist/tools/batchLsp.js +328 -0
  277. package/dist/tools/batchLsp.js.map +1 -0
  278. package/dist/tools/blame-utils.d.ts +30 -0
  279. package/dist/tools/blame-utils.js +60 -0
  280. package/dist/tools/blame-utils.js.map +1 -0
  281. package/dist/tools/bridgeDoctor.d.ts +78 -0
  282. package/dist/tools/bridgeDoctor.js +542 -0
  283. package/dist/tools/bridgeDoctor.js.map +1 -0
  284. package/dist/tools/bridgeStatus.d.ts +122 -0
  285. package/dist/tools/bridgeStatus.js +250 -0
  286. package/dist/tools/bridgeStatus.js.map +1 -0
  287. package/dist/tools/cancelClaudeTask.d.ts +48 -0
  288. package/dist/tools/cancelClaudeTask.js +56 -0
  289. package/dist/tools/cancelClaudeTask.js.map +1 -0
  290. package/dist/tools/checkDocumentDirty.d.ts +56 -0
  291. package/dist/tools/checkDocumentDirty.js +74 -0
  292. package/dist/tools/checkDocumentDirty.js.map +1 -0
  293. package/dist/tools/clipboard.d.ts +80 -0
  294. package/dist/tools/clipboard.js +211 -0
  295. package/dist/tools/clipboard.js.map +1 -0
  296. package/dist/tools/closeTabs.d.ts +84 -0
  297. package/dist/tools/closeTabs.js +97 -0
  298. package/dist/tools/closeTabs.js.map +1 -0
  299. package/dist/tools/codeLens.d.ts +50 -0
  300. package/dist/tools/codeLens.js +47 -0
  301. package/dist/tools/codeLens.js.map +1 -0
  302. package/dist/tools/contextBundle.d.ts +75 -0
  303. package/dist/tools/contextBundle.js +218 -0
  304. package/dist/tools/contextBundle.js.map +1 -0
  305. package/dist/tools/createIssueFromAIComment.d.ts +75 -0
  306. package/dist/tools/createIssueFromAIComment.js +119 -0
  307. package/dist/tools/createIssueFromAIComment.js.map +1 -0
  308. package/dist/tools/ctxGetTaskContext.d.ts +103 -0
  309. package/dist/tools/ctxGetTaskContext.js +274 -0
  310. package/dist/tools/ctxGetTaskContext.js.map +1 -0
  311. package/dist/tools/ctxQueryTraces.d.ts +142 -0
  312. package/dist/tools/ctxQueryTraces.js +194 -0
  313. package/dist/tools/ctxQueryTraces.js.map +1 -0
  314. package/dist/tools/ctxSaveTrace.d.ts +87 -0
  315. package/dist/tools/ctxSaveTrace.js +94 -0
  316. package/dist/tools/ctxSaveTrace.js.map +1 -0
  317. package/dist/tools/debug.d.ts +206 -0
  318. package/dist/tools/debug.js +234 -0
  319. package/dist/tools/debug.js.map +1 -0
  320. package/dist/tools/decorations.d.ts +130 -0
  321. package/dist/tools/decorations.js +160 -0
  322. package/dist/tools/decorations.js.map +1 -0
  323. package/dist/tools/detectUnusedCode.d.ts +78 -0
  324. package/dist/tools/detectUnusedCode.js +173 -0
  325. package/dist/tools/detectUnusedCode.js.map +1 -0
  326. package/dist/tools/documentLinks.d.ts +62 -0
  327. package/dist/tools/documentLinks.js +55 -0
  328. package/dist/tools/documentLinks.js.map +1 -0
  329. package/dist/tools/editText.d.ts +108 -0
  330. package/dist/tools/editText.js +318 -0
  331. package/dist/tools/editText.js.map +1 -0
  332. package/dist/tools/enrichCommit.d.ts +89 -0
  333. package/dist/tools/enrichCommit.js +201 -0
  334. package/dist/tools/enrichCommit.js.map +1 -0
  335. package/dist/tools/enrichStackTrace.d.ts +121 -0
  336. package/dist/tools/enrichStackTrace.js +194 -0
  337. package/dist/tools/enrichStackTrace.js.map +1 -0
  338. package/dist/tools/explainDiagnostic.d.ts +137 -0
  339. package/dist/tools/explainDiagnostic.js +230 -0
  340. package/dist/tools/explainDiagnostic.js.map +1 -0
  341. package/dist/tools/explainSymbol.d.ts +119 -0
  342. package/dist/tools/explainSymbol.js +177 -0
  343. package/dist/tools/explainSymbol.js.map +1 -0
  344. package/dist/tools/fileOperations.d.ts +186 -0
  345. package/dist/tools/fileOperations.js +330 -0
  346. package/dist/tools/fileOperations.js.map +1 -0
  347. package/dist/tools/fileWatcher.d.ts +107 -0
  348. package/dist/tools/fileWatcher.js +121 -0
  349. package/dist/tools/fileWatcher.js.map +1 -0
  350. package/dist/tools/findFiles.d.ts +65 -0
  351. package/dist/tools/findFiles.js +142 -0
  352. package/dist/tools/findFiles.js.map +1 -0
  353. package/dist/tools/findRelatedTests.d.ts +83 -0
  354. package/dist/tools/findRelatedTests.js +196 -0
  355. package/dist/tools/findRelatedTests.js.map +1 -0
  356. package/dist/tools/fixAllLintErrors.d.ts +66 -0
  357. package/dist/tools/fixAllLintErrors.js +128 -0
  358. package/dist/tools/fixAllLintErrors.js.map +1 -0
  359. package/dist/tools/foldingRanges.d.ts +50 -0
  360. package/dist/tools/foldingRanges.js +51 -0
  361. package/dist/tools/foldingRanges.js.map +1 -0
  362. package/dist/tools/formatAndSave.d.ts +57 -0
  363. package/dist/tools/formatAndSave.js +87 -0
  364. package/dist/tools/formatAndSave.js.map +1 -0
  365. package/dist/tools/formatDocument.d.ts +61 -0
  366. package/dist/tools/formatDocument.js +144 -0
  367. package/dist/tools/formatDocument.js.map +1 -0
  368. package/dist/tools/generateAPIDocumentation.d.ts +62 -0
  369. package/dist/tools/generateAPIDocumentation.js +249 -0
  370. package/dist/tools/generateAPIDocumentation.js.map +1 -0
  371. package/dist/tools/generateTests.d.ts +75 -0
  372. package/dist/tools/generateTests.js +226 -0
  373. package/dist/tools/generateTests.js.map +1 -0
  374. package/dist/tools/getAIComments.d.ts +79 -0
  375. package/dist/tools/getAIComments.js +93 -0
  376. package/dist/tools/getAIComments.js.map +1 -0
  377. package/dist/tools/getAnalyticsReport.d.ts +102 -0
  378. package/dist/tools/getAnalyticsReport.js +137 -0
  379. package/dist/tools/getAnalyticsReport.js.map +1 -0
  380. package/dist/tools/getArchitectureContext.d.ts +85 -0
  381. package/dist/tools/getArchitectureContext.js +135 -0
  382. package/dist/tools/getArchitectureContext.js.map +1 -0
  383. package/dist/tools/getBufferContent.d.ts +80 -0
  384. package/dist/tools/getBufferContent.js +207 -0
  385. package/dist/tools/getBufferContent.js.map +1 -0
  386. package/dist/tools/getChangeImpact.d.ts +76 -0
  387. package/dist/tools/getChangeImpact.js +184 -0
  388. package/dist/tools/getChangeImpact.js.map +1 -0
  389. package/dist/tools/getClaudeTaskStatus.d.ts +87 -0
  390. package/dist/tools/getClaudeTaskStatus.js +89 -0
  391. package/dist/tools/getClaudeTaskStatus.js.map +1 -0
  392. package/dist/tools/getCodeCoverage.d.ts +86 -0
  393. package/dist/tools/getCodeCoverage.js +237 -0
  394. package/dist/tools/getCodeCoverage.js.map +1 -0
  395. package/dist/tools/getCommitsForIssue.d.ts +98 -0
  396. package/dist/tools/getCommitsForIssue.js +106 -0
  397. package/dist/tools/getCommitsForIssue.js.map +1 -0
  398. package/dist/tools/getCurrentSelection.d.ts +123 -0
  399. package/dist/tools/getCurrentSelection.js +113 -0
  400. package/dist/tools/getCurrentSelection.js.map +1 -0
  401. package/dist/tools/getDebugState.d.ts +140 -0
  402. package/dist/tools/getDebugState.js +109 -0
  403. package/dist/tools/getDebugState.js.map +1 -0
  404. package/dist/tools/getDependencyTree.d.ts +59 -0
  405. package/dist/tools/getDependencyTree.js +207 -0
  406. package/dist/tools/getDependencyTree.js.map +1 -0
  407. package/dist/tools/getDiagnostics.d.ts +108 -0
  408. package/dist/tools/getDiagnostics.js +371 -0
  409. package/dist/tools/getDiagnostics.js.map +1 -0
  410. package/dist/tools/getDiffFromHandoff.d.ts +89 -0
  411. package/dist/tools/getDiffFromHandoff.js +163 -0
  412. package/dist/tools/getDiffFromHandoff.js.map +1 -0
  413. package/dist/tools/getDocumentSymbols.d.ts +74 -0
  414. package/dist/tools/getDocumentSymbols.js +177 -0
  415. package/dist/tools/getDocumentSymbols.js.map +1 -0
  416. package/dist/tools/getFileTree.d.ts +66 -0
  417. package/dist/tools/getFileTree.js +131 -0
  418. package/dist/tools/getFileTree.js.map +1 -0
  419. package/dist/tools/getGitDiff.d.ts +50 -0
  420. package/dist/tools/getGitDiff.js +73 -0
  421. package/dist/tools/getGitDiff.js.map +1 -0
  422. package/dist/tools/getGitHotspots.d.ts +88 -0
  423. package/dist/tools/getGitHotspots.js +145 -0
  424. package/dist/tools/getGitHotspots.js.map +1 -0
  425. package/dist/tools/getGitLog.d.ts +62 -0
  426. package/dist/tools/getGitLog.js +87 -0
  427. package/dist/tools/getGitLog.js.map +1 -0
  428. package/dist/tools/getGitStatus.d.ts +72 -0
  429. package/dist/tools/getGitStatus.js +126 -0
  430. package/dist/tools/getGitStatus.js.map +1 -0
  431. package/dist/tools/getImportTree.d.ts +73 -0
  432. package/dist/tools/getImportTree.js +223 -0
  433. package/dist/tools/getImportTree.js.map +1 -0
  434. package/dist/tools/getImportedSignatures.d.ts +62 -0
  435. package/dist/tools/getImportedSignatures.js +255 -0
  436. package/dist/tools/getImportedSignatures.js.map +1 -0
  437. package/dist/tools/getOpenEditors.d.ts +62 -0
  438. package/dist/tools/getOpenEditors.js +126 -0
  439. package/dist/tools/getOpenEditors.js.map +1 -0
  440. package/dist/tools/getPRTemplate.d.ts +68 -0
  441. package/dist/tools/getPRTemplate.js +187 -0
  442. package/dist/tools/getPRTemplate.js.map +1 -0
  443. package/dist/tools/getProjectContext.d.ts +114 -0
  444. package/dist/tools/getProjectContext.js +344 -0
  445. package/dist/tools/getProjectContext.js.map +1 -0
  446. package/dist/tools/getProjectInfo.d.ts +51 -0
  447. package/dist/tools/getProjectInfo.js +325 -0
  448. package/dist/tools/getProjectInfo.js.map +1 -0
  449. package/dist/tools/getSecurityAdvisories.d.ts +105 -0
  450. package/dist/tools/getSecurityAdvisories.js +472 -0
  451. package/dist/tools/getSecurityAdvisories.js.map +1 -0
  452. package/dist/tools/getSessionUsage.d.ts +58 -0
  453. package/dist/tools/getSessionUsage.js +57 -0
  454. package/dist/tools/getSessionUsage.js.map +1 -0
  455. package/dist/tools/getSymbolHistory.d.ts +157 -0
  456. package/dist/tools/getSymbolHistory.js +256 -0
  457. package/dist/tools/getSymbolHistory.js.map +1 -0
  458. package/dist/tools/getToolCapabilities.d.ts +69 -0
  459. package/dist/tools/getToolCapabilities.js +298 -0
  460. package/dist/tools/getToolCapabilities.js.map +1 -0
  461. package/dist/tools/getTypeSignature.d.ts +70 -0
  462. package/dist/tools/getTypeSignature.js +132 -0
  463. package/dist/tools/getTypeSignature.js.map +1 -0
  464. package/dist/tools/getWorkspaceFolders.d.ts +58 -0
  465. package/dist/tools/getWorkspaceFolders.js +69 -0
  466. package/dist/tools/getWorkspaceFolders.js.map +1 -0
  467. package/dist/tools/getWorkspaceSettings.d.ts +44 -0
  468. package/dist/tools/getWorkspaceSettings.js +70 -0
  469. package/dist/tools/getWorkspaceSettings.js.map +1 -0
  470. package/dist/tools/git-utils.d.ts +16 -0
  471. package/dist/tools/git-utils.js +46 -0
  472. package/dist/tools/git-utils.js.map +1 -0
  473. package/dist/tools/gitHistory.d.ts +110 -0
  474. package/dist/tools/gitHistory.js +167 -0
  475. package/dist/tools/gitHistory.js.map +1 -0
  476. package/dist/tools/gitWrite.d.ts +612 -0
  477. package/dist/tools/gitWrite.js +983 -0
  478. package/dist/tools/gitWrite.js.map +1 -0
  479. package/dist/tools/github/actions.d.ts +152 -0
  480. package/dist/tools/github/actions.js +195 -0
  481. package/dist/tools/github/actions.js.map +1 -0
  482. package/dist/tools/github/index.d.ts +3 -0
  483. package/dist/tools/github/index.js +4 -0
  484. package/dist/tools/github/index.js.map +1 -0
  485. package/dist/tools/github/issues.d.ts +281 -0
  486. package/dist/tools/github/issues.js +340 -0
  487. package/dist/tools/github/issues.js.map +1 -0
  488. package/dist/tools/github/pr.d.ts +433 -0
  489. package/dist/tools/github/pr.js +588 -0
  490. package/dist/tools/github/pr.js.map +1 -0
  491. package/dist/tools/github/shared.d.ts +4 -0
  492. package/dist/tools/github/shared.js +12 -0
  493. package/dist/tools/github/shared.js.map +1 -0
  494. package/dist/tools/handoffNote.d.ts +106 -0
  495. package/dist/tools/handoffNote.js +232 -0
  496. package/dist/tools/handoffNote.js.map +1 -0
  497. package/dist/tools/headless/lspClient.d.ts +26 -0
  498. package/dist/tools/headless/lspClient.js +221 -0
  499. package/dist/tools/headless/lspClient.js.map +1 -0
  500. package/dist/tools/headless/lspFallback.d.ts +28 -0
  501. package/dist/tools/headless/lspFallback.js +122 -0
  502. package/dist/tools/headless/lspFallback.js.map +1 -0
  503. package/dist/tools/hoverAtCursor.d.ts +54 -0
  504. package/dist/tools/hoverAtCursor.js +68 -0
  505. package/dist/tools/hoverAtCursor.js.map +1 -0
  506. package/dist/tools/httpClient.d.ts +141 -0
  507. package/dist/tools/httpClient.js +486 -0
  508. package/dist/tools/httpClient.js.map +1 -0
  509. package/dist/tools/index.d.ts +49 -0
  510. package/dist/tools/index.js +672 -0
  511. package/dist/tools/index.js.map +1 -0
  512. package/dist/tools/inlayHints.d.ts +81 -0
  513. package/dist/tools/inlayHints.js +76 -0
  514. package/dist/tools/inlayHints.js.map +1 -0
  515. package/dist/tools/issueRefs.d.ts +14 -0
  516. package/dist/tools/issueRefs.js +27 -0
  517. package/dist/tools/issueRefs.js.map +1 -0
  518. package/dist/tools/jumpToFirstError.d.ts +63 -0
  519. package/dist/tools/jumpToFirstError.js +124 -0
  520. package/dist/tools/jumpToFirstError.js.map +1 -0
  521. package/dist/tools/launchQuickTask.d.ts +76 -0
  522. package/dist/tools/launchQuickTask.js +170 -0
  523. package/dist/tools/launchQuickTask.js.map +1 -0
  524. package/dist/tools/linters/biome.d.ts +2 -0
  525. package/dist/tools/linters/biome.js +44 -0
  526. package/dist/tools/linters/biome.js.map +1 -0
  527. package/dist/tools/linters/cargo.d.ts +2 -0
  528. package/dist/tools/linters/cargo.js +45 -0
  529. package/dist/tools/linters/cargo.js.map +1 -0
  530. package/dist/tools/linters/eslint.d.ts +2 -0
  531. package/dist/tools/linters/eslint.js +59 -0
  532. package/dist/tools/linters/eslint.js.map +1 -0
  533. package/dist/tools/linters/govet.d.ts +2 -0
  534. package/dist/tools/linters/govet.js +37 -0
  535. package/dist/tools/linters/govet.js.map +1 -0
  536. package/dist/tools/linters/pyright.d.ts +2 -0
  537. package/dist/tools/linters/pyright.js +34 -0
  538. package/dist/tools/linters/pyright.js.map +1 -0
  539. package/dist/tools/linters/ruff.d.ts +2 -0
  540. package/dist/tools/linters/ruff.js +30 -0
  541. package/dist/tools/linters/ruff.js.map +1 -0
  542. package/dist/tools/linters/types.d.ts +16 -0
  543. package/dist/tools/linters/types.js +2 -0
  544. package/dist/tools/linters/types.js.map +1 -0
  545. package/dist/tools/linters/typescript.d.ts +2 -0
  546. package/dist/tools/linters/typescript.js +38 -0
  547. package/dist/tools/linters/typescript.js.map +1 -0
  548. package/dist/tools/listClaudeTasks.d.ts +84 -0
  549. package/dist/tools/listClaudeTasks.js +88 -0
  550. package/dist/tools/listClaudeTasks.js.map +1 -0
  551. package/dist/tools/listTerminals.d.ts +55 -0
  552. package/dist/tools/listTerminals.js +78 -0
  553. package/dist/tools/listTerminals.js.map +1 -0
  554. package/dist/tools/lsp.d.ts +1086 -0
  555. package/dist/tools/lsp.js +1339 -0
  556. package/dist/tools/lsp.js.map +1 -0
  557. package/dist/tools/navigateToSymbolByName.d.ts +56 -0
  558. package/dist/tools/navigateToSymbolByName.js +170 -0
  559. package/dist/tools/navigateToSymbolByName.js.map +1 -0
  560. package/dist/tools/openDiff.d.ts +66 -0
  561. package/dist/tools/openDiff.js +126 -0
  562. package/dist/tools/openDiff.js.map +1 -0
  563. package/dist/tools/openFile.d.ts +69 -0
  564. package/dist/tools/openFile.js +129 -0
  565. package/dist/tools/openFile.js.map +1 -0
  566. package/dist/tools/openInBrowser.d.ts +55 -0
  567. package/dist/tools/openInBrowser.js +129 -0
  568. package/dist/tools/openInBrowser.js.map +1 -0
  569. package/dist/tools/organizeImports.d.ts +56 -0
  570. package/dist/tools/organizeImports.js +115 -0
  571. package/dist/tools/organizeImports.js.map +1 -0
  572. package/dist/tools/performanceReport.d.ts +133 -0
  573. package/dist/tools/performanceReport.js +218 -0
  574. package/dist/tools/performanceReport.js.map +1 -0
  575. package/dist/tools/planPersistence.d.ts +306 -0
  576. package/dist/tools/planPersistence.js +485 -0
  577. package/dist/tools/planPersistence.js.map +1 -0
  578. package/dist/tools/previewEdit.d.ts +107 -0
  579. package/dist/tools/previewEdit.js +270 -0
  580. package/dist/tools/previewEdit.js.map +1 -0
  581. package/dist/tools/recentTracesDigest.d.ts +35 -0
  582. package/dist/tools/recentTracesDigest.js +98 -0
  583. package/dist/tools/recentTracesDigest.js.map +1 -0
  584. package/dist/tools/refactorAnalyze.d.ts +78 -0
  585. package/dist/tools/refactorAnalyze.js +141 -0
  586. package/dist/tools/refactorAnalyze.js.map +1 -0
  587. package/dist/tools/refactorExtractFunction.d.ts +52 -0
  588. package/dist/tools/refactorExtractFunction.js +121 -0
  589. package/dist/tools/refactorExtractFunction.js.map +1 -0
  590. package/dist/tools/refactorPreview.d.ts +75 -0
  591. package/dist/tools/refactorPreview.js +93 -0
  592. package/dist/tools/refactorPreview.js.map +1 -0
  593. package/dist/tools/replaceBlock.d.ts +62 -0
  594. package/dist/tools/replaceBlock.js +125 -0
  595. package/dist/tools/replaceBlock.js.map +1 -0
  596. package/dist/tools/resumeClaudeTask.d.ts +75 -0
  597. package/dist/tools/resumeClaudeTask.js +149 -0
  598. package/dist/tools/resumeClaudeTask.js.map +1 -0
  599. package/dist/tools/runClaudeTask.d.ts +97 -0
  600. package/dist/tools/runClaudeTask.js +224 -0
  601. package/dist/tools/runClaudeTask.js.map +1 -0
  602. package/dist/tools/runCommand.d.ts +82 -0
  603. package/dist/tools/runCommand.js +101 -0
  604. package/dist/tools/runCommand.js.map +1 -0
  605. package/dist/tools/runTests.d.ts +146 -0
  606. package/dist/tools/runTests.js +315 -0
  607. package/dist/tools/runTests.js.map +1 -0
  608. package/dist/tools/saveDocument.d.ts +50 -0
  609. package/dist/tools/saveDocument.js +73 -0
  610. package/dist/tools/saveDocument.js.map +1 -0
  611. package/dist/tools/screenshot.d.ts +23 -0
  612. package/dist/tools/screenshot.js +43 -0
  613. package/dist/tools/screenshot.js.map +1 -0
  614. package/dist/tools/screenshotAndAnnotate.d.ts +103 -0
  615. package/dist/tools/screenshotAndAnnotate.js +192 -0
  616. package/dist/tools/screenshotAndAnnotate.js.map +1 -0
  617. package/dist/tools/searchAndReplace.d.ts +108 -0
  618. package/dist/tools/searchAndReplace.js +281 -0
  619. package/dist/tools/searchAndReplace.js.map +1 -0
  620. package/dist/tools/searchTools.d.ts +61 -0
  621. package/dist/tools/searchTools.js +85 -0
  622. package/dist/tools/searchTools.js.map +1 -0
  623. package/dist/tools/searchWorkspace.d.ts +99 -0
  624. package/dist/tools/searchWorkspace.js +189 -0
  625. package/dist/tools/searchWorkspace.js.map +1 -0
  626. package/dist/tools/selectionRanges.d.ts +58 -0
  627. package/dist/tools/selectionRanges.js +61 -0
  628. package/dist/tools/selectionRanges.js.map +1 -0
  629. package/dist/tools/semanticTokens.d.ts +87 -0
  630. package/dist/tools/semanticTokens.js +86 -0
  631. package/dist/tools/semanticTokens.js.map +1 -0
  632. package/dist/tools/setActiveWorkspaceFolder.d.ts +41 -0
  633. package/dist/tools/setActiveWorkspaceFolder.js +38 -0
  634. package/dist/tools/setActiveWorkspaceFolder.js.map +1 -0
  635. package/dist/tools/signatureHelp.d.ts +86 -0
  636. package/dist/tools/signatureHelp.js +79 -0
  637. package/dist/tools/signatureHelp.js.map +1 -0
  638. package/dist/tools/spawnWorkspace.d.ts +103 -0
  639. package/dist/tools/spawnWorkspace.js +268 -0
  640. package/dist/tools/spawnWorkspace.js.map +1 -0
  641. package/dist/tools/stackTraceParser.d.ts +43 -0
  642. package/dist/tools/stackTraceParser.js +139 -0
  643. package/dist/tools/stackTraceParser.js.map +1 -0
  644. package/dist/tools/terminal.d.ts +352 -0
  645. package/dist/tools/terminal.js +670 -0
  646. package/dist/tools/terminal.js.map +1 -0
  647. package/dist/tools/testRunners/cargoTest.d.ts +2 -0
  648. package/dist/tools/testRunners/cargoTest.js +129 -0
  649. package/dist/tools/testRunners/cargoTest.js.map +1 -0
  650. package/dist/tools/testRunners/goTest.d.ts +2 -0
  651. package/dist/tools/testRunners/goTest.js +108 -0
  652. package/dist/tools/testRunners/goTest.js.map +1 -0
  653. package/dist/tools/testRunners/pytest.d.ts +2 -0
  654. package/dist/tools/testRunners/pytest.js +135 -0
  655. package/dist/tools/testRunners/pytest.js.map +1 -0
  656. package/dist/tools/testRunners/types.d.ts +18 -0
  657. package/dist/tools/testRunners/types.js +2 -0
  658. package/dist/tools/testRunners/types.js.map +1 -0
  659. package/dist/tools/testRunners/vitestJest.d.ts +3 -0
  660. package/dist/tools/testRunners/vitestJest.js +215 -0
  661. package/dist/tools/testRunners/vitestJest.js.map +1 -0
  662. package/dist/tools/testTraceToSource.d.ts +80 -0
  663. package/dist/tools/testTraceToSource.js +206 -0
  664. package/dist/tools/testTraceToSource.js.map +1 -0
  665. package/dist/tools/transaction.d.ts +243 -0
  666. package/dist/tools/transaction.js +309 -0
  667. package/dist/tools/transaction.js.map +1 -0
  668. package/dist/tools/typeHierarchy.d.ts +77 -0
  669. package/dist/tools/typeHierarchy.js +86 -0
  670. package/dist/tools/typeHierarchy.js.map +1 -0
  671. package/dist/tools/utils.d.ts +124 -0
  672. package/dist/tools/utils.js +566 -0
  673. package/dist/tools/utils.js.map +1 -0
  674. package/dist/tools/vscodeCommands.d.ts +90 -0
  675. package/dist/tools/vscodeCommands.js +112 -0
  676. package/dist/tools/vscodeCommands.js.map +1 -0
  677. package/dist/tools/vscodeTasks.d.ts +102 -0
  678. package/dist/tools/vscodeTasks.js +110 -0
  679. package/dist/tools/vscodeTasks.js.map +1 -0
  680. package/dist/tools/watchDiagnostics.d.ts +64 -0
  681. package/dist/tools/watchDiagnostics.js +270 -0
  682. package/dist/tools/watchDiagnostics.js.map +1 -0
  683. package/dist/tools/workspaceSettings.d.ts +57 -0
  684. package/dist/tools/workspaceSettings.js +80 -0
  685. package/dist/tools/workspaceSettings.js.map +1 -0
  686. package/dist/transport.d.ts +207 -0
  687. package/dist/transport.js +1272 -0
  688. package/dist/transport.js.map +1 -0
  689. package/dist/version.d.ts +13 -0
  690. package/dist/version.js +31 -0
  691. package/dist/version.js.map +1 -0
  692. package/dist/wsUtils.d.ts +8 -0
  693. package/dist/wsUtils.js +54 -0
  694. package/dist/wsUtils.js.map +1 -0
  695. package/package.json +118 -0
  696. package/scripts/gen-claude-desktop-config.sh +124 -0
  697. package/scripts/gen-mcp-config.sh +390 -0
  698. package/scripts/install-extension.sh +106 -0
  699. package/scripts/mcp-stdio-shim.cjs +482 -0
  700. package/scripts/postinstall.mjs +68 -0
  701. package/scripts/start-all.sh +502 -0
  702. package/scripts/start-orchestrator.sh +186 -0
  703. package/scripts/start-remote.sh +126 -0
  704. package/scripts/start-vps.sh +116 -0
  705. package/templates/CLAUDE.bridge.md +125 -0
  706. package/templates/automation-policies/security-first.json +46 -0
  707. package/templates/automation-policies/strict-lint.json +41 -0
  708. package/templates/automation-policies/test-driven.json +54 -0
  709. package/templates/automation-policy.example.json +105 -0
  710. package/templates/bridge-tools.md +111 -0
  711. package/templates/dispatch-context.md +33 -0
  712. package/templates/managed-agent/code-review-agent.md +50 -0
  713. package/templates/managed-agent/managed-agent-mcp.json +102 -0
  714. package/templates/recipes/ambient-journal.yaml +11 -0
  715. package/templates/recipes/daily-status.yaml +21 -0
  716. package/templates/recipes/lint-on-save.yaml +13 -0
  717. package/templates/recipes/stale-branches.yaml +18 -0
  718. package/templates/recipes/watch-failing-tests.yaml +15 -0
  719. package/templates/scheduled-tasks/dependency-audit/SKILL.md +77 -0
  720. package/templates/scheduled-tasks/health-check/SKILL.md +73 -0
  721. package/templates/scheduled-tasks/nightly-review/SKILL.md +69 -0
@@ -0,0 +1,983 @@
1
+ import { checkGitRepo, isValidRef, runGit } from "./git-utils.js";
2
+ import { error, execSafe, optionalBool, optionalString, requireString, resolveFilePath, successStructured, } from "./utils.js";
3
+ async function currentBranch(workspace, signal) {
4
+ const r = await execSafe("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
5
+ cwd: workspace,
6
+ signal,
7
+ });
8
+ return r.stdout.trim();
9
+ }
10
+ // Validate that all provided paths stay within the workspace.
11
+ // Uses resolveFilePath which also resolves symlinks (preventing symlink-based escapes).
12
+ function validatePaths(files, workspace) {
13
+ for (const f of files) {
14
+ try {
15
+ resolveFilePath(f, workspace);
16
+ }
17
+ catch (err) {
18
+ return err instanceof Error
19
+ ? err.message
20
+ : `Path escapes workspace: ${f}`;
21
+ }
22
+ }
23
+ return null;
24
+ }
25
+ export function createGitAddTool(workspace) {
26
+ return {
27
+ schema: {
28
+ name: "gitAdd",
29
+ description: "Stage files for commit. Omit to stage all tracked (git add -u). addUntracked:true for new files.",
30
+ annotations: { destructiveHint: false },
31
+ inputSchema: {
32
+ type: "object",
33
+ properties: {
34
+ files: {
35
+ type: "array",
36
+ items: { type: "string" },
37
+ description: "Paths to stage (absolute or workspace-relative). Omit to stage all modified tracked files.",
38
+ },
39
+ addUntracked: {
40
+ type: "boolean",
41
+ description: "Also stage new untracked files. Default: false.",
42
+ },
43
+ },
44
+ additionalProperties: false,
45
+ },
46
+ outputSchema: {
47
+ type: "object",
48
+ properties: {
49
+ staged: { type: "array", items: { type: "string" } },
50
+ count: { type: "integer" },
51
+ },
52
+ required: ["staged", "count"],
53
+ },
54
+ },
55
+ handler: async (args, signal) => {
56
+ if (!(await checkGitRepo(workspace, signal))) {
57
+ return error("Not a git repository", "git_error");
58
+ }
59
+ const rawFiles = args.files;
60
+ const addUntracked = optionalBool(args, "addUntracked") ?? false;
61
+ let addArgs;
62
+ if (Array.isArray(rawFiles) && rawFiles.length > 0) {
63
+ const files = rawFiles.map(String);
64
+ const pathErr = validatePaths(files, workspace);
65
+ if (pathErr)
66
+ return error(pathErr);
67
+ addArgs = ["add", "--", ...files];
68
+ }
69
+ else if (addUntracked) {
70
+ addArgs = ["add", "."];
71
+ }
72
+ else {
73
+ addArgs = ["add", "-u"];
74
+ }
75
+ try {
76
+ await runGit(addArgs, workspace, { signal, timeout: 15_000 });
77
+ }
78
+ catch (e) {
79
+ return error(`git add failed: ${e instanceof Error ? e.message : "unknown error"}`);
80
+ }
81
+ // Show what's now staged
82
+ const statusResult = await execSafe("git", ["diff", "--name-only", "--cached"], { cwd: workspace, signal });
83
+ const staged = statusResult.stdout
84
+ .split("\n")
85
+ .map((f) => f.trim())
86
+ .filter(Boolean);
87
+ return successStructured({ staged, count: staged.length });
88
+ },
89
+ };
90
+ }
91
+ export function createGitCommitTool(workspace, onGitCommit) {
92
+ return {
93
+ schema: {
94
+ name: "gitCommit",
95
+ description: "Commit staged changes. Pass files to stage-and-commit in one step. Returns hash, branch, files.",
96
+ annotations: { destructiveHint: true },
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: {
100
+ message: {
101
+ type: "string",
102
+ description: "Commit message",
103
+ },
104
+ files: {
105
+ type: "array",
106
+ items: { type: "string" },
107
+ description: "Files to stage before committing. Omit to commit already-staged changes.",
108
+ },
109
+ addAll: {
110
+ type: "boolean",
111
+ description: "Stage all tracked changes before committing (git add -u). Default: false.",
112
+ },
113
+ },
114
+ required: ["message"],
115
+ additionalProperties: false,
116
+ },
117
+ outputSchema: {
118
+ type: "object",
119
+ properties: {
120
+ hash: { type: "string" },
121
+ branch: { type: "string" },
122
+ message: { type: "string" },
123
+ files: { type: "array", items: { type: "string" } },
124
+ count: { type: "integer" },
125
+ },
126
+ required: ["hash", "branch", "message", "files", "count"],
127
+ },
128
+ },
129
+ handler: async (args, signal) => {
130
+ if (!(await checkGitRepo(workspace, signal))) {
131
+ return error("Not a git repository", "git_error");
132
+ }
133
+ const message = requireString(args, "message", 4096);
134
+ if (message.trim().length === 0) {
135
+ return error("Commit message must not be empty");
136
+ }
137
+ const rawFiles = args.files;
138
+ const addAll = optionalBool(args, "addAll") ?? false;
139
+ // Stage files if requested
140
+ if (Array.isArray(rawFiles) && rawFiles.length > 0) {
141
+ const files = rawFiles.map(String);
142
+ const pathErr = validatePaths(files, workspace);
143
+ if (pathErr)
144
+ return error(pathErr);
145
+ try {
146
+ await runGit(["add", "--", ...files], workspace, {
147
+ signal,
148
+ timeout: 15_000,
149
+ });
150
+ }
151
+ catch (e) {
152
+ return error(`git add failed: ${e instanceof Error ? e.message : "unknown error"}`);
153
+ }
154
+ }
155
+ else if (addAll) {
156
+ try {
157
+ await runGit(["add", "-u"], workspace, { signal, timeout: 15_000 });
158
+ }
159
+ catch (e) {
160
+ return error(`git add -u failed: ${e instanceof Error ? e.message : "unknown error"}`);
161
+ }
162
+ }
163
+ // Check there is something staged
164
+ const diffCheck = await execSafe("git", ["diff", "--cached", "--quiet"], {
165
+ cwd: workspace,
166
+ signal,
167
+ });
168
+ if (diffCheck.exitCode === 0) {
169
+ // exit 0 = nothing staged (exit 1 = something staged; exit 128 = no HEAD
170
+ // yet on initial repo — fall through and let `git commit` surface the error)
171
+ const status = await execSafe("git", ["status", "--short"], {
172
+ cwd: workspace,
173
+ signal,
174
+ });
175
+ return error(`Nothing staged to commit. ${status.stdout.trim()
176
+ ? `Unstaged changes exist:\n${status.stdout.trim()}\nUse gitAdd or pass files to this tool.`
177
+ : "Working tree is clean."}`);
178
+ }
179
+ // Commit
180
+ try {
181
+ await runGit(["commit", "-m", message], workspace, {
182
+ signal,
183
+ timeout: 30_000,
184
+ });
185
+ }
186
+ catch (e) {
187
+ return error(`git commit failed: ${e instanceof Error ? e.message : "unknown error"}`);
188
+ }
189
+ // Get commit hash
190
+ const hashResult = await execSafe("git", ["rev-parse", "HEAD"], {
191
+ cwd: workspace,
192
+ signal,
193
+ });
194
+ const hash = hashResult.stdout.trim().slice(0, 12);
195
+ const branch = await currentBranch(workspace, signal);
196
+ // List files that actually landed in the commit (post-commit, so pre-commit
197
+ // hooks that stage additional files are included in the reported list).
198
+ const diffTreeResult = await execSafe("git", ["diff-tree", "--no-commit-id", "-r", "--name-only", "HEAD"], { cwd: workspace, signal });
199
+ const committedFiles = diffTreeResult.stdout
200
+ .split("\n")
201
+ .map((f) => f.trim())
202
+ .filter(Boolean);
203
+ const commitResult = {
204
+ hash,
205
+ branch,
206
+ message,
207
+ files: committedFiles,
208
+ count: committedFiles.length,
209
+ };
210
+ onGitCommit?.(commitResult);
211
+ return successStructured(commitResult);
212
+ },
213
+ };
214
+ }
215
+ export function createGitCheckoutTool(workspace, onBranchCheckout) {
216
+ return {
217
+ schema: {
218
+ name: "gitCheckout",
219
+ description: "Switch to a branch, or create and switch to a new branch. Use create: true to create from HEAD or a specified base.",
220
+ annotations: { destructiveHint: true },
221
+ inputSchema: {
222
+ type: "object",
223
+ properties: {
224
+ branch: {
225
+ type: "string",
226
+ description: "Branch name to switch to or create",
227
+ },
228
+ create: {
229
+ type: "boolean",
230
+ description: "Create branch if it doesn't exist. Default: false.",
231
+ },
232
+ base: {
233
+ type: "string",
234
+ description: "Base branch or commit to create from (only when create: true). Defaults to HEAD.",
235
+ },
236
+ },
237
+ required: ["branch"],
238
+ additionalProperties: false,
239
+ },
240
+ outputSchema: {
241
+ type: "object",
242
+ properties: {
243
+ branch: { type: "string" },
244
+ previousBranch: { type: ["string", "null"] },
245
+ created: { type: "boolean" },
246
+ },
247
+ required: ["branch", "created"],
248
+ },
249
+ },
250
+ handler: async (args, signal) => {
251
+ if (!(await checkGitRepo(workspace, signal))) {
252
+ return error("Not a git repository", "git_error");
253
+ }
254
+ const branch = requireString(args, "branch");
255
+ const create = optionalBool(args, "create") ?? false;
256
+ const base = optionalString(args, "base");
257
+ // Validate ref names to prevent git flag injection (e.g. --orphan, -b)
258
+ if (!isValidRef(branch)) {
259
+ return error(`Invalid branch name: must match git ref rules (no spaces, no shell metacharacters)`);
260
+ }
261
+ if (base !== undefined && !isValidRef(base)) {
262
+ return error(`Invalid base ref: "${base}"`);
263
+ }
264
+ const prevBranch = await currentBranch(workspace, signal);
265
+ let checkoutArgs;
266
+ if (create) {
267
+ checkoutArgs = base
268
+ ? ["checkout", "-b", branch, base]
269
+ : ["checkout", "-b", branch];
270
+ }
271
+ else {
272
+ checkoutArgs = ["checkout", branch];
273
+ }
274
+ try {
275
+ await runGit(checkoutArgs, workspace, { signal, timeout: 15_000 });
276
+ }
277
+ catch (e) {
278
+ const msg = e instanceof Error ? e.message : "unknown error";
279
+ // Surface helpful hints for common errors
280
+ if (msg.includes("already exists")) {
281
+ return error(`Branch '${branch}' already exists. Use create: false to switch to it, or choose a different name.`);
282
+ }
283
+ if (msg.includes("did not match") || msg.includes("pathspec")) {
284
+ return error(`Branch '${branch}' not found locally. If it exists on remote, run gitFetch first to update remote-tracking branches, then retry.`);
285
+ }
286
+ if (msg.includes("local changes")) {
287
+ return error(`Cannot switch branch: you have uncommitted changes. Use gitStash to save them, then switch branches and use gitStashPop to restore.\n${msg}`);
288
+ }
289
+ return error(`git checkout failed: ${msg}`);
290
+ }
291
+ const newBranch = await currentBranch(workspace, signal);
292
+ const checkoutResult = {
293
+ branch: newBranch,
294
+ // If HEAD was detached, prevBranch is the literal string "HEAD" which
295
+ // cannot be passed back to gitCheckout to restore position. Annotate it
296
+ // so callers know to use the commit hash instead.
297
+ previousBranch: prevBranch === "HEAD" ? null : prevBranch,
298
+ previousCommit: prevBranch === "HEAD"
299
+ ? (await execSafe("git", ["rev-parse", "HEAD"], {
300
+ cwd: workspace,
301
+ signal,
302
+ })).stdout
303
+ .trim()
304
+ .slice(0, 12)
305
+ : undefined,
306
+ wasDetached: prevBranch === "HEAD" || undefined,
307
+ created: create,
308
+ };
309
+ onBranchCheckout?.({
310
+ branch: checkoutResult.branch,
311
+ previousBranch: checkoutResult.previousBranch,
312
+ created: checkoutResult.created,
313
+ });
314
+ return successStructured(checkoutResult);
315
+ },
316
+ };
317
+ }
318
+ export function createGitBlameTool(workspace) {
319
+ return {
320
+ schema: {
321
+ name: "gitBlame",
322
+ description: "Per-line last modifier and commit. Trace why code was written or find the introducing commit.",
323
+ annotations: { readOnlyHint: true },
324
+ inputSchema: {
325
+ type: "object",
326
+ properties: {
327
+ filePath: {
328
+ type: "string",
329
+ description: "Workspace or absolute path to the file",
330
+ },
331
+ startLine: {
332
+ type: "number",
333
+ description: "First line number to blame (1-based, inclusive). Omit for start of file.",
334
+ },
335
+ endLine: {
336
+ type: "number",
337
+ description: "Last line number to blame (1-based, inclusive). Omit for end of file.",
338
+ },
339
+ },
340
+ required: ["filePath"],
341
+ additionalProperties: false,
342
+ },
343
+ outputSchema: {
344
+ type: "object",
345
+ properties: {
346
+ lines: { type: "array" },
347
+ count: { type: "integer" },
348
+ },
349
+ required: ["lines", "count"],
350
+ },
351
+ },
352
+ handler: async (args, signal) => {
353
+ if (!(await checkGitRepo(workspace, signal))) {
354
+ return error("Not a git repository", "git_error");
355
+ }
356
+ const rawPath = requireString(args, "filePath");
357
+ const filePath = resolveFilePath(rawPath, workspace);
358
+ const startLine = typeof args.startLine === "number"
359
+ ? Math.max(1, Math.floor(args.startLine))
360
+ : undefined;
361
+ const endLine = typeof args.endLine === "number"
362
+ ? Math.max(1, Math.floor(args.endLine))
363
+ : undefined;
364
+ const blameArgs = ["blame", "--porcelain"];
365
+ if (startLine !== undefined && endLine !== undefined) {
366
+ blameArgs.push(`-L${startLine},${endLine}`);
367
+ }
368
+ else if (startLine !== undefined) {
369
+ blameArgs.push(`-L${startLine},+50`); // default 50 lines if only start given
370
+ }
371
+ blameArgs.push("--", filePath);
372
+ let blameOutput;
373
+ try {
374
+ ({ stdout: blameOutput } = await runGit(blameArgs, workspace, {
375
+ signal,
376
+ timeout: 15_000,
377
+ maxBuffer: 512 * 1024,
378
+ }));
379
+ }
380
+ catch (e) {
381
+ const msg = e instanceof Error ? e.message : "unknown error";
382
+ if (msg.includes("no such path")) {
383
+ return error(`File not tracked by git: ${filePath}`);
384
+ }
385
+ return error(`git blame failed: ${msg}`);
386
+ }
387
+ // Parse porcelain format
388
+ const lines = blameOutput.split("\n");
389
+ const commits = new Map();
390
+ const blameLines = [];
391
+ let currentHash = "";
392
+ let lineNum = 0;
393
+ for (let i = 0; i < lines.length; i++) {
394
+ const l = lines[i] ?? "";
395
+ if (!l)
396
+ continue;
397
+ const headerMatch = l.match(/^([0-9a-f]{40})\s+\d+\s+(\d+)/);
398
+ if (headerMatch) {
399
+ currentHash = headerMatch[1] ?? "";
400
+ lineNum = Number.parseInt(headerMatch[2] ?? "0", 10);
401
+ continue;
402
+ }
403
+ if (!currentHash)
404
+ continue;
405
+ if (l.startsWith("author ") && !l.startsWith("author-")) {
406
+ const existing = commits.get(currentHash);
407
+ if (!existing) {
408
+ commits.set(currentHash, {
409
+ author: l.slice(7),
410
+ authorEmail: "",
411
+ summary: "",
412
+ timestamp: 0,
413
+ });
414
+ }
415
+ else {
416
+ existing.author = l.slice(7);
417
+ }
418
+ }
419
+ else if (l.startsWith("author-mail ")) {
420
+ const entry = commits.get(currentHash);
421
+ if (entry)
422
+ entry.authorEmail = l.slice(12).replace(/[<>]/g, "");
423
+ }
424
+ else if (l.startsWith("author-time ")) {
425
+ const entry = commits.get(currentHash);
426
+ if (entry)
427
+ entry.timestamp = Number.parseInt(l.slice(12), 10);
428
+ }
429
+ else if (l.startsWith("summary ")) {
430
+ const entry = commits.get(currentHash);
431
+ if (entry)
432
+ entry.summary = l.slice(8);
433
+ }
434
+ else if (l.startsWith("\t")) {
435
+ const info = commits.get(currentHash);
436
+ if (info && lineNum > 0) {
437
+ blameLines.push({
438
+ line: lineNum,
439
+ hash: currentHash.slice(0, 12),
440
+ author: info.author,
441
+ summary: info.summary,
442
+ code: l.slice(1),
443
+ });
444
+ lineNum = 0;
445
+ }
446
+ }
447
+ }
448
+ return successStructured({ lines: blameLines, count: blameLines.length });
449
+ },
450
+ };
451
+ }
452
+ export function createGitFetchTool(workspace) {
453
+ return {
454
+ schema: {
455
+ name: "gitFetch",
456
+ description: "Fetch updates from a remote without merging. Updates remote-tracking branches so gitListBranches " +
457
+ "and gitCheckout see the latest state. Use gitPull to fetch and merge in one step.",
458
+ annotations: { readOnlyHint: true },
459
+ inputSchema: {
460
+ type: "object",
461
+ properties: {
462
+ remote: {
463
+ type: "string",
464
+ description: "Remote to fetch from (default: origin)",
465
+ },
466
+ all: {
467
+ type: "boolean",
468
+ description: "Fetch from all configured remotes. Default: false.",
469
+ },
470
+ },
471
+ additionalProperties: false,
472
+ },
473
+ outputSchema: {
474
+ type: "object",
475
+ properties: {
476
+ fetched: { type: "boolean" },
477
+ nothingNew: { type: "boolean" },
478
+ output: { type: "string" },
479
+ },
480
+ required: ["fetched"],
481
+ },
482
+ },
483
+ handler: async (args, signal) => {
484
+ if (!(await checkGitRepo(workspace, signal))) {
485
+ return error("Not a git repository", "git_error");
486
+ }
487
+ const all = optionalBool(args, "all") ?? false;
488
+ const remote = optionalString(args, "remote", 256) ?? "origin";
489
+ if (!all && !isValidRef(remote)) {
490
+ return error(`Invalid remote name: "${remote}"`);
491
+ }
492
+ const fetchArgs = all ? ["fetch", "--all"] : ["fetch", remote];
493
+ let fetchStdout;
494
+ let fetchStderr;
495
+ try {
496
+ ({ stdout: fetchStdout, stderr: fetchStderr } = await runGit(fetchArgs, workspace, { signal, timeout: 60_000 }));
497
+ }
498
+ catch (e) {
499
+ const msg = e instanceof Error ? e.message : "unknown error";
500
+ if (msg.includes("Authentication") ||
501
+ msg.includes("credential") ||
502
+ msg.includes("Permission denied") ||
503
+ msg.includes("could not read Username")) {
504
+ return error(`Authentication failed. Check your git credentials.\n${msg}`);
505
+ }
506
+ if (msg.includes("does not appear") || msg.includes("not found")) {
507
+ return error(`Remote '${remote}' not found. Check configured remotes.`);
508
+ }
509
+ return error(`git fetch failed: ${msg}`);
510
+ }
511
+ // git fetch writes to stderr even on success; empty = nothing new
512
+ const output = fetchStderr.trim() || fetchStdout.trim();
513
+ return successStructured({ fetched: true, nothingNew: !output, output });
514
+ },
515
+ };
516
+ }
517
+ export function createGitListBranchesTool(workspace) {
518
+ return {
519
+ schema: {
520
+ name: "gitListBranches",
521
+ description: "List git branches. Returns local branches with the current branch marked. Pass includeRemote: true for remote-tracking branches.",
522
+ annotations: { readOnlyHint: true },
523
+ inputSchema: {
524
+ type: "object",
525
+ properties: {
526
+ includeRemote: {
527
+ type: "boolean",
528
+ description: "Include remote-tracking branches (e.g. origin/main). Default: false.",
529
+ },
530
+ },
531
+ additionalProperties: false,
532
+ },
533
+ outputSchema: {
534
+ type: "object",
535
+ properties: {
536
+ local: { type: "array" },
537
+ current: { type: "string" },
538
+ remote: { type: "array", items: { type: "string" } },
539
+ },
540
+ required: ["local", "current"],
541
+ },
542
+ },
543
+ handler: async (args, signal) => {
544
+ if (!(await checkGitRepo(workspace, signal))) {
545
+ return error("Not a git repository", "git_error");
546
+ }
547
+ const includeRemote = optionalBool(args, "includeRemote") ?? false;
548
+ let branchOutput;
549
+ try {
550
+ ({ stdout: branchOutput } = await runGit(["branch"], workspace, {
551
+ signal,
552
+ }));
553
+ }
554
+ catch (e) {
555
+ return error(`git branch failed: ${e instanceof Error ? e.message : "unknown error"}`);
556
+ }
557
+ const local = branchOutput
558
+ .split("\n")
559
+ .map((l) => l.trimEnd())
560
+ .filter(Boolean)
561
+ .map((l) => ({
562
+ name: l.startsWith("* ") ? l.slice(2) : l.trimStart(),
563
+ current: l.startsWith("* "),
564
+ }));
565
+ const current = local.find((b) => b.current)?.name ?? "";
566
+ const result = { local, current };
567
+ if (includeRemote) {
568
+ const remoteResult = await execSafe("git", ["branch", "-r"], {
569
+ cwd: workspace,
570
+ signal,
571
+ });
572
+ if (remoteResult.exitCode === 0) {
573
+ result.remote = remoteResult.stdout
574
+ .split("\n")
575
+ .map((l) => l.trim())
576
+ .filter(Boolean)
577
+ .filter((b) => !b.includes("HEAD ->"));
578
+ }
579
+ }
580
+ return successStructured(result);
581
+ },
582
+ };
583
+ }
584
+ export function createGitPullTool(workspace, onGitPull) {
585
+ return {
586
+ schema: {
587
+ name: "gitPull",
588
+ description: "Pull changes from a remote into the current branch. Defaults to origin with merge. Use rebase: true for linear history.",
589
+ annotations: { destructiveHint: true },
590
+ inputSchema: {
591
+ type: "object",
592
+ properties: {
593
+ remote: {
594
+ type: "string",
595
+ description: "Remote name (default: origin)",
596
+ },
597
+ branch: {
598
+ type: "string",
599
+ description: "Remote branch to pull from (default: tracking branch for current branch)",
600
+ },
601
+ rebase: {
602
+ type: "boolean",
603
+ description: "Rebase local commits on top of remote changes instead of merging. Default: false.",
604
+ },
605
+ },
606
+ additionalProperties: false,
607
+ },
608
+ outputSchema: {
609
+ type: "object",
610
+ properties: {
611
+ alreadyUpToDate: { type: "boolean" },
612
+ output: { type: "string" },
613
+ },
614
+ required: ["alreadyUpToDate"],
615
+ },
616
+ },
617
+ handler: async (args, signal) => {
618
+ if (!(await checkGitRepo(workspace, signal))) {
619
+ return error("Not a git repository", "git_error");
620
+ }
621
+ const remote = optionalString(args, "remote", 256) ?? "origin";
622
+ const branch = optionalString(args, "branch", 256);
623
+ const rebase = optionalBool(args, "rebase") ?? false;
624
+ if (!isValidRef(remote)) {
625
+ return error(`Invalid remote name: "${remote}"`);
626
+ }
627
+ if (branch !== undefined && !isValidRef(branch)) {
628
+ return error(`Invalid branch name: must match git ref rules (no spaces, no shell metacharacters)`);
629
+ }
630
+ const pullArgs = ["pull"];
631
+ if (rebase)
632
+ pullArgs.push("--rebase");
633
+ pullArgs.push(remote);
634
+ if (branch)
635
+ pullArgs.push(branch);
636
+ let pullOutput;
637
+ try {
638
+ ({ stdout: pullOutput } = await runGit(pullArgs, workspace, {
639
+ signal,
640
+ timeout: 60_000,
641
+ }));
642
+ }
643
+ catch (e) {
644
+ const msg = e instanceof Error ? e.message : "unknown error";
645
+ if (msg.includes("CONFLICT")) {
646
+ return error(`Merge conflict during pull. Resolve conflicts manually, then use gitAdd + gitCommit.\n${msg}`);
647
+ }
648
+ if (msg.includes("no tracking information") ||
649
+ msg.includes("has no upstream") ||
650
+ msg.includes("no upstream")) {
651
+ return error("No upstream branch configured for the current branch. Specify remote and branch explicitly.");
652
+ }
653
+ if (msg.includes("Authentication") ||
654
+ msg.includes("credential") ||
655
+ msg.includes("Permission denied") ||
656
+ msg.includes("could not read Username")) {
657
+ return error(`Authentication failed. Check your git credentials.\n${msg}`);
658
+ }
659
+ return error(`git pull failed: ${msg}`);
660
+ }
661
+ const alreadyUpToDate = pullOutput.includes("Already up to date") ||
662
+ pullOutput.includes("Already up-to-date");
663
+ const branchResult = await execSafe("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: workspace, signal });
664
+ const currentBranch = branchResult.stdout.trim() || branch || remote;
665
+ onGitPull?.({ remote, branch: currentBranch, alreadyUpToDate });
666
+ return successStructured({ alreadyUpToDate, output: pullOutput });
667
+ },
668
+ };
669
+ }
670
+ export function createGitPushTool(workspace, onGitPush) {
671
+ return {
672
+ // Override the global 60s MCP tool timeout — SSH pushes on high-latency
673
+ // VPS connections can take longer than 60s end-to-end.
674
+ timeoutMs: 180_000,
675
+ schema: {
676
+ name: "gitPush",
677
+ description: "Push the current branch to a remote. Use setUpstream: true on the first push. Force push uses --force-with-lease. Blocked on main/master.",
678
+ annotations: { destructiveHint: true },
679
+ inputSchema: {
680
+ type: "object",
681
+ properties: {
682
+ remote: {
683
+ type: "string",
684
+ description: "Remote name (default: origin)",
685
+ },
686
+ branch: {
687
+ type: "string",
688
+ description: "Branch to push (default: current branch)",
689
+ },
690
+ setUpstream: {
691
+ type: "boolean",
692
+ description: "Set the upstream tracking branch (-u). Use on first push of a new branch. Default: false.",
693
+ },
694
+ force: {
695
+ type: "boolean",
696
+ description: "Force push with --force-with-lease. Blocked on main/master. Default: false.",
697
+ },
698
+ },
699
+ additionalProperties: false,
700
+ },
701
+ outputSchema: {
702
+ type: "object",
703
+ properties: {
704
+ remote: { type: "string" },
705
+ branch: { type: "string" },
706
+ hash: { type: "string" },
707
+ setUpstream: { type: "boolean" },
708
+ output: { type: "string" },
709
+ },
710
+ required: ["remote", "branch", "hash"],
711
+ },
712
+ },
713
+ handler: async (args, signal) => {
714
+ if (!(await checkGitRepo(workspace, signal))) {
715
+ return error("Not a git repository", "git_error");
716
+ }
717
+ const remote = optionalString(args, "remote", 256) ?? "origin";
718
+ const branchArg = optionalString(args, "branch", 256);
719
+ const setUpstream = optionalBool(args, "setUpstream") ?? false;
720
+ const force = optionalBool(args, "force") ?? false;
721
+ if (!isValidRef(remote)) {
722
+ return error(`Invalid remote name: "${remote}"`);
723
+ }
724
+ if (branchArg !== undefined && !isValidRef(branchArg)) {
725
+ return error(`Invalid branch name: must match git ref rules (no spaces, no shell metacharacters)`);
726
+ }
727
+ const branch = branchArg ?? (await currentBranch(workspace, signal));
728
+ // Check force-push protection before anything else — this is a local safety
729
+ // guard that must fire regardless of whether the remote exists.
730
+ if (force && (branch === "main" || branch === "master")) {
731
+ return error(`Force push to '${branch}' is blocked. This would rewrite shared history on the main branch.`);
732
+ }
733
+ // Pre-flight: verify the remote exists before attempting the push so we
734
+ // surface a clear message instead of a raw git error.
735
+ const remoteCheck = await execSafe("git", ["remote", "get-url", remote], {
736
+ cwd: workspace,
737
+ signal,
738
+ });
739
+ if (remoteCheck.exitCode !== 0) {
740
+ const knownRemotes = (await execSafe("git", ["remote"], { cwd: workspace, signal })).stdout
741
+ .trim()
742
+ .split("\n")
743
+ .filter(Boolean);
744
+ const hint = knownRemotes.length > 0
745
+ ? ` Known remotes: ${knownRemotes.join(", ")}.`
746
+ : " No remotes are configured.";
747
+ return error(`Remote "${remote}" does not exist in this repository.${hint}`);
748
+ }
749
+ const pushArgs = ["push"];
750
+ if (force)
751
+ pushArgs.push("--force-with-lease");
752
+ if (setUpstream)
753
+ pushArgs.push("-u");
754
+ pushArgs.push(remote, branch);
755
+ let pushStdout;
756
+ let pushStderr;
757
+ try {
758
+ ({ stdout: pushStdout, stderr: pushStderr } = await runGit(pushArgs, workspace, {
759
+ signal,
760
+ // SSH pushes on high-latency VPS connections can exceed 60s;
761
+ // raise to 120s to avoid false-timeout failures.
762
+ timeout: 120_000,
763
+ // Inject SSH options: fast connect-timeout surfaces auth errors
764
+ // immediately instead of hanging; keepalive prevents silent TCP drops.
765
+ env: {
766
+ ...process.env,
767
+ GIT_SSH_COMMAND: "ssh -o ConnectTimeout=15 -o ServerAliveInterval=30 -o ServerAliveCountMax=6",
768
+ },
769
+ }));
770
+ }
771
+ catch (e) {
772
+ const msg = e instanceof Error ? e.message : "unknown error";
773
+ if (msg.includes("rejected") && msg.includes("non-fast-forward")) {
774
+ return error("Push rejected: remote has commits not present locally. Run gitPull to sync, then push again.");
775
+ }
776
+ if (msg.includes("rejected") &&
777
+ (msg.includes("stale") || msg.includes("force-with-lease"))) {
778
+ return error("Force push rejected: remote branch was updated since your last fetch. Run gitPull to sync first.");
779
+ }
780
+ if (msg.includes("has no upstream") ||
781
+ msg.includes("no upstream branch")) {
782
+ return error(`Branch '${branch}' has no upstream. Use setUpstream: true to set the tracking branch on first push.`);
783
+ }
784
+ if (msg.includes("Authentication") ||
785
+ msg.includes("credential") ||
786
+ msg.includes("Permission denied") ||
787
+ msg.includes("Repository not found") ||
788
+ msg.includes("could not read Username")) {
789
+ return error(`Authentication failed. Check your git credentials.\n${msg}`);
790
+ }
791
+ return error(`git push failed: ${msg}`);
792
+ }
793
+ const hashResult = await execSafe("git", ["rev-parse", "HEAD"], {
794
+ cwd: workspace,
795
+ signal,
796
+ });
797
+ const hash = hashResult.stdout.trim().slice(0, 12);
798
+ const pushResult = {
799
+ remote,
800
+ branch,
801
+ hash,
802
+ setUpstream,
803
+ output: pushStderr.trim() || pushStdout.trim(),
804
+ };
805
+ onGitPush?.({ remote, branch, hash });
806
+ return successStructured(pushResult);
807
+ },
808
+ };
809
+ }
810
+ export function createGitStashTool(workspace) {
811
+ return {
812
+ schema: {
813
+ name: "gitStash",
814
+ description: "Stash current changes to get a clean working tree. Required before switching branches with uncommitted changes. " +
815
+ "Use gitStashPop to restore. Pass includeUntracked: true to also stash new files.",
816
+ annotations: { destructiveHint: true },
817
+ inputSchema: {
818
+ type: "object",
819
+ properties: {
820
+ message: {
821
+ type: "string",
822
+ description: "Optional description for the stash entry",
823
+ },
824
+ includeUntracked: {
825
+ type: "boolean",
826
+ description: "Also stash untracked (new) files. Default: false.",
827
+ },
828
+ },
829
+ additionalProperties: false,
830
+ },
831
+ outputSchema: {
832
+ type: "object",
833
+ properties: {
834
+ stashed: { type: "boolean" },
835
+ stashRef: { type: "string" },
836
+ output: { type: "string" },
837
+ reason: { type: "string" },
838
+ },
839
+ required: ["stashed"],
840
+ },
841
+ },
842
+ handler: async (args, signal) => {
843
+ if (!(await checkGitRepo(workspace, signal))) {
844
+ return error("Not a git repository", "git_error");
845
+ }
846
+ const message = optionalString(args, "message", 256);
847
+ const includeUntracked = optionalBool(args, "includeUntracked") ?? false;
848
+ const stashArgs = ["stash", "push"];
849
+ if (includeUntracked)
850
+ stashArgs.push("-u");
851
+ if (message)
852
+ stashArgs.push("-m", message);
853
+ let stashStdout;
854
+ let stashStderr;
855
+ try {
856
+ ({ stdout: stashStdout, stderr: stashStderr } = await runGit(stashArgs, workspace, { signal, timeout: 15_000 }));
857
+ }
858
+ catch (e) {
859
+ return error(`git stash failed: ${e instanceof Error ? e.message : "unknown error"}`);
860
+ }
861
+ const output = stashStdout.trim() || stashStderr.trim();
862
+ if (output.includes("No local changes to save")) {
863
+ return successStructured({
864
+ stashed: false,
865
+ reason: "No local changes to save",
866
+ });
867
+ }
868
+ const listResult = await execSafe("git", ["stash", "list", "--max-count=1"], { cwd: workspace, signal });
869
+ const stashRef = listResult.stdout.trim().split(":")[0] ?? "stash@{0}";
870
+ return successStructured({ stashed: true, stashRef, output });
871
+ },
872
+ };
873
+ }
874
+ export function createGitStashPopTool(workspace) {
875
+ return {
876
+ schema: {
877
+ name: "gitStashPop",
878
+ description: "Restore stashed changes to the working tree. Pops the most recent stash by default, " +
879
+ "or a specific entry by index (from gitStashList).",
880
+ annotations: { destructiveHint: true },
881
+ inputSchema: {
882
+ type: "object",
883
+ properties: {
884
+ index: {
885
+ type: "integer",
886
+ description: "Stash entry index to pop (0 = most recent). Default: 0.",
887
+ },
888
+ },
889
+ additionalProperties: false,
890
+ },
891
+ outputSchema: {
892
+ type: "object",
893
+ properties: {
894
+ restored: { type: "boolean" },
895
+ stashRef: { type: "string" },
896
+ output: { type: "string" },
897
+ },
898
+ required: ["restored"],
899
+ },
900
+ },
901
+ handler: async (args, signal) => {
902
+ if (!(await checkGitRepo(workspace, signal))) {
903
+ return error("Not a git repository", "git_error");
904
+ }
905
+ const index = typeof args.index === "number"
906
+ ? Math.max(0, Math.floor(args.index))
907
+ : 0;
908
+ const stashRef = `stash@{${index}}`;
909
+ let popOutput;
910
+ try {
911
+ ({ stdout: popOutput } = await runGit(["stash", "pop", stashRef], workspace, { signal, timeout: 15_000 }));
912
+ }
913
+ catch (e) {
914
+ const msg = e instanceof Error ? e.message : "unknown error";
915
+ if (msg.includes("CONFLICT")) {
916
+ return error(`Merge conflict while applying stash. Resolve conflicts, then use gitAdd to mark them resolved.\n${msg}`);
917
+ }
918
+ if (msg.includes("No stash entries") ||
919
+ msg.includes("is not a valid reference")) {
920
+ return error(`No stash entry at index ${index}. Use gitStashList to see available entries.`);
921
+ }
922
+ return error(`git stash pop failed: ${msg}`);
923
+ }
924
+ return successStructured({
925
+ restored: true,
926
+ stashRef,
927
+ output: popOutput.trim(),
928
+ });
929
+ },
930
+ };
931
+ }
932
+ export function createGitStashListTool(workspace) {
933
+ return {
934
+ schema: {
935
+ name: "gitStashList",
936
+ description: "List all stash entries in the repository. " +
937
+ "Returns each entry's index, branch it was stashed from, message, and age. " +
938
+ "Use before gitStashPop to identify the right entry to restore.",
939
+ annotations: { readOnlyHint: true },
940
+ inputSchema: {
941
+ type: "object",
942
+ properties: {},
943
+ additionalProperties: false,
944
+ },
945
+ outputSchema: {
946
+ type: "object",
947
+ properties: {
948
+ entries: { type: "array" },
949
+ count: { type: "integer" },
950
+ },
951
+ required: ["entries", "count"],
952
+ },
953
+ },
954
+ handler: async (_args, signal) => {
955
+ if (!(await checkGitRepo(workspace, signal))) {
956
+ return error("Not a git repository", "git_error");
957
+ }
958
+ let listOutput;
959
+ try {
960
+ ({ stdout: listOutput } = await runGit(["stash", "list", "--format=%gd|%gs|%cr"], workspace, { signal }));
961
+ }
962
+ catch (e) {
963
+ return error(`git stash list failed: ${e instanceof Error ? e.message : "unknown error"}`);
964
+ }
965
+ const entries = listOutput
966
+ .split("\n")
967
+ .map((l) => l.trim())
968
+ .filter(Boolean)
969
+ .map((l) => {
970
+ const [ref, subject, age] = l.split("|");
971
+ const index = Number.parseInt(ref?.match(/\{(\d+)\}/)?.[1] ?? "0", 10);
972
+ return {
973
+ index,
974
+ ref: ref ?? "",
975
+ subject: subject ?? "",
976
+ age: age ?? "",
977
+ };
978
+ });
979
+ return successStructured({ entries, count: entries.length });
980
+ },
981
+ };
982
+ }
983
+ //# sourceMappingURL=gitWrite.js.map