maxsimcli 4.8.0 → 4.10.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 (162) hide show
  1. package/README.md +180 -202
  2. package/dist/assets/CHANGELOG.md +61 -0
  3. package/dist/assets/hooks/maxsim-check-update.cjs +38 -0
  4. package/dist/assets/hooks/maxsim-check-update.cjs.map +1 -1
  5. package/dist/assets/hooks/maxsim-statusline.cjs +116 -48
  6. package/dist/assets/hooks/maxsim-statusline.cjs.map +1 -1
  7. package/dist/assets/hooks/maxsim-sync-reminder.cjs +117 -0
  8. package/dist/assets/hooks/maxsim-sync-reminder.cjs.map +1 -0
  9. package/dist/assets/templates/agents/AGENTS.md +78 -106
  10. package/dist/assets/templates/agents/executor.md +101 -0
  11. package/dist/assets/templates/agents/planner.md +86 -0
  12. package/dist/assets/templates/agents/researcher.md +71 -0
  13. package/dist/assets/templates/agents/verifier.md +88 -0
  14. package/dist/assets/templates/commands/maxsim/debug.md +7 -7
  15. package/dist/assets/templates/commands/maxsim/execute.md +45 -0
  16. package/dist/assets/templates/commands/maxsim/go.md +29 -0
  17. package/dist/assets/templates/commands/maxsim/help.md +2 -2
  18. package/dist/assets/templates/commands/maxsim/init.md +52 -0
  19. package/dist/assets/templates/commands/maxsim/plan.md +50 -0
  20. package/dist/assets/templates/commands/maxsim/progress.md +4 -3
  21. package/dist/assets/templates/commands/maxsim/quick.md +6 -4
  22. package/dist/assets/templates/commands/maxsim/settings.md +4 -3
  23. package/dist/assets/templates/references/continuation-format.md +16 -16
  24. package/dist/assets/templates/references/model-profile-resolution.md +1 -1
  25. package/dist/assets/templates/references/model-profiles.md +12 -19
  26. package/dist/assets/templates/rules/conventions.md +51 -0
  27. package/dist/assets/templates/rules/verification-protocol.md +57 -0
  28. package/dist/assets/templates/skills/agent-system-map/SKILL.md +92 -0
  29. package/dist/assets/templates/skills/brainstorming/SKILL.md +48 -36
  30. package/dist/assets/templates/skills/code-review/SKILL.md +40 -61
  31. package/dist/assets/templates/skills/commit-conventions/SKILL.md +75 -0
  32. package/dist/assets/templates/skills/evidence-collection/SKILL.md +87 -0
  33. package/dist/assets/templates/skills/handoff-contract/SKILL.md +70 -0
  34. package/dist/assets/templates/skills/input-validation/SKILL.md +51 -0
  35. package/dist/assets/templates/skills/maxsim-batch/SKILL.md +41 -45
  36. package/dist/assets/templates/skills/maxsim-simplify/SKILL.md +37 -90
  37. package/dist/assets/templates/skills/memory-management/SKILL.md +32 -67
  38. package/dist/assets/templates/skills/research-methodology/SKILL.md +137 -0
  39. package/dist/assets/templates/skills/roadmap-writing/SKILL.md +40 -58
  40. package/dist/assets/templates/skills/sdd/SKILL.md +34 -69
  41. package/dist/assets/templates/skills/systematic-debugging/SKILL.md +20 -26
  42. package/dist/assets/templates/skills/tdd/SKILL.md +25 -33
  43. package/dist/assets/templates/skills/tool-priority-guide/SKILL.md +80 -0
  44. package/dist/assets/templates/skills/using-maxsim/SKILL.md +42 -73
  45. package/dist/assets/templates/skills/verification-before-completion/SKILL.md +12 -24
  46. package/dist/assets/templates/skills/verification-gates/SKILL.md +169 -0
  47. package/dist/assets/templates/templates/UAT.md +3 -3
  48. package/dist/assets/templates/templates/VALIDATION.md +1 -1
  49. package/dist/assets/templates/templates/context.md +4 -4
  50. package/dist/assets/templates/templates/debug-subagent-prompt.md +3 -3
  51. package/dist/assets/templates/templates/discovery.md +2 -2
  52. package/dist/assets/templates/templates/phase-prompt.md +2 -2
  53. package/dist/assets/templates/templates/planner-subagent-prompt.md +7 -7
  54. package/dist/assets/templates/templates/project.md +1 -1
  55. package/dist/assets/templates/templates/research.md +1 -1
  56. package/dist/assets/templates/templates/state.md +2 -2
  57. package/dist/assets/templates/templates/summary.md +41 -0
  58. package/dist/assets/templates/workflows/batch.md +5 -5
  59. package/dist/assets/templates/workflows/diagnose-issues.md +2 -2
  60. package/dist/assets/templates/workflows/discovery-phase.md +3 -3
  61. package/dist/assets/templates/workflows/discuss-phase.md +11 -11
  62. package/dist/assets/templates/workflows/execute-phase.md +205 -11
  63. package/dist/assets/templates/workflows/execute-plan.md +299 -34
  64. package/dist/assets/templates/workflows/execute.md +421 -0
  65. package/dist/assets/templates/workflows/go.md +250 -0
  66. package/dist/assets/templates/workflows/health.md +5 -5
  67. package/dist/assets/templates/workflows/help.md +165 -435
  68. package/dist/assets/templates/workflows/init-existing.md +23 -23
  69. package/dist/assets/templates/workflows/init.md +205 -0
  70. package/dist/assets/templates/workflows/new-milestone.md +9 -9
  71. package/dist/assets/templates/workflows/new-project.md +26 -26
  72. package/dist/assets/templates/workflows/plan-create.md +298 -0
  73. package/dist/assets/templates/workflows/plan-discuss.md +347 -0
  74. package/dist/assets/templates/workflows/plan-phase.md +29 -29
  75. package/dist/assets/templates/workflows/plan-research.md +177 -0
  76. package/dist/assets/templates/workflows/plan.md +231 -0
  77. package/dist/assets/templates/workflows/progress.md +46 -42
  78. package/dist/assets/templates/workflows/quick.md +195 -14
  79. package/dist/assets/templates/workflows/research-phase.md +5 -5
  80. package/dist/assets/templates/workflows/sdd.md +20 -12
  81. package/dist/assets/templates/workflows/settings.md +18 -14
  82. package/dist/assets/templates/workflows/verify-phase.md +1 -1
  83. package/dist/assets/templates/workflows/verify-work.md +16 -16
  84. package/dist/cli.cjs +4589 -229
  85. package/dist/cli.cjs.map +1 -1
  86. package/dist/core-D5zUr9cb.cjs.map +1 -1
  87. package/dist/install.cjs +234 -17
  88. package/dist/install.cjs.map +1 -1
  89. package/dist/mcp-server.cjs +298 -20
  90. package/dist/mcp-server.cjs.map +1 -1
  91. package/dist/skills-CjFWZIGM.cjs.map +1 -1
  92. package/package.json +1 -1
  93. package/dist/assets/hooks/maxsim-context-monitor.cjs +0 -121
  94. package/dist/assets/hooks/maxsim-context-monitor.cjs.map +0 -1
  95. package/dist/assets/templates/agents/maxsim-code-reviewer.md +0 -239
  96. package/dist/assets/templates/agents/maxsim-codebase-mapper.md +0 -214
  97. package/dist/assets/templates/agents/maxsim-debugger.md +0 -572
  98. package/dist/assets/templates/agents/maxsim-drift-checker.md +0 -522
  99. package/dist/assets/templates/agents/maxsim-executor.md +0 -504
  100. package/dist/assets/templates/agents/maxsim-integration-checker.md +0 -273
  101. package/dist/assets/templates/agents/maxsim-phase-researcher.md +0 -305
  102. package/dist/assets/templates/agents/maxsim-plan-checker.md +0 -343
  103. package/dist/assets/templates/agents/maxsim-planner.md +0 -610
  104. package/dist/assets/templates/agents/maxsim-project-researcher.md +0 -359
  105. package/dist/assets/templates/agents/maxsim-research-synthesizer.md +0 -263
  106. package/dist/assets/templates/agents/maxsim-roadmapper.md +0 -324
  107. package/dist/assets/templates/agents/maxsim-spec-reviewer.md +0 -245
  108. package/dist/assets/templates/agents/maxsim-verifier.md +0 -393
  109. package/dist/assets/templates/commands/maxsim/add-phase.md +0 -43
  110. package/dist/assets/templates/commands/maxsim/add-tests.md +0 -41
  111. package/dist/assets/templates/commands/maxsim/add-todo.md +0 -57
  112. package/dist/assets/templates/commands/maxsim/artefakte.md +0 -122
  113. package/dist/assets/templates/commands/maxsim/audit-milestone.md +0 -36
  114. package/dist/assets/templates/commands/maxsim/batch.md +0 -42
  115. package/dist/assets/templates/commands/maxsim/check-drift.md +0 -56
  116. package/dist/assets/templates/commands/maxsim/check-todos.md +0 -46
  117. package/dist/assets/templates/commands/maxsim/cleanup.md +0 -18
  118. package/dist/assets/templates/commands/maxsim/complete-milestone.md +0 -136
  119. package/dist/assets/templates/commands/maxsim/discuss-phase.md +0 -87
  120. package/dist/assets/templates/commands/maxsim/discuss.md +0 -70
  121. package/dist/assets/templates/commands/maxsim/execute-phase.md +0 -41
  122. package/dist/assets/templates/commands/maxsim/health.md +0 -22
  123. package/dist/assets/templates/commands/maxsim/init-existing.md +0 -46
  124. package/dist/assets/templates/commands/maxsim/insert-phase.md +0 -32
  125. package/dist/assets/templates/commands/maxsim/list-phase-assumptions.md +0 -46
  126. package/dist/assets/templates/commands/maxsim/map-codebase.md +0 -71
  127. package/dist/assets/templates/commands/maxsim/new-milestone.md +0 -44
  128. package/dist/assets/templates/commands/maxsim/new-project.md +0 -46
  129. package/dist/assets/templates/commands/maxsim/pause-work.md +0 -38
  130. package/dist/assets/templates/commands/maxsim/plan-milestone-gaps.md +0 -34
  131. package/dist/assets/templates/commands/maxsim/plan-phase.md +0 -44
  132. package/dist/assets/templates/commands/maxsim/realign.md +0 -39
  133. package/dist/assets/templates/commands/maxsim/reapply-patches.md +0 -110
  134. package/dist/assets/templates/commands/maxsim/remove-phase.md +0 -31
  135. package/dist/assets/templates/commands/maxsim/research-phase.md +0 -189
  136. package/dist/assets/templates/commands/maxsim/resume-work.md +0 -40
  137. package/dist/assets/templates/commands/maxsim/roadmap.md +0 -19
  138. package/dist/assets/templates/commands/maxsim/sdd.md +0 -39
  139. package/dist/assets/templates/commands/maxsim/set-profile.md +0 -34
  140. package/dist/assets/templates/commands/maxsim/update.md +0 -37
  141. package/dist/assets/templates/commands/maxsim/verify-work.md +0 -38
  142. package/dist/assets/templates/workflows/add-phase.md +0 -111
  143. package/dist/assets/templates/workflows/add-tests.md +0 -351
  144. package/dist/assets/templates/workflows/add-todo.md +0 -247
  145. package/dist/assets/templates/workflows/audit-milestone.md +0 -297
  146. package/dist/assets/templates/workflows/check-drift.md +0 -248
  147. package/dist/assets/templates/workflows/check-todos.md +0 -261
  148. package/dist/assets/templates/workflows/cleanup.md +0 -153
  149. package/dist/assets/templates/workflows/complete-milestone.md +0 -701
  150. package/dist/assets/templates/workflows/discuss.md +0 -343
  151. package/dist/assets/templates/workflows/insert-phase.md +0 -129
  152. package/dist/assets/templates/workflows/list-phase-assumptions.md +0 -178
  153. package/dist/assets/templates/workflows/map-codebase.md +0 -315
  154. package/dist/assets/templates/workflows/pause-work.md +0 -122
  155. package/dist/assets/templates/workflows/plan-milestone-gaps.md +0 -274
  156. package/dist/assets/templates/workflows/realign.md +0 -288
  157. package/dist/assets/templates/workflows/remove-phase.md +0 -154
  158. package/dist/assets/templates/workflows/resume-project.md +0 -306
  159. package/dist/assets/templates/workflows/roadmap.md +0 -130
  160. package/dist/assets/templates/workflows/set-profile.md +0 -81
  161. package/dist/assets/templates/workflows/transition.md +0 -544
  162. package/dist/assets/templates/workflows/update.md +0 -220
@@ -39,6 +39,7 @@ let child_process = require("child_process");
39
39
  require("node:events");
40
40
  let node_child_process = require("node:child_process");
41
41
  let node_util = require("node:util");
42
+ let node_crypto = require("node:crypto");
42
43
 
43
44
  //#region ../../node_modules/zod/v3/helpers/util.js
44
45
  var util$2;
@@ -26858,6 +26859,12 @@ async function pathExistsInternal(p) {
26858
26859
  async function loadConfig(cwd) {
26859
26860
  if (_configCache && _configCache.cwd === cwd) return _configCache.config;
26860
26861
  const cfgPath = configPath(cwd);
26862
+ const reviewDefaults = {
26863
+ spec_review: true,
26864
+ code_review: true,
26865
+ simplify_review: true,
26866
+ retry_limit: 3
26867
+ };
26861
26868
  const defaults = {
26862
26869
  model_profile: "balanced",
26863
26870
  commit_docs: true,
@@ -26869,7 +26876,10 @@ async function loadConfig(cwd) {
26869
26876
  plan_checker: true,
26870
26877
  verifier: true,
26871
26878
  parallelization: true,
26872
- brave_search: false
26879
+ brave_search: false,
26880
+ worktree_mode: "auto",
26881
+ max_parallel_agents: 10,
26882
+ review: reviewDefaults
26873
26883
  };
26874
26884
  try {
26875
26885
  const raw = await node_fs.promises.readFile(cfgPath, "utf-8");
@@ -26926,7 +26936,17 @@ async function loadConfig(cwd) {
26926
26936
  }) ?? defaults.verifier,
26927
26937
  parallelization,
26928
26938
  brave_search: get("brave_search") ?? defaults.brave_search,
26929
- model_overrides: parsed["model_overrides"]
26939
+ model_overrides: parsed["model_overrides"],
26940
+ worktree_mode: get("worktree_mode") ?? defaults.worktree_mode,
26941
+ max_parallel_agents: get("max_parallel_agents") ?? defaults.max_parallel_agents,
26942
+ review: (() => {
26943
+ const userReview = get("review");
26944
+ if (!userReview || typeof userReview !== "object") return reviewDefaults;
26945
+ return {
26946
+ ...reviewDefaults,
26947
+ ...userReview
26948
+ };
26949
+ })()
26930
26950
  };
26931
26951
  _configCache = {
26932
26952
  cwd,
@@ -38040,9 +38060,9 @@ async function postPlanComment(phaseIssueNumber, planNumber, planContent) {
38040
38060
  /**
38041
38061
  * Close an issue. Optionally post a reason comment before closing.
38042
38062
  *
38043
- * Uses `state_reason: 'completed'` by default.
38063
+ * @param stateReason - 'completed' (default) or 'not_planned' (rollback/cancel)
38044
38064
  */
38045
- async function closeIssue(issueNumber, reason) {
38065
+ async function closeIssue(issueNumber, reason, stateReason = "completed") {
38046
38066
  return withGhResult(async () => {
38047
38067
  const octokit = getOctokit();
38048
38068
  const { owner, repo } = await getRepoInfo();
@@ -38057,7 +38077,7 @@ async function closeIssue(issueNumber, reason) {
38057
38077
  repo,
38058
38078
  issue_number: issueNumber,
38059
38079
  state: "closed",
38060
- state_reason: "completed"
38080
+ state_reason: stateReason
38061
38081
  });
38062
38082
  });
38063
38083
  }
@@ -38079,7 +38099,7 @@ async function reopenIssue(issueNumber) {
38079
38099
  /**
38080
38100
  * Fetch a single issue by number.
38081
38101
  *
38082
- * Returns number, id, title, state, and body.
38102
+ * Returns number, id, title, state, body, updated_at, labels, and comments_url.
38083
38103
  */
38084
38104
  async function getPhaseIssue(phaseIssueNumber) {
38085
38105
  return withGhResult(async () => {
@@ -38090,12 +38110,16 @@ async function getPhaseIssue(phaseIssueNumber) {
38090
38110
  repo,
38091
38111
  issue_number: phaseIssueNumber
38092
38112
  });
38113
+ const labels = response.data.labels.map((l) => typeof l === "string" ? l : l.name ?? "").filter(Boolean);
38093
38114
  return {
38094
38115
  number: response.data.number,
38095
38116
  id: response.data.id,
38096
38117
  title: response.data.title,
38097
38118
  state: response.data.state,
38098
- body: response.data.body ?? ""
38119
+ body: response.data.body ?? "",
38120
+ updated_at: response.data.updated_at,
38121
+ labels,
38122
+ comments_url: response.data.comments_url
38099
38123
  };
38100
38124
  });
38101
38125
  }
@@ -38103,7 +38127,7 @@ async function getPhaseIssue(phaseIssueNumber) {
38103
38127
  * List all sub-issues of a phase Issue.
38104
38128
  *
38105
38129
  * Uses GitHub's native sub-issues API.
38106
- * Returns each sub-issue's number, id, title, and state.
38130
+ * Returns each sub-issue's number, id, title, state, and updated_at.
38107
38131
  */
38108
38132
  async function listPhaseSubIssues(phaseIssueNumber) {
38109
38133
  return withGhResult(async () => {
@@ -38117,7 +38141,8 @@ async function listPhaseSubIssues(phaseIssueNumber) {
38117
38141
  number: issue.number,
38118
38142
  id: issue.id,
38119
38143
  title: issue.title,
38120
- state: issue.state
38144
+ state: issue.state,
38145
+ updated_at: issue.updated_at ?? ""
38121
38146
  }));
38122
38147
  });
38123
38148
  }
@@ -38239,6 +38264,13 @@ function mappingFilePath(cwd) {
38239
38264
  return planningPath(cwd, MAPPING_FILENAME);
38240
38265
  }
38241
38266
  /**
38267
+ * Compute a SHA-256 hash of an issue body string.
38268
+ * Used for external edit detection (WIRE-06).
38269
+ */
38270
+ function hashBody(body) {
38271
+ return (0, node_crypto.createHash)("sha256").update(body).digest("hex");
38272
+ }
38273
+ /**
38242
38274
  * Load and parse the mapping file (local cache).
38243
38275
  *
38244
38276
  * Returns null if the file does not exist.
@@ -38268,6 +38300,39 @@ function saveMapping(cwd, mapping) {
38268
38300
  node_fs.default.mkdirSync(dir, { recursive: true });
38269
38301
  node_fs.default.writeFileSync(filePath, JSON.stringify(mapping, null, 2) + "\n", "utf-8");
38270
38302
  }
38303
+ /**
38304
+ * Update a specific task's issue mapping within a phase.
38305
+ *
38306
+ * Load-modify-save pattern. Creates phase entry if it does not exist.
38307
+ * Merges partial data with existing entry (if any).
38308
+ *
38309
+ * @throws If mapping file does not exist (must be initialized first via saveMapping)
38310
+ */
38311
+ function updateTaskMapping(cwd, phaseNum, taskId, data) {
38312
+ const mapping = loadMapping(cwd);
38313
+ if (!mapping) throw new Error("github-issues.json does not exist. Run project setup first.");
38314
+ if (!mapping.phases[phaseNum]) mapping.phases[phaseNum] = {
38315
+ tracking_issue: {
38316
+ number: 0,
38317
+ id: 0,
38318
+ node_id: "",
38319
+ item_id: "",
38320
+ status: "To Do"
38321
+ },
38322
+ plan: "",
38323
+ tasks: {}
38324
+ };
38325
+ const existing = mapping.phases[phaseNum].tasks[taskId];
38326
+ const defaults = {
38327
+ number: 0,
38328
+ id: 0,
38329
+ node_id: "",
38330
+ item_id: "",
38331
+ status: "To Do"
38332
+ };
38333
+ mapping.phases[phaseNum].tasks[taskId] = Object.assign(defaults, existing, data);
38334
+ saveMapping(cwd, mapping);
38335
+ }
38271
38336
 
38272
38337
  //#endregion
38273
38338
  //#region src/mcp/utils.ts
@@ -40294,10 +40359,24 @@ function registerGitHubTools(server) {
40294
40359
  }
40295
40360
  const result = await createPhaseIssue(phase_number, phase_name, goal, requirements, success_criteria);
40296
40361
  if (!result.ok) return mcpError(`Phase issue creation failed: ${result.error}`, "Creation failed");
40297
- return mcpSuccess({
40362
+ const responseData = {
40298
40363
  issue_number: result.data.number,
40299
40364
  issue_id: result.data.id
40300
- }, `Created phase issue #${result.data.number}: [Phase ${phase_number}] ${phase_name}`);
40365
+ };
40366
+ const cwd = detectProjectRoot();
40367
+ if (cwd) {
40368
+ const mapping = loadMapping(cwd);
40369
+ if (mapping && mapping.project_number) {
40370
+ const addResult = await addItemToProject(mapping.project_number, result.data.number);
40371
+ if (addResult.ok) {
40372
+ responseData.item_id = addResult.data.itemId;
40373
+ responseData.project_number = mapping.project_number;
40374
+ const moveResult = await moveItemToStatus(mapping.project_number, addResult.data.itemId, "To Do");
40375
+ if (!moveResult.ok) responseData.board_warning = `Added to board but could not set status: ${moveResult.error}`;
40376
+ } else responseData.board_warning = `Issue created but could not add to board: ${addResult.error}`;
40377
+ }
40378
+ }
40379
+ return mcpSuccess(responseData, `Created phase issue #${result.data.number}: [Phase ${phase_number}] ${phase_name}`);
40301
40380
  } catch (e) {
40302
40381
  return mcpError(e.message, "Operation failed");
40303
40382
  }
@@ -40318,11 +40397,24 @@ function registerGitHubTools(server) {
40318
40397
  }
40319
40398
  const result = await createTaskSubIssue(phase_number, task_id, title, body, parent_issue_number);
40320
40399
  if (!result.ok) return mcpError(`Task issue creation failed: ${result.error}`, "Creation failed");
40321
- return mcpSuccess({
40400
+ const responseData = {
40322
40401
  issue_number: result.data.number,
40323
40402
  issue_id: result.data.id,
40324
40403
  parent_issue_number
40325
- }, `Created task sub-issue #${result.data.number}: ${title}`);
40404
+ };
40405
+ const cwd = detectProjectRoot();
40406
+ if (cwd) try {
40407
+ updateTaskMapping(cwd, phase_number, task_id, {
40408
+ number: result.data.number,
40409
+ id: result.data.id,
40410
+ node_id: "",
40411
+ item_id: "",
40412
+ status: "To Do"
40413
+ });
40414
+ } catch (mappingErr) {
40415
+ responseData.mapping_warning = `Issue created but mapping update failed: ${mappingErr.message}`;
40416
+ }
40417
+ return mcpSuccess(responseData, `Created task sub-issue #${result.data.number}: ${title}`);
40326
40418
  } catch (e) {
40327
40419
  return mcpError(e.message, "Operation failed");
40328
40420
  }
@@ -40350,10 +40442,11 @@ function registerGitHubTools(server) {
40350
40442
  return mcpError(e.message, "Operation failed");
40351
40443
  }
40352
40444
  });
40353
- server.tool("mcp_close_issue", "Close a GitHub issue as completed.", {
40445
+ server.tool("mcp_close_issue", "Close a GitHub issue as completed or not planned.", {
40354
40446
  issue_number: numberType().describe("GitHub issue number"),
40355
- reason: stringType().optional().describe("Optional reason comment to post before closing")
40356
- }, async ({ issue_number, reason }) => {
40447
+ reason: stringType().optional().describe("Optional reason comment to post before closing"),
40448
+ state_reason: enumType(["completed", "not_planned"]).optional().default("completed").describe("Close reason: completed (default) or not_planned (rollback)")
40449
+ }, async ({ issue_number, reason, state_reason }) => {
40357
40450
  try {
40358
40451
  try {
40359
40452
  requireAuth();
@@ -40361,12 +40454,13 @@ function registerGitHubTools(server) {
40361
40454
  if (e instanceof AuthError) return mcpAuthError$1(e);
40362
40455
  throw e;
40363
40456
  }
40364
- const result = await closeIssue(issue_number, reason);
40457
+ const result = await closeIssue(issue_number, reason, state_reason);
40365
40458
  if (!result.ok) return mcpError(`Close failed: ${result.error}`, "Close failed");
40366
40459
  return mcpSuccess({
40367
40460
  issue_number,
40368
- closed: true
40369
- }, `Issue #${issue_number} closed`);
40461
+ closed: true,
40462
+ state_reason
40463
+ }, `Issue #${issue_number} closed (${state_reason})`);
40370
40464
  } catch (e) {
40371
40465
  return mcpError(e.message, "Operation failed");
40372
40466
  }
@@ -40405,7 +40499,10 @@ function registerGitHubTools(server) {
40405
40499
  id: issue.id,
40406
40500
  title: issue.title,
40407
40501
  state: issue.state,
40408
- body: issue.body
40502
+ body: issue.body,
40503
+ updated_at: issue.updated_at,
40504
+ labels: issue.labels,
40505
+ comments_url: issue.comments_url
40409
40506
  }, `Issue #${issue.number}: ${issue.title} (${issue.state})`);
40410
40507
  } catch (e) {
40411
40508
  return mcpError(e.message, "Operation failed");
@@ -40482,6 +40579,136 @@ function registerGitHubTools(server) {
40482
40579
  return mcpError(e.message, "Operation failed");
40483
40580
  }
40484
40581
  });
40582
+ server.tool("mcp_post_comment", "Post a comment on a GitHub issue.", {
40583
+ issue_number: numberType().describe("GitHub issue number"),
40584
+ body: stringType().describe("Comment body (markdown)"),
40585
+ type: enumType([
40586
+ "research",
40587
+ "context",
40588
+ "summary",
40589
+ "verification",
40590
+ "uat",
40591
+ "general"
40592
+ ]).optional().describe("Comment type for structured header")
40593
+ }, async ({ issue_number, body, type }) => {
40594
+ try {
40595
+ try {
40596
+ requireAuth();
40597
+ } catch (e) {
40598
+ if (e instanceof AuthError) return mcpAuthError$1(e);
40599
+ throw e;
40600
+ }
40601
+ const result = await postComment(issue_number, type ? `<!-- maxsim:type=${type} -->\n${body}` : body);
40602
+ if (!result.ok) return mcpError(`Comment failed: ${result.error}`, "Comment failed");
40603
+ return mcpSuccess({
40604
+ issue_number,
40605
+ comment_id: result.data.commentId,
40606
+ type: type ?? "general"
40607
+ }, `Comment posted on issue #${issue_number}`);
40608
+ } catch (e) {
40609
+ return mcpError(e.message, "Operation failed");
40610
+ }
40611
+ });
40612
+ server.tool("mcp_batch_create_tasks", "Create multiple task sub-issues for a phase with automatic rollback on failure.", {
40613
+ phase_number: stringType().describe("Phase number (e.g. \"01\")"),
40614
+ parent_issue_number: numberType().describe("Parent phase issue number"),
40615
+ tasks: arrayType(objectType({
40616
+ task_id: stringType().describe("Task ID within the phase"),
40617
+ title: stringType().describe("Task title"),
40618
+ body: stringType().describe("Task body (markdown)")
40619
+ })).describe("List of tasks to create")
40620
+ }, async ({ phase_number, parent_issue_number, tasks }) => {
40621
+ try {
40622
+ try {
40623
+ requireAuth();
40624
+ } catch (e) {
40625
+ if (e instanceof AuthError) return mcpAuthError$1(e);
40626
+ throw e;
40627
+ }
40628
+ const succeeded = [];
40629
+ const failed = [];
40630
+ const created = [];
40631
+ for (const task of tasks) {
40632
+ const result = await createTaskSubIssue(phase_number, task.task_id, task.title, task.body, parent_issue_number);
40633
+ if (result.ok) {
40634
+ created.push({
40635
+ issueNumber: result.data.number,
40636
+ taskId: task.task_id
40637
+ });
40638
+ succeeded.push({
40639
+ task_id: task.task_id,
40640
+ issue_number: result.data.number
40641
+ });
40642
+ const cwd = detectProjectRoot();
40643
+ if (cwd) try {
40644
+ updateTaskMapping(cwd, phase_number, task.task_id, {
40645
+ number: result.data.number,
40646
+ id: result.data.id,
40647
+ node_id: "",
40648
+ item_id: "",
40649
+ status: "To Do"
40650
+ });
40651
+ } catch {}
40652
+ } else {
40653
+ failed.push({
40654
+ task_id: task.task_id,
40655
+ error: result.error
40656
+ });
40657
+ const rolledBack = [];
40658
+ for (const c of [...created].reverse()) if ((await closeIssue(c.issueNumber, "[MAXSIM-ROLLBACK] Partial batch failure", "not_planned")).ok) rolledBack.push(c.issueNumber);
40659
+ return mcpSuccess({
40660
+ succeeded,
40661
+ failed,
40662
+ rolled_back: rolledBack,
40663
+ partial: true
40664
+ }, `Batch failed at task "${task.task_id}". Rolled back ${rolledBack.length} issue(s).`);
40665
+ }
40666
+ }
40667
+ return mcpSuccess({
40668
+ succeeded,
40669
+ failed,
40670
+ rolled_back: [],
40671
+ partial: false
40672
+ }, `Batch created ${succeeded.length} task issue(s) for phase ${phase_number}`);
40673
+ } catch (e) {
40674
+ return mcpError(e.message, "Operation failed");
40675
+ }
40676
+ });
40677
+ server.tool("mcp_detect_external_edits", "Check if a phase issue body was modified outside MAXSIM.", { phase_number: stringType().describe("Phase number (e.g. \"01\")") }, async ({ phase_number }) => {
40678
+ try {
40679
+ try {
40680
+ requireAuth();
40681
+ } catch (e) {
40682
+ if (e instanceof AuthError) return mcpAuthError$1(e);
40683
+ throw e;
40684
+ }
40685
+ const cwd = detectProjectRoot();
40686
+ if (!cwd) return mcpError("No .planning/ directory found", "Project not detected");
40687
+ const mapping = loadMapping(cwd);
40688
+ if (!mapping) return mcpError("github-issues.json not found. Run project setup first.", "Mapping missing");
40689
+ const phaseMapping = mapping.phases[phase_number];
40690
+ if (!phaseMapping) return mcpError(`Phase ${phase_number} not found in mapping`, "Phase not found");
40691
+ const storedHash = phaseMapping.body_hash;
40692
+ const issueNumber = phaseMapping.tracking_issue.number;
40693
+ const issueResult = await getPhaseIssue(issueNumber);
40694
+ if (!issueResult.ok) return mcpError(`Failed to fetch issue #${issueNumber}: ${issueResult.error}`, "Fetch failed");
40695
+ const liveHash = hashBody(issueResult.data.body);
40696
+ if (!storedHash) return mcpSuccess({
40697
+ modified: false,
40698
+ phase_number,
40699
+ issue_number: issueNumber,
40700
+ note: "No stored hash — baseline not yet established"
40701
+ }, `Phase ${phase_number}: no baseline hash stored`);
40702
+ const modified = liveHash !== storedHash;
40703
+ return mcpSuccess({
40704
+ modified,
40705
+ phase_number,
40706
+ issue_number: issueNumber
40707
+ }, modified ? `Phase ${phase_number} issue #${issueNumber} has been externally modified` : `Phase ${phase_number} issue #${issueNumber} matches stored hash`);
40708
+ } catch (e) {
40709
+ return mcpError(e.message, "Operation failed");
40710
+ }
40711
+ });
40485
40712
  }
40486
40713
 
40487
40714
  //#endregion
@@ -40567,6 +40794,57 @@ function registerBoardTools(server) {
40567
40794
  return mcpError(e.message, "Operation failed");
40568
40795
  }
40569
40796
  });
40797
+ server.tool("mcp_sync_check", "Verify local github-issues.json mapping is in sync with live GitHub state.", {}, async () => {
40798
+ try {
40799
+ try {
40800
+ requireAuth();
40801
+ } catch (e) {
40802
+ if (e instanceof AuthError) return mcpAuthError(e);
40803
+ throw e;
40804
+ }
40805
+ const cwd = detectProjectRoot();
40806
+ if (!cwd) return mcpError("No .planning/ directory found", "Project not detected");
40807
+ const mapping = loadMapping(cwd);
40808
+ if (!mapping) return mcpError("github-issues.json not found. Run project setup first.", "Mapping missing");
40809
+ const mismatches = [];
40810
+ const missing_remote = [];
40811
+ for (const [phaseNum, phaseMapping] of Object.entries(mapping.phases)) {
40812
+ const issueNumber = phaseMapping.tracking_issue.number;
40813
+ if (!issueNumber) continue;
40814
+ const issueResult = await getPhaseIssue(issueNumber);
40815
+ if (!issueResult.ok) {
40816
+ if (issueResult.error.includes("NOT_FOUND") || issueResult.error.includes("404")) missing_remote.push({
40817
+ phase_number: phaseNum,
40818
+ issue_number: issueNumber
40819
+ });
40820
+ continue;
40821
+ }
40822
+ const localStatus = phaseMapping.tracking_issue.status;
40823
+ const remoteState = issueResult.data.state;
40824
+ if (remoteState === "closed" && localStatus !== "Done") mismatches.push({
40825
+ phase_number: phaseNum,
40826
+ issue_number: issueNumber,
40827
+ local_state: localStatus,
40828
+ remote_state: remoteState
40829
+ });
40830
+ else if (remoteState === "open" && localStatus === "Done") mismatches.push({
40831
+ phase_number: phaseNum,
40832
+ issue_number: issueNumber,
40833
+ local_state: localStatus,
40834
+ remote_state: remoteState
40835
+ });
40836
+ }
40837
+ const in_sync = mismatches.length === 0 && missing_remote.length === 0;
40838
+ return mcpSuccess({
40839
+ in_sync,
40840
+ mismatches,
40841
+ missing_local: [],
40842
+ missing_remote
40843
+ }, in_sync ? "Local mapping is in sync with GitHub" : `Sync issues found: ${mismatches.length} mismatch(es), ${missing_remote.length} missing remote`);
40844
+ } catch (e) {
40845
+ return mcpError(e.message, "Operation failed");
40846
+ }
40847
+ });
40570
40848
  server.tool("mcp_search_issues", "Search GitHub issues by label, state, or text query.", {
40571
40849
  labels: arrayType(stringType()).optional().describe("Filter by label names"),
40572
40850
  state: enumType([