internaltool-mcp 1.6.2 → 1.6.4
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 +117 -14
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -861,6 +861,39 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
|
|
|
861
861
|
const subtasksTotal = subtasks.length
|
|
862
862
|
|
|
863
863
|
// ── Preview: show the full plan before touching anything ──
|
|
864
|
+
const approvalState = task.approval?.state || 'none'
|
|
865
|
+
const approvalBlocks = ['backlog', 'todo'].includes(task.column) && approvalState !== 'approved'
|
|
866
|
+
|
|
867
|
+
// Build the next-step roadmap so developer knows exactly what comes after reading the plan
|
|
868
|
+
let workflowRoadmap
|
|
869
|
+
if (!hasReadme) {
|
|
870
|
+
workflowRoadmap = [
|
|
871
|
+
`1. Write the implementation plan — click "Start writing" on the Plan tab`,
|
|
872
|
+
`2. Call submit_task_for_approval to send it for review`,
|
|
873
|
+
`3. After approval, call create_branch — the task moves to In progress automatically`,
|
|
874
|
+
]
|
|
875
|
+
} else if (approvalState === 'none') {
|
|
876
|
+
workflowRoadmap = [
|
|
877
|
+
`1. ✅ Implementation plan is written — read it above`,
|
|
878
|
+
`2. Call submit_task_for_approval with taskId="${taskId}" to send it for review`,
|
|
879
|
+
`3. After approval, call create_branch — the task moves to In progress automatically`,
|
|
880
|
+
]
|
|
881
|
+
} else if (approvalState === 'pending') {
|
|
882
|
+
workflowRoadmap = [
|
|
883
|
+
`1. ✅ Implementation plan written`,
|
|
884
|
+
`2. ⏳ Waiting for reviewer approval`,
|
|
885
|
+
`3. After approval, call create_branch — the task moves to In progress automatically`,
|
|
886
|
+
]
|
|
887
|
+
} else {
|
|
888
|
+
// approved
|
|
889
|
+
workflowRoadmap = [
|
|
890
|
+
`1. ✅ Implementation plan written and approved`,
|
|
891
|
+
`2. Call create_branch with taskId="${taskId}" — moves task to In progress automatically`,
|
|
892
|
+
`3. Code → commit (use commit_helper) → push`,
|
|
893
|
+
`4. Call raise_pr — task moves to In review automatically`,
|
|
894
|
+
]
|
|
895
|
+
}
|
|
896
|
+
|
|
864
897
|
if (!confirmed) {
|
|
865
898
|
return text({
|
|
866
899
|
brief: {
|
|
@@ -868,24 +901,28 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
|
|
|
868
901
|
title: task.title,
|
|
869
902
|
priority: task.priority,
|
|
870
903
|
description: task.description || '(no description)',
|
|
871
|
-
// The implementation plan — Claude must read and present this to the developer
|
|
872
904
|
implementationPlan: hasReadme
|
|
873
905
|
? task.readmeMarkdown
|
|
874
|
-
: '⚠️ No implementation plan
|
|
906
|
+
: '⚠️ No implementation plan found. Write one in the Plan tab before starting work.',
|
|
875
907
|
subtasks: subtasksTotal > 0
|
|
876
908
|
? { items: subtasks, progress: `${subtasksDone}/${subtasksTotal} done` }
|
|
877
909
|
: null,
|
|
878
|
-
approvalState
|
|
910
|
+
approvalState,
|
|
879
911
|
},
|
|
880
912
|
meta: {
|
|
881
913
|
currentColumn: task.column,
|
|
882
|
-
willMoveTo: 'in_progress',
|
|
883
914
|
suggestedBranch,
|
|
884
915
|
},
|
|
916
|
+
workflowRoadmap,
|
|
917
|
+
approvalWarning: approvalBlocks
|
|
918
|
+
? approvalState === 'pending'
|
|
919
|
+
? `⏳ Plan is submitted and awaiting approval — you cannot create a branch until it is approved.`
|
|
920
|
+
: `⚠️ Plan is not yet submitted for approval. Submit it first, then create the branch.`
|
|
921
|
+
: null,
|
|
885
922
|
requiresConfirmation: true,
|
|
886
|
-
message:
|
|
887
|
-
? `Read the
|
|
888
|
-
:
|
|
923
|
+
message: approvalBlocks
|
|
924
|
+
? `Read the plan above, then follow workflowRoadmap — approval is required before you can branch and start coding.`
|
|
925
|
+
: `Read the implementation plan above carefully, then call kickoff_task again with confirmed=true.`,
|
|
889
926
|
})
|
|
890
927
|
}
|
|
891
928
|
|
|
@@ -1443,6 +1480,34 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
|
|
|
1443
1480
|
if (!taskRes?.success) return errorText('Task not found')
|
|
1444
1481
|
const task = taskRes.data.task
|
|
1445
1482
|
|
|
1483
|
+
// ── Approval gate check ───────────────────────────────────────────────────
|
|
1484
|
+
// The server blocks non-admins from moving todo → in_progress without approval.
|
|
1485
|
+
// Detect this early and guide the developer instead of failing silently after branch creation.
|
|
1486
|
+
const approvalState = task.approval?.state || 'none'
|
|
1487
|
+
const PLANNING_COLS = ['backlog', 'todo']
|
|
1488
|
+
const needsApproval = PLANNING_COLS.includes(task.column) && approvalState !== 'approved'
|
|
1489
|
+
if (needsApproval && !confirmed) {
|
|
1490
|
+
const isFix2 = /\b(fix|bug|hotfix|patch)\b/i.test(task.title + ' ' + (task.description || ''))
|
|
1491
|
+
const slug2 = task.title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 35)
|
|
1492
|
+
const previewBranch = `${isFix2 ? 'fix' : 'feature'}/${task.key.toLowerCase()}-${slug2}`
|
|
1493
|
+
return text({
|
|
1494
|
+
blocked: true,
|
|
1495
|
+
reason: 'approval_required',
|
|
1496
|
+
task: { key: task.key, title: task.title, column: task.column, approvalState },
|
|
1497
|
+
message: `The task's implementation plan (README) must be approved before creating a branch and moving to In progress.`,
|
|
1498
|
+
approvalStatus: approvalState === 'pending'
|
|
1499
|
+
? `Plan is already submitted and waiting for reviewer approval. Once approved, call create_branch again.`
|
|
1500
|
+
: `Plan has not been submitted for review yet.`,
|
|
1501
|
+
nextSteps: approvalState === 'pending'
|
|
1502
|
+
? [`Wait for the reviewer to approve, then call create_branch with taskId="${taskId}"`]
|
|
1503
|
+
: [
|
|
1504
|
+
`1. Make sure the README / implementation plan is written on the task (use update_task with readmeMarkdown if needed)`,
|
|
1505
|
+
`2. Call submit_task_for_approval with taskId="${taskId}" and the reviewerId of your project lead`,
|
|
1506
|
+
`3. Once approved, call create_branch again — it will create "${previewBranch}" and move the task to In progress automatically`,
|
|
1507
|
+
],
|
|
1508
|
+
})
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1446
1511
|
const isFix = /\b(fix|bug|hotfix|patch)\b/i.test(task.title + ' ' + (task.description || ''))
|
|
1447
1512
|
const prefix = isFix ? 'fix' : 'feature'
|
|
1448
1513
|
const slug = task.title
|
|
@@ -1527,18 +1592,31 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
|
|
|
1527
1592
|
})
|
|
1528
1593
|
}
|
|
1529
1594
|
|
|
1530
|
-
// Step 3 — create branch on GitHub, then link
|
|
1595
|
+
// Step 3 — create branch on GitHub (or confirm it already exists), then link + move
|
|
1531
1596
|
const localState = gitState?.localState || 'unknown'
|
|
1532
1597
|
try {
|
|
1598
|
+
let branchUrl = null
|
|
1599
|
+
let alreadyExisted = false
|
|
1600
|
+
|
|
1533
1601
|
const res = await api.post(`/api/projects/${projectId}/github/branches`, { branchName, fromRef })
|
|
1534
|
-
if (!res?.success)
|
|
1602
|
+
if (!res?.success) {
|
|
1603
|
+
// "Reference already exists" means the branch is already on GitHub — treat as success
|
|
1604
|
+
const msg = (res?.message || '').toLowerCase()
|
|
1605
|
+
if (msg.includes('already exists') || msg.includes('reference already exists')) {
|
|
1606
|
+
alreadyExisted = true
|
|
1607
|
+
} else {
|
|
1608
|
+
return errorText(res?.message || 'Could not create branch')
|
|
1609
|
+
}
|
|
1610
|
+
} else {
|
|
1611
|
+
branchUrl = res.data?.url || null
|
|
1612
|
+
}
|
|
1535
1613
|
|
|
1536
|
-
// Link
|
|
1614
|
+
// Link branch to task regardless of whether it was just created or already existed
|
|
1537
1615
|
try {
|
|
1538
1616
|
await api.patch(`/api/tasks/${taskId}/github/branch`, { headBranch: branchName })
|
|
1539
|
-
} catch { /* non-fatal
|
|
1617
|
+
} catch { /* non-fatal */ }
|
|
1540
1618
|
|
|
1541
|
-
// Move task to in_progress now that
|
|
1619
|
+
// Move task to in_progress now that branch is linked
|
|
1542
1620
|
let movedToInProgress = false
|
|
1543
1621
|
try {
|
|
1544
1622
|
const freshTask = await api.get(`/api/tasks/${taskId}`)
|
|
@@ -1562,17 +1640,42 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
|
|
|
1562
1640
|
unknown: null,
|
|
1563
1641
|
}[localState] || null
|
|
1564
1642
|
|
|
1643
|
+
const statusMsg = alreadyExisted
|
|
1644
|
+
? `Branch "${branchName}" already existed on GitHub — linked to task.${movedToInProgress ? ' Task moved to In progress.' : ''}`
|
|
1645
|
+
: `Branch "${branchName}" created on GitHub.${movedToInProgress ? ' Task moved to In progress.' : ''}`
|
|
1646
|
+
|
|
1565
1647
|
return text({
|
|
1566
1648
|
branchName,
|
|
1567
|
-
url:
|
|
1649
|
+
url: branchUrl,
|
|
1650
|
+
alreadyExisted,
|
|
1568
1651
|
localState,
|
|
1569
1652
|
movedToInProgress,
|
|
1570
|
-
message:
|
|
1653
|
+
message: statusMsg,
|
|
1571
1654
|
gitSteps: checkoutSteps,
|
|
1572
1655
|
localStateNote,
|
|
1573
1656
|
nextStep: 'Run the git steps above to switch locally, then start coding. When commits are pushed, use raise_pr.',
|
|
1574
1657
|
})
|
|
1575
1658
|
} catch (e) {
|
|
1659
|
+
// Last-resort catch: if error message indicates branch already exists, still link + move
|
|
1660
|
+
const msg = (e.message || '').toLowerCase()
|
|
1661
|
+
if (msg.includes('already exists') || msg.includes('reference already exists')) {
|
|
1662
|
+
try { await api.patch(`/api/tasks/${taskId}/github/branch`, { headBranch: branchName }) } catch { /* ok */ }
|
|
1663
|
+
try {
|
|
1664
|
+
const freshTask = await api.get(`/api/tasks/${taskId}`)
|
|
1665
|
+
const col = freshTask?.data?.task?.column
|
|
1666
|
+
if (col && ['todo', 'backlog'].includes(col)) {
|
|
1667
|
+
await api.post(`/api/tasks/${taskId}/move`, { column: 'in_progress', toIndex: 0 })
|
|
1668
|
+
}
|
|
1669
|
+
} catch { /* ok */ }
|
|
1670
|
+
return text({
|
|
1671
|
+
branchName,
|
|
1672
|
+
alreadyExisted: true,
|
|
1673
|
+
movedToInProgress: true,
|
|
1674
|
+
message: `Branch "${branchName}" already existed on GitHub — linked to task and moved to In progress.`,
|
|
1675
|
+
gitSteps: ['git fetch origin', `git checkout ${branchName}`],
|
|
1676
|
+
nextStep: 'Run the git steps above to switch locally, then start coding.',
|
|
1677
|
+
})
|
|
1678
|
+
}
|
|
1576
1679
|
return errorText(e.message)
|
|
1577
1680
|
}
|
|
1578
1681
|
}
|
package/package.json
CHANGED