internaltool-mcp 1.5.2 → 1.5.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.
Files changed (2) hide show
  1. package/index.js +74 -24
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -541,7 +541,12 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
541
541
  })),
542
542
  movedToInProgress: moved,
543
543
  suggestedBranch,
544
- nextStep: `Use create_branch to create "${suggestedBranch}" on GitHub, then run:\n git fetch origin\n git checkout ${suggestedBranch}`,
544
+ preflightBeforeBranch: {
545
+ message: 'Before creating the branch, check your local git state first.',
546
+ commands: ['git status', 'git stash list'],
547
+ instruction: 'If you have uncommitted changes, stash or commit them before switching branches. Then call create_branch with your localState.',
548
+ },
549
+ nextStep: `Use create_branch to create "${suggestedBranch}" on GitHub — it will ask for your local git state first.`,
545
550
  })
546
551
  }
547
552
  )
@@ -847,7 +852,7 @@ Use this when returning to a task after a break, or when Claude needs the full p
847
852
 
848
853
  let coachingPrompt = null
849
854
  if (task.column === 'in_progress' && !task.github?.headBranch) {
850
- coachingPrompt = 'No branch created yet. Use create_branch before writing code.'
855
+ coachingPrompt = 'No branch yet. Before create_branch: run "git status" in your terminal first — stash or commit any local changes, then call create_branch with your localState.'
851
856
  } else if (task.column === 'in_progress' && task.github?.headBranch) {
852
857
  coachingPrompt = `Branch: ${task.github.headBranch}. When commits are pushed, use raise_pr to open a PR.`
853
858
  } else if (task.column === 'in_review') {
@@ -885,19 +890,28 @@ Use this when returning to a task after a break, or when Claude needs the full p
885
890
  fix/TASK-XXX-short-description (for bug fixes / patches)
886
891
 
887
892
  WHEN TO USE: Immediately after a task moves to in_progress.
888
- Claude will suggest this automatically after kickoff_task.
889
893
 
890
- Set confirmed=false first to preview the branch name, then confirmed=true to create it.
891
- After creation, run locally:
892
- git fetch origin
893
- git checkout <branchName>`,
894
+ THREE-STEP FLOW do not skip steps:
895
+ 1. confirmed=false → preview branch name + get pre-flight git commands to run locally
896
+ 2. Run the pre-flight commands → check local state, stash if needed, report back with localState
897
+ 3. confirmed=true + localState → branch is created on GitHub
898
+
899
+ localState must be one of:
900
+ "clean" — git status shows nothing to commit, working tree clean
901
+ "stashed" — had changes, ran git stash, now clean
902
+ "committed" — had changes, did a WIP commit, now clean
903
+
904
+ Never skip the localState check — switching branches with uncommitted changes
905
+ can cause conflicts or silently carry changes onto the new branch.`,
894
906
  {
895
- taskId: z.string().describe("Task's MongoDB ObjectId"),
896
- projectId: z.string().describe("Project's MongoDB ObjectId"),
897
- fromRef: z.string().optional().describe("Base ref to branch from (default: project's default branch)"),
898
- confirmed: z.boolean().optional().default(false).describe('Set true to create the branch after reviewing the preview'),
907
+ taskId: z.string().describe("Task's MongoDB ObjectId"),
908
+ projectId: z.string().describe("Project's MongoDB ObjectId"),
909
+ fromRef: z.string().optional().describe("Base ref to branch from (default: project's default branch)"),
910
+ confirmed: z.boolean().optional().default(false).describe('Set true only after running pre-flight commands and setting localState'),
911
+ localState: z.enum(['clean', 'untracked', 'stashed', 'committed']).optional()
912
+ .describe('Your local git state after running git status. Required when confirmed=true. Use "untracked" if git status shows only untracked files with no modified tracked files.'),
899
913
  },
900
- async ({ taskId, projectId, fromRef, confirmed = false }) => {
914
+ async ({ taskId, projectId, fromRef, confirmed = false, localState }) => {
901
915
  if (scopedProjectId && projectId !== scopedProjectId) {
902
916
  return errorText(`Access denied: session is scoped to project ${scopedProjectId}`)
903
917
  }
@@ -915,33 +929,69 @@ After creation, run locally:
915
929
  .slice(0, 35)
916
930
  const branchName = `${prefix}/${task.key.toLowerCase()}-${slug}`
917
931
 
918
- // Preview
932
+ // Step 1 — preview + pre-flight commands
919
933
  if (!confirmed) {
920
934
  return text({
921
935
  preview: {
922
936
  action: 'create_branch',
923
937
  branchName,
924
- fromRef: fromRef || '(project default branch)',
925
- repo: '(resolved from project)',
938
+ basedOn: fromRef || '(project default branch)',
926
939
  task: { key: task.key, title: task.title },
927
940
  },
928
- requiresConfirmation: true,
929
- message: `Will create branch "${branchName}" on GitHub. Call create_branch again with confirmed=true to proceed.`,
941
+ preflightRequired: true,
942
+ preflightCommands: [
943
+ 'git status',
944
+ 'git stash list',
945
+ 'git diff --stat',
946
+ ],
947
+ preflightInstructions: [
948
+ 'Run the three commands above in your terminal right now.',
949
+ 'Read your git status output and pick the matching localState:',
950
+ ' "clean" — "nothing to commit, working tree clean"',
951
+ ' "untracked" — only untracked files listed, no modified tracked files. Safe to proceed — untracked files stay in place when you switch branches, they do NOT follow you.',
952
+ ' "stashed" — you had modified tracked files; run: git stash push -m "wip: switching to ' + branchName + '" — then set this.',
953
+ ' "committed" — you had changes; run: git add . && git commit -m "chore: wip" — then set this.',
954
+ ],
955
+ message: `Run the pre-flight commands above, read the output, then call create_branch again with confirmed=true and localState set to one of: clean | untracked | stashed | committed.`,
930
956
  })
931
957
  }
932
958
 
959
+ // Step 2 — localState gate: block if developer skipped the check
960
+ if (!localState) {
961
+ return text({
962
+ blocked: true,
963
+ reason: 'localState is required when confirmed=true.',
964
+ message: 'You must run "git status" first and tell me your local state. Set localState to "clean", "stashed", or "committed" depending on what you found.',
965
+ preflightCommands: ['git status', 'git stash list'],
966
+ })
967
+ }
968
+
969
+ // Step 3 — create branch on GitHub
933
970
  try {
934
971
  const res = await api.post(`/api/projects/${projectId}/github/branches`, { branchName, fromRef })
935
972
  if (!res?.success) return errorText(res?.message || 'Could not create branch')
973
+
974
+ const checkoutSteps = [
975
+ 'git fetch origin',
976
+ `git checkout ${branchName}`,
977
+ ]
978
+
979
+ // State-specific notes
980
+ const localStateNote = {
981
+ clean: null,
982
+ untracked: 'Your untracked files (.cursor/, docs, etc.) will stay in your working directory after checkout — they are not tracked by git so they do not follow branches. They will not appear in commits on the new branch unless you explicitly git add them.',
983
+ stashed: 'You stashed changes before switching. After checkout, decide: does your stash belong on this new branch? If yes: git stash pop. If it belongs to a different branch, leave it and pop it there later.',
984
+ committed: 'You made a WIP commit before switching. That commit stays on the branch you were on — it will not appear on the new branch.',
985
+ }[localState] || null
986
+
936
987
  return text({
937
988
  branchName,
938
- url: res.data.url,
939
- message: 'Branch created on GitHub.',
940
- gitSteps: [
941
- 'git fetch origin',
942
- `git checkout ${branchName}`,
943
- ],
944
- nextStep: 'Start coding! When your commits are ready to review, use raise_pr to open a pull request.',
989
+ url: res.data.url,
990
+ localState,
991
+ message: `Branch "${branchName}" created on GitHub.`,
992
+ gitSteps: checkoutSteps,
993
+ localStateNote,
994
+ nextStep: 'Run the git steps above to switch locally, then start coding. When commits are pushed, use raise_pr.',
945
995
  })
946
996
  } catch (e) {
947
997
  return errorText(e.message)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "internaltool-mcp",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "MCP server for InternalTool — connect AI assistants (Claude Code, Cursor) to your project and task management platform",
5
5
  "type": "module",
6
6
  "main": "index.js",