internaltool-mcp 1.6.9 → 1.6.10
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.
- package/index.js +36 -10
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
19
19
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
20
20
|
import { execSync } from 'child_process'
|
|
21
|
-
import { mkdirSync, writeFileSync, unlinkSync, existsSync } from 'fs'
|
|
21
|
+
import { mkdirSync, writeFileSync, unlinkSync, existsSync, readdirSync, statSync } from 'fs'
|
|
22
22
|
import { join } from 'path'
|
|
23
23
|
import { z } from 'zod'
|
|
24
24
|
import { api, login, configure } from './api-client.js'
|
|
@@ -848,8 +848,9 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
|
|
|
848
848
|
{
|
|
849
849
|
taskId: z.string().describe("Task's MongoDB ObjectId"),
|
|
850
850
|
confirmed: z.boolean().optional().default(false).describe('Set true after reading the plan to move the task to in_progress'),
|
|
851
|
+
repoPath: z.string().optional().describe('Absolute path to the local git repo (defaults to MCP process working directory). Used to write cursor rules file.'),
|
|
851
852
|
},
|
|
852
|
-
async ({ taskId, confirmed = false }) => {
|
|
853
|
+
async ({ taskId, confirmed = false, repoPath }) => {
|
|
853
854
|
const taskRes = await api.get(`/api/tasks/${taskId}`)
|
|
854
855
|
if (!taskRes?.success) return errorText('Task not found')
|
|
855
856
|
const task = taskRes.data.task
|
|
@@ -963,7 +964,7 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
|
|
|
963
964
|
// Write cursor rules file to local repo immediately on kickoff
|
|
964
965
|
let cursorRulesFile = null
|
|
965
966
|
if (hasCursorRules) {
|
|
966
|
-
cursorRulesFile = writeCursorRulesFile(task.key, task.cursorRules)
|
|
967
|
+
cursorRulesFile = writeCursorRulesFile(task.key, task.cursorRules, repoPath)
|
|
967
968
|
}
|
|
968
969
|
|
|
969
970
|
return text({
|
|
@@ -1238,10 +1239,33 @@ function runGit(args, cwd) {
|
|
|
1238
1239
|
}).trim()
|
|
1239
1240
|
}
|
|
1240
1241
|
|
|
1242
|
+
/**
|
|
1243
|
+
* Find the root of the git repo starting from `startPath`.
|
|
1244
|
+
* If `startPath` itself is not a git repo, scan one level of subdirectories.
|
|
1245
|
+
* Returns the repo root string or null.
|
|
1246
|
+
*/
|
|
1247
|
+
function findRepoRoot(startPath) {
|
|
1248
|
+
const base = startPath || process.cwd()
|
|
1249
|
+
try {
|
|
1250
|
+
return runGit('rev-parse --show-toplevel', base)
|
|
1251
|
+
} catch { /* not a git repo — try subdirectories */ }
|
|
1252
|
+
try {
|
|
1253
|
+
const entries = readdirSync(base, { withFileTypes: true })
|
|
1254
|
+
for (const entry of entries) {
|
|
1255
|
+
if (!entry.isDirectory()) continue
|
|
1256
|
+
try {
|
|
1257
|
+
return runGit('rev-parse --show-toplevel', join(base, entry.name))
|
|
1258
|
+
} catch { /* not a git repo */ }
|
|
1259
|
+
}
|
|
1260
|
+
} catch { /* can't read dir */ }
|
|
1261
|
+
return null
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1241
1264
|
/** Write task-specific cursor rules to .cursor/rules/<taskKey>.mdc in the local repo root. */
|
|
1242
|
-
function writeCursorRulesFile(taskKey, rulesMarkdown) {
|
|
1265
|
+
function writeCursorRulesFile(taskKey, rulesMarkdown, startPath) {
|
|
1243
1266
|
try {
|
|
1244
|
-
const repoRoot =
|
|
1267
|
+
const repoRoot = findRepoRoot(startPath)
|
|
1268
|
+
if (!repoRoot) return null
|
|
1245
1269
|
const rulesDir = join(repoRoot, '.cursor', 'rules')
|
|
1246
1270
|
mkdirSync(rulesDir, { recursive: true })
|
|
1247
1271
|
const filePath = join(rulesDir, `${taskKey.toLowerCase()}.mdc`)
|
|
@@ -1254,9 +1278,10 @@ function writeCursorRulesFile(taskKey, rulesMarkdown) {
|
|
|
1254
1278
|
}
|
|
1255
1279
|
|
|
1256
1280
|
/** Delete the task-specific cursor rules file when work is complete. */
|
|
1257
|
-
function deleteCursorRulesFile(taskKey) {
|
|
1281
|
+
function deleteCursorRulesFile(taskKey, startPath) {
|
|
1258
1282
|
try {
|
|
1259
|
-
const repoRoot =
|
|
1283
|
+
const repoRoot = findRepoRoot(startPath)
|
|
1284
|
+
if (!repoRoot) return null
|
|
1260
1285
|
const filePath = join(repoRoot, '.cursor', 'rules', `${taskKey.toLowerCase()}.mdc`)
|
|
1261
1286
|
if (existsSync(filePath)) {
|
|
1262
1287
|
unlinkSync(filePath)
|
|
@@ -1690,7 +1715,7 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
|
|
|
1690
1715
|
const freshTaskForRules = await api.get(`/api/tasks/${taskId}`).catch(() => null)
|
|
1691
1716
|
const cursorRulesContent = freshTaskForRules?.data?.task?.cursorRules
|
|
1692
1717
|
if (cursorRulesContent?.trim()) {
|
|
1693
|
-
cursorRulesFile = writeCursorRulesFile(freshTaskForRules.data.task.key, cursorRulesContent)
|
|
1718
|
+
cursorRulesFile = writeCursorRulesFile(freshTaskForRules.data.task.key, cursorRulesContent, cwd)
|
|
1694
1719
|
}
|
|
1695
1720
|
|
|
1696
1721
|
const checkoutSteps = [
|
|
@@ -1977,8 +2002,9 @@ Set confirmed=false first to preview the full PR content, then confirmed=true to
|
|
|
1977
2002
|
additionalNotes: z.string().optional().describe('Extra context to add to the PR body'),
|
|
1978
2003
|
draft: z.boolean().optional().default(false).describe('Open as a draft PR (not yet ready for review)'),
|
|
1979
2004
|
confirmed: z.boolean().optional().default(false).describe('Set true to create the PR after reviewing the preview'),
|
|
2005
|
+
repoPath: z.string().optional().describe('Absolute path to the local git repo (defaults to MCP process working directory). Used to delete cursor rules file.'),
|
|
1980
2006
|
},
|
|
1981
|
-
async ({ taskId, projectId, headBranch, additionalNotes = '', draft = false, confirmed = false }) => {
|
|
2007
|
+
async ({ taskId, projectId, headBranch, additionalNotes = '', draft = false, confirmed = false, repoPath }) => {
|
|
1982
2008
|
if (scopedProjectId && projectId !== scopedProjectId) {
|
|
1983
2009
|
return errorText(`Access denied: session is scoped to project ${scopedProjectId}`)
|
|
1984
2010
|
}
|
|
@@ -2026,7 +2052,7 @@ Set confirmed=false first to preview the full PR content, then confirmed=true to
|
|
|
2026
2052
|
if (!res?.success) return errorText(res?.message || 'Could not create PR')
|
|
2027
2053
|
|
|
2028
2054
|
// Delete the task-specific cursor rules file — coding is done
|
|
2029
|
-
const deletedRulesFile = deleteCursorRulesFile(task.key)
|
|
2055
|
+
const deletedRulesFile = deleteCursorRulesFile(task.key, repoPath)
|
|
2030
2056
|
|
|
2031
2057
|
return text({
|
|
2032
2058
|
prNumber: res.data.prNumber,
|
package/package.json
CHANGED