@taptap/instant-games-open-mcp 1.23.1 → 1.23.2

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/dist/maker.js CHANGED
@@ -29059,7 +29059,7 @@ async function cloneMakerProject(options) {
29059
29059
  let authUrl = makeAuthenticatedGitUrl(gitUrl, pat.token);
29060
29060
  let retriedWithNewPat = false;
29061
29061
  let transientRetries = 0;
29062
- if (isGitRepo(target) && hasGitHead(target)) {
29062
+ if (isOwnGitRoot(target) && hasGitHead(target)) {
29063
29063
  (_d = options.onProgress) == null ? void 0 : _d.call(options, {
29064
29064
  progress: 10,
29065
29065
  total: 100,
@@ -29112,7 +29112,7 @@ async function cloneMakerProject(options) {
29112
29112
  warnings
29113
29113
  };
29114
29114
  }
29115
- if (isGitRepo(target)) {
29115
+ if (isOwnGitRoot(target)) {
29116
29116
  warnings.push(
29117
29117
  "Target directory already contained git metadata but no checked-out commit. Maker MCP will fetch and check out the remote Maker project branch before reporting success."
29118
29118
  );
@@ -29158,6 +29158,7 @@ async function cloneMakerProject(options) {
29158
29158
  }
29159
29159
  try {
29160
29160
  ensureGitHeadCheckedOut(target);
29161
+ ensureOwnGitRoot(target);
29161
29162
  } catch (error2) {
29162
29163
  throw withPreCloneWarnings(error2, warnings);
29163
29164
  }
@@ -29191,14 +29192,9 @@ async function pushMakerProject(options) {
29191
29192
  phase: "prepare",
29192
29193
  message: "Preparing Maker project push"
29193
29194
  });
29194
- const cwd = path5.resolve(options.cwd);
29195
- if (!isGitRepo(cwd)) {
29196
- throw new Error(`${cwd} is not a git repository.`);
29197
- }
29198
- const configPath = path5.join(cwd, ".maker-mcp", "config.json");
29199
- if (!fs4.existsSync(configPath)) {
29200
- throw new Error(`${cwd} is not bound to a Maker project. .maker-mcp/config.json is missing.`);
29201
- }
29195
+ const requestedCwd = path5.resolve(options.cwd);
29196
+ const workspace = resolveUsableMakerGitWorkspace(requestedCwd);
29197
+ const cwd = workspace.projectRoot;
29202
29198
  const project = loadProjectConfig(cwd);
29203
29199
  if (!(project == null ? void 0 : project.project_id)) {
29204
29200
  throw new Error(`${cwd} Maker project config does not contain project_id.`);
@@ -29219,7 +29215,8 @@ async function pushMakerProject(options) {
29219
29215
  });
29220
29216
  const statusBefore = await readGit(["status", "--porcelain"], cwd);
29221
29217
  const branch = await currentBranch(cwd, options.branch);
29222
- if (!statusBefore.trim() && !options.allowEmpty) {
29218
+ const unpushed = await readUnpushedCommitState(cwd, branch);
29219
+ if (!statusBefore.trim() && !options.allowEmpty && !unpushed.hasUnpushedCommits) {
29223
29220
  (_c = options.onProgress) == null ? void 0 : _c.call(options, {
29224
29221
  progress: 100,
29225
29222
  total: 100,
@@ -29234,7 +29231,12 @@ async function pushMakerProject(options) {
29234
29231
  status: "clean"
29235
29232
  };
29236
29233
  }
29237
- if ((_d = options.files) == null ? void 0 : _d.length) {
29234
+ let committed = false;
29235
+ let commitHash;
29236
+ let message;
29237
+ if (!statusBefore.trim() && !options.allowEmpty && unpushed.hasUnpushedCommits) {
29238
+ commitHash = (await readGit(["rev-parse", "--short", "HEAD"], cwd)).trim();
29239
+ } else if ((_d = options.files) == null ? void 0 : _d.length) {
29238
29240
  (_e = options.onProgress) == null ? void 0 : _e.call(options, {
29239
29241
  progress: 20,
29240
29242
  total: 100,
@@ -29250,33 +29252,31 @@ async function pushMakerProject(options) {
29250
29252
  message: "Staging all local changes"
29251
29253
  });
29252
29254
  await runGit(["add", "-A"], { cwd });
29253
- }
29254
- const staged = await readGit(["diff", "--cached", "--name-only"], cwd);
29255
- let committed = false;
29256
- let commitHash;
29257
- const message = options.message || generateCommitMessage(statusBefore);
29258
- if (staged.trim() || options.allowEmpty) {
29259
- (_g = options.onProgress) == null ? void 0 : _g.call(options, {
29260
- progress: 45,
29261
- total: 100,
29262
- phase: "commit",
29263
- message: "Creating local Maker project commit"
29264
- });
29265
- await runGit(
29266
- [
29267
- "-c",
29268
- "user.email=maker-mcp@local",
29269
- "-c",
29270
- "user.name=taptap-maker",
29271
- "commit",
29272
- ...options.allowEmpty ? ["--allow-empty"] : [],
29273
- "-m",
29274
- message
29275
- ],
29276
- { cwd }
29277
- );
29278
- committed = true;
29279
- commitHash = (await readGit(["rev-parse", "--short", "HEAD"], cwd)).trim();
29255
+ const staged = await readGit(["diff", "--cached", "--name-only"], cwd);
29256
+ message = options.message || generateCommitMessage(statusBefore);
29257
+ if (staged.trim() || options.allowEmpty) {
29258
+ (_g = options.onProgress) == null ? void 0 : _g.call(options, {
29259
+ progress: 45,
29260
+ total: 100,
29261
+ phase: "commit",
29262
+ message: "Creating local Maker project commit"
29263
+ });
29264
+ await runGit(
29265
+ [
29266
+ "-c",
29267
+ "user.email=maker-mcp@local",
29268
+ "-c",
29269
+ "user.name=taptap-maker",
29270
+ "commit",
29271
+ ...options.allowEmpty ? ["--allow-empty"] : [],
29272
+ "-m",
29273
+ message
29274
+ ],
29275
+ { cwd }
29276
+ );
29277
+ committed = true;
29278
+ commitHash = (await readGit(["rev-parse", "--short", "HEAD"], cwd)).trim();
29279
+ }
29280
29280
  }
29281
29281
  try {
29282
29282
  (_h = options.onProgress) == null ? void 0 : _h.call(options, {
@@ -29294,7 +29294,7 @@ async function pushMakerProject(options) {
29294
29294
  commitHash,
29295
29295
  message,
29296
29296
  pushed: false,
29297
- status: committed ? "failed_after_commit" : "clean",
29297
+ status: committed || unpushed.hasUnpushedCommits ? "failed_after_commit" : "clean",
29298
29298
  failure,
29299
29299
  ahead: await readAheadState(cwd)
29300
29300
  };
@@ -29316,28 +29316,23 @@ async function pushMakerProject(options) {
29316
29316
  }
29317
29317
  async function readMakerProjectLocalChanges(cwd) {
29318
29318
  ensureGitAvailable();
29319
- const requestedDir = path5.resolve(cwd);
29320
- if (!isGitRepo(requestedDir)) {
29321
- throw new Error(`${requestedDir} is not a git repository.`);
29322
- }
29323
- const projectRoot = (await readGit(["rev-parse", "--show-toplevel"], requestedDir)).trim();
29324
- const configPath = path5.join(projectRoot, ".maker-mcp", "config.json");
29325
- if (!fs4.existsSync(configPath)) {
29326
- throw new Error(
29327
- `${projectRoot} is not bound to a Maker project. .maker-mcp/config.json is missing.`
29328
- );
29329
- }
29319
+ const { projectRoot } = resolveUsableMakerGitWorkspace(cwd);
29330
29320
  const rawStatus = await readGit(["status", "--porcelain", "-z"], projectRoot);
29331
- const files = parseGitStatusFiles(rawStatus).filter(
29332
- (file2) => file2 !== ".maker-mcp" && !file2.startsWith(".maker-mcp/")
29333
- );
29321
+ const files = parseGitStatusFiles(rawStatus).filter((file2) => !isIgnoredBuildGuardChange(file2));
29322
+ const branch = await currentBranch(projectRoot);
29323
+ const unpushed = await readUnpushedCommitState(projectRoot, branch);
29334
29324
  return {
29335
- hasChanges: files.length > 0,
29325
+ hasChanges: files.length > 0 || unpushed.hasUnpushedCommits,
29336
29326
  projectRoot,
29337
29327
  files,
29338
- rawStatus
29328
+ rawStatus,
29329
+ hasUnpushedCommits: unpushed.hasUnpushedCommits,
29330
+ ahead: unpushed.ahead
29339
29331
  };
29340
29332
  }
29333
+ function isIgnoredBuildGuardChange(file2) {
29334
+ return file2 === ".gitignore" || file2 === ".maker-mcp" || file2.startsWith(".maker-mcp/");
29335
+ }
29341
29336
  function ensureTargetCanBindApp(target, appId) {
29342
29337
  const existingConfig = loadProjectConfig(target);
29343
29338
  if (!(existingConfig == null ? void 0 : existingConfig.project_id) || existingConfig.project_id === appId) {
@@ -29393,6 +29388,28 @@ async function readAheadState(cwd) {
29393
29388
  return void 0;
29394
29389
  }
29395
29390
  }
29391
+ async function readUnpushedCommitState(cwd, branch) {
29392
+ const remoteRef = `origin/${branch}`;
29393
+ try {
29394
+ const countText = await readGit(["rev-list", "--count", `${remoteRef}..HEAD`], cwd);
29395
+ const count = Number.parseInt(countText.trim(), 10);
29396
+ if (Number.isFinite(count) && count > 0) {
29397
+ return {
29398
+ hasUnpushedCommits: true,
29399
+ ahead: `${remoteRef}..HEAD (${count} commit${count === 1 ? "" : "s"})`
29400
+ };
29401
+ }
29402
+ } catch {
29403
+ }
29404
+ const status = await readAheadState(cwd);
29405
+ if (status && /\bahead\s+\d+/i.test(status)) {
29406
+ return {
29407
+ hasUnpushedCommits: true,
29408
+ ahead: status
29409
+ };
29410
+ }
29411
+ return { hasUnpushedCommits: false, ahead: status };
29412
+ }
29396
29413
  function toMakerGitFailure(error2, stage) {
29397
29414
  if (error2 instanceof MakerGitError) {
29398
29415
  return error2.failure;
@@ -29450,13 +29467,13 @@ function nextActionForFailure(classification) {
29450
29467
  case "auth":
29451
29468
  return "刷新 Maker PAT 后重试 maker_submit_current_directory;如果仍失败,请确认 PAT 是否过期或缺少 Maker git 权限。";
29452
29469
  case "remote_transient":
29453
- return "远端 Maker git 服务临时不可用。不要重新提交,稍后直接重试 maker_submit_current_directory。";
29470
+ return "远端 Maker git 服务临时不可用。本地 commit 会保留;不要手动执行通用 git push,稍后直接重试 maker_submit_current_directory,或在构建重试时调用 maker_build_current_directory 并设置 submit_local_changes_before_build=true。";
29454
29471
  case "remote_rejected":
29455
- return "远端已有新提交。不要新建分支或要任务号,先询问用户是否 pull/rebase 当前 Maker 远端变更,再重试 push。";
29472
+ return "远端已有新提交。不要新建分支、不要要任务号、不要手动执行通用 git push;先询问用户是否 pull/rebase 当前 Maker 远端变更,再重试 maker_submit_current_directory。";
29456
29473
  case "local":
29457
29474
  return "本地目录或权限异常。检查当前目录是否是 Maker git repo,以及 Codex 是否有目录写权限。";
29458
29475
  default:
29459
- return "保留本地提交,不要重复提交;把错误详情反馈给用户,并在确认后重试 push。";
29476
+ return "保留本地提交,不要重复提交;把错误详情反馈给用户,并在确认后重试 maker_submit_current_directory。";
29460
29477
  }
29461
29478
  }
29462
29479
  function pushGit(args, cwd, onProgress) {
@@ -29718,12 +29735,139 @@ async function assertNoCheckoutFileConflicts(cwd, branch) {
29718
29735
  async function setOrigin(cwd, authUrl) {
29719
29736
  await runGit(["remote", "get-url", "origin"], { cwd, quiet: true }).then(() => runGit(["remote", "set-url", "origin", authUrl], { cwd, quiet: true })).catch(() => runGit(["remote", "add", "origin", authUrl], { cwd, quiet: true }));
29720
29737
  }
29721
- function isGitRepo(repoDir) {
29738
+ function isOwnGitRoot(repoDir) {
29739
+ const status = inspectMakerDirectoryGitStatus(repoDir);
29740
+ return status.isOwnGitRoot;
29741
+ }
29742
+ function ensureOwnGitRoot(repoDir) {
29743
+ const status = inspectMakerDirectoryGitStatus(repoDir);
29744
+ if (status.isOwnGitRoot) {
29745
+ return;
29746
+ }
29747
+ throw new Error(
29748
+ [
29749
+ "Maker project checkout did not create an independent Git repository.",
29750
+ `target_dir: ${status.targetDir}`,
29751
+ status.gitRoot ? `detected_git_root: ${status.gitRoot}` : "",
29752
+ "A Maker project directory must have its own .git directory. Parent Git repositories must not be reused."
29753
+ ].filter(Boolean).join("\n")
29754
+ );
29755
+ }
29756
+ function inspectMakerDirectoryGitStatus(cwd) {
29757
+ const targetDir = path5.resolve(cwd);
29758
+ const gitRoot = resolveGitRoot(targetDir);
29759
+ const gitDir = resolveGitDir(targetDir);
29760
+ const makerBinding = findMakerProjectBinding(targetDir);
29761
+ const isGitWorkTree = Boolean(gitRoot);
29762
+ const isOwnGitRoot2 = Boolean(gitRoot && samePath(gitRoot, targetDir));
29763
+ const isUsableMakerGitRepo = Boolean(
29764
+ (makerBinding == null ? void 0 : makerBinding.projectRoot) && gitRoot && samePath(makerBinding.projectRoot, gitRoot)
29765
+ );
29766
+ let issue2;
29767
+ let message;
29768
+ if (makerBinding && gitRoot && !samePath(makerBinding.projectRoot, gitRoot)) {
29769
+ issue2 = "inside_parent_git_repo";
29770
+ message = [
29771
+ `${makerBinding.projectRoot} contains Maker binding config, but Git root is ${gitRoot}.`,
29772
+ "The Maker directory must be an independent Git repository before build or submit."
29773
+ ].join(" ");
29774
+ } else if (makerBinding && !gitRoot) {
29775
+ issue2 = "missing_git_repo";
29776
+ message = `${makerBinding.projectRoot} is bound to Maker but is not a Git repository.`;
29777
+ } else if (!makerBinding) {
29778
+ issue2 = "missing_maker_config";
29779
+ message = `${targetDir} is not bound to a Maker project. .maker-mcp/config.json is missing.`;
29780
+ }
29781
+ return {
29782
+ targetDir,
29783
+ gitRoot,
29784
+ gitDir,
29785
+ makerProjectRoot: makerBinding == null ? void 0 : makerBinding.projectRoot,
29786
+ configPath: makerBinding == null ? void 0 : makerBinding.configPath,
29787
+ isGitWorkTree,
29788
+ isOwnGitRoot: isOwnGitRoot2,
29789
+ isUsableMakerGitRepo,
29790
+ issue: issue2,
29791
+ message
29792
+ };
29793
+ }
29794
+ function resolveUsableMakerGitWorkspace(cwd) {
29795
+ const status = inspectMakerDirectoryGitStatus(cwd);
29796
+ if (!status.makerProjectRoot || !status.configPath) {
29797
+ throw new Error(status.message || `${status.targetDir} is not bound to a Maker project.`);
29798
+ }
29799
+ if (!status.gitRoot) {
29800
+ throw new Error(
29801
+ [
29802
+ `${status.makerProjectRoot} is bound to a Maker project but is not a Git repository.`,
29803
+ "The Maker project directory must be an independent Git repository before build or submit."
29804
+ ].join("\n")
29805
+ );
29806
+ }
29807
+ if (!samePath(status.makerProjectRoot, status.gitRoot)) {
29808
+ throw new Error(formatMakerGitRootMismatch(status));
29809
+ }
29810
+ return {
29811
+ projectRoot: status.makerProjectRoot,
29812
+ configPath: status.configPath,
29813
+ gitRoot: status.gitRoot
29814
+ };
29815
+ }
29816
+ function formatMakerGitRootMismatch(status) {
29817
+ return [
29818
+ `${status.makerProjectRoot} must be an independent Git repository before build or submit.`,
29819
+ "",
29820
+ `maker_project_root: ${status.makerProjectRoot}`,
29821
+ `git_root: ${status.gitRoot || "(none)"}`,
29822
+ status.configPath ? `config: ${status.configPath}` : "",
29823
+ "",
29824
+ "The current Maker directory is inside another Git repository, but it does not have its own .git directory.",
29825
+ "Re-run maker_clone_to_current_directory after this fix, or use a fresh independent Maker directory."
29826
+ ].filter(Boolean).join("\n");
29827
+ }
29828
+ function findMakerProjectBinding(startDir) {
29829
+ var _a2;
29830
+ let current = path5.resolve(startDir);
29831
+ while (current.length > 0) {
29832
+ const configPath = getProjectConfigPath(current);
29833
+ if (fs4.existsSync(configPath) && ((_a2 = loadProjectConfig(current)) == null ? void 0 : _a2.project_id)) {
29834
+ return {
29835
+ projectRoot: current,
29836
+ configPath
29837
+ };
29838
+ }
29839
+ const parent = path5.dirname(current);
29840
+ if (parent === current) {
29841
+ return null;
29842
+ }
29843
+ current = parent;
29844
+ }
29845
+ return null;
29846
+ }
29847
+ function resolveGitRoot(cwd) {
29722
29848
  try {
29723
- const gitDir = readGitSync(["-C", repoDir, "rev-parse", "--git-dir"]);
29724
- return gitDir.trim().length > 0;
29849
+ return path5.resolve(readGitSync(["-C", cwd, "rev-parse", "--show-toplevel"]).trim());
29725
29850
  } catch {
29726
- return false;
29851
+ return void 0;
29852
+ }
29853
+ }
29854
+ function resolveGitDir(cwd) {
29855
+ try {
29856
+ const gitDir = readGitSync(["-C", cwd, "rev-parse", "--git-dir"]).trim();
29857
+ return path5.isAbsolute(gitDir) ? path5.resolve(gitDir) : path5.resolve(cwd, gitDir);
29858
+ } catch {
29859
+ return void 0;
29860
+ }
29861
+ }
29862
+ function samePath(left, right) {
29863
+ return normalizePathForCompare(left) === normalizePathForCompare(right);
29864
+ }
29865
+ function normalizePathForCompare(value) {
29866
+ const resolved = path5.resolve(value);
29867
+ try {
29868
+ return fs4.realpathSync.native(resolved);
29869
+ } catch {
29870
+ return resolved;
29727
29871
  }
29728
29872
  }
29729
29873
  function hasGitHead(repoDir) {
@@ -30082,10 +30226,19 @@ function getBundledSkillSourceDir(skillName) {
30082
30226
  }
30083
30227
 
30084
30228
  // src/maker/server/mcp.ts
30085
- var VERSION = true ? "1.23.1" : "dev";
30229
+ var VERSION = true ? "1.23.2" : "dev";
30086
30230
  var DEFAULT_PROXY_PACKAGE = "@taptap/instant-games-open-mcp@1.22.0";
30087
30231
  var DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1e3;
30088
30232
  var LONG_OPERATION_HEARTBEAT_MS = 3 * 60 * 1e3;
30233
+ var MakerCloneFailedError = class extends Error {
30234
+ constructor(targetDir, originalError) {
30235
+ const message = originalError instanceof Error ? originalError.message : String(originalError);
30236
+ super(message);
30237
+ this.name = "MakerCloneFailedError";
30238
+ this.targetDir = targetDir;
30239
+ this.originalError = originalError;
30240
+ }
30241
+ };
30089
30242
  var tools = [
30090
30243
  {
30091
30244
  name: "maker_exchange_pat",
@@ -30340,6 +30493,7 @@ async function startMakerMcpServer() {
30340
30493
  throw new McpError(ErrorCode.InvalidParams, "app_id is required");
30341
30494
  }
30342
30495
  const targetDir = resolveMakerToolTargetDir(args.target_dir);
30496
+ ensureGitAvailable();
30343
30497
  const progressReporter = createToolProgressReporter(
30344
30498
  (_a2 = request.params._meta) == null ? void 0 : _a2.progressToken,
30345
30499
  extra,
@@ -30415,7 +30569,7 @@ async function startMakerMcpServer() {
30415
30569
  progressSummary = progressReporter.finish();
30416
30570
  } catch (error2) {
30417
30571
  progressReporter.finish();
30418
- throw error2;
30572
+ throw new MakerCloneFailedError(targetDir, error2);
30419
30573
  }
30420
30574
  return {
30421
30575
  content: [
@@ -30533,6 +30687,7 @@ async function formatStatus(options = {}) {
30533
30687
  var _a2;
30534
30688
  const targetDir = resolveMakerToolTargetDir(options.targetDir);
30535
30689
  const identify = identifyMakerProject({ cwd: targetDir });
30690
+ const gitDirectoryStatus = inspectMakerDirectoryGitStatus(targetDir);
30536
30691
  const pat = loadPat();
30537
30692
  let tapAuth = loadTapAuth();
30538
30693
  const makerPatTokensUrl = getMakerPatTokensUrl();
@@ -30559,7 +30714,7 @@ async function formatStatus(options = {}) {
30559
30714
  "目标目录已绑定 Maker 项目。",
30560
30715
  "请继续在当前绑定项目上执行状态、提交、构建等操作;不要再引导用户 clone,除非用户明确要求切换或重新拉取项目。",
30561
30716
  "本地 Maker 工作流请优先参考 taptap-maker-local skill;MCP tools 只负责保存 PAT、列 app、clone、submit 和 build 等机器动作。"
30562
- ].join("\n") : pat ? await formatAutoProjectListFromPat() : formatIdentifyHint();
30717
+ ].join("\n") : isLikelyAiDialogueDirectory(targetDir) ? formatAiDialogueDirectoryHint(targetDir) : pat ? await formatAutoProjectListFromPat() : formatIdentifyHint();
30563
30718
  return [
30564
30719
  "TapTap Maker MCP status",
30565
30720
  "",
@@ -30576,6 +30731,8 @@ async function formatStatus(options = {}) {
30576
30731
  "",
30577
30732
  formatGitEnvironmentStatus(git),
30578
30733
  "",
30734
+ formatMakerGitDirectoryStatus(gitDirectoryStatus),
30735
+ "",
30579
30736
  pat ? "" : ["Auth next step", "", `Maker PAT 缺失。PAT 页面:${makerPatTokensUrl}`].join("\n"),
30580
30737
  "",
30581
30738
  tapAuthRefreshText,
@@ -30587,6 +30744,41 @@ async function formatStatus(options = {}) {
30587
30744
  projectSection
30588
30745
  ].filter(Boolean).join("\n");
30589
30746
  }
30747
+ function formatMakerGitDirectoryStatus(status) {
30748
+ return [
30749
+ "Maker Git directory",
30750
+ "",
30751
+ `- status: ${status.isUsableMakerGitRepo ? "ready" : status.issue || "unbound"}`,
30752
+ `- target_dir: ${status.targetDir}`,
30753
+ status.makerProjectRoot ? `- maker_project_root: ${status.makerProjectRoot}` : "",
30754
+ status.gitRoot ? `- git_root: ${status.gitRoot}` : "- git_root: (none)",
30755
+ status.gitDir ? `- git_dir: ${status.gitDir}` : "",
30756
+ `- target_is_git_root: ${status.isOwnGitRoot ? "yes" : "no"}`,
30757
+ `- usable_for_build_submit: ${status.isUsableMakerGitRepo ? "yes" : "no"}`,
30758
+ status.message ? `- warning: ${status.message}` : "",
30759
+ status.issue === "inside_parent_git_repo" ? "- recommendation: 当前目录位于外层 Git 仓库下,但不是独立 Maker Git 仓库;建议新开独立目录重新 clone,或重新执行 clone 让当前目录创建自己的 .git。" : ""
30760
+ ].filter(Boolean).join("\n");
30761
+ }
30762
+ function isLikelyAiDialogueDirectory(targetDir) {
30763
+ const normalized = targetDir.replace(/\\/g, "/").toLowerCase();
30764
+ if (normalized.includes("/xdt-maker/dialogues/")) {
30765
+ return true;
30766
+ }
30767
+ return /(^|\/)dialogues\/\d{4}-\d{2}-\d{2}\/[0-9a-f]{8}-[0-9a-f-]{13,}$/i.test(normalized);
30768
+ }
30769
+ function formatAiDialogueDirectoryHint(targetDir) {
30770
+ return [
30771
+ "AI client workspace selection",
30772
+ "",
30773
+ `- current_target_dir: ${targetDir}`,
30774
+ "- detected_issue: current directory looks like an AI dialogue/session directory, not a Maker project directory.",
30775
+ "- do_not_clone_here: yes",
30776
+ "- next_step: inspect the AI client attached/extra workspace directories and choose the Maker project directory.",
30777
+ '- if_single_attached_workspace: call maker_status(target_dir="<attached project directory>") directly.',
30778
+ "- if_multiple_attached_workspaces: show the directories to the user and ask which one is the Maker project.",
30779
+ "- do_not_show_app_selection_here: yes"
30780
+ ].join("\n");
30781
+ }
30590
30782
  function resolveMakerToolTargetDir(targetDir) {
30591
30783
  if (targetDir) {
30592
30784
  return path7.resolve(targetDir);
@@ -30705,6 +30897,33 @@ function formatCloneWarnings(warnings) {
30705
30897
  ""
30706
30898
  ];
30707
30899
  }
30900
+ function formatClonePartialStateLines(targetDir) {
30901
+ const resolvedTargetDir = path7.resolve(targetDir);
30902
+ const identify = identifyMakerProject({ cwd: resolvedTargetDir });
30903
+ const gitStatus = inspectMakerDirectoryGitStatus(resolvedTargetDir);
30904
+ const devKitStatus = inspectAiDevKit(resolvedTargetDir);
30905
+ const stagedDevKitGitignorePath = path7.join(resolvedTargetDir, DEV_KIT_GITIGNORE_STAGING_FILE);
30906
+ const projectBound = Boolean(identify.projectId);
30907
+ const gitInitialized = Boolean(
30908
+ gitStatus.isOwnGitRoot || fs6.existsSync(path7.join(resolvedTargetDir, ".git"))
30909
+ );
30910
+ const safeToRetry = !projectBound;
30911
+ return [
30912
+ "partial_state:",
30913
+ `- target_dir: ${resolvedTargetDir}`,
30914
+ `- git_initialized: ${gitInitialized ? "yes" : "no"}`,
30915
+ gitStatus.gitRoot ? `- git_root: ${gitStatus.gitRoot}` : "- git_root: (none)",
30916
+ `- target_is_git_root: ${gitStatus.isOwnGitRoot ? "yes" : "no"}`,
30917
+ `- project_bound: ${projectBound ? "yes" : "no"}`,
30918
+ identify.projectId ? `- project_id: ${identify.projectId}` : "",
30919
+ identify.configPath ? `- config: ${identify.configPath}` : "",
30920
+ `- ai_dev_kit_present: ${devKitStatus.ready ? "yes" : "no"}`,
30921
+ `- ai_dev_kit_missing_entries: ${devKitStatus.missingEntries.join(", ") || "(none)"}`,
30922
+ `- staged_dev_kit_gitignore: ${fs6.existsSync(stagedDevKitGitignorePath) ? "yes" : "no"}`,
30923
+ `- safe_to_retry: ${safeToRetry ? "yes" : "no"}`,
30924
+ safeToRetry ? "- next_step: 可以直接重试 maker_clone_to_current_directory;如果连续失败,建议换一个全新的独立目录重新 clone。" : "- next_step: 当前目录已经有 Maker 绑定信息;先运行 maker_status 确认状态,不要重复 clone。"
30925
+ ].filter(Boolean);
30926
+ }
30708
30927
  function createRemoteProxyContext(options) {
30709
30928
  const identify = identifyMakerProject({ cwd: options.targetDir });
30710
30929
  if (!identify.projectRoot || !identify.projectId) {
@@ -30914,7 +31133,12 @@ async function buildCurrentDirectory(options) {
30914
31133
  buildLocalChangesPolicy
30915
31134
  };
30916
31135
  }
30917
- throw new Error(formatLocalChangesBeforeBuildMessage(localChanges.files));
31136
+ throw new Error(
31137
+ formatLocalChangesBeforeBuildMessage(localChanges.files, {
31138
+ ahead: localChanges.ahead,
31139
+ hasUnpushedCommits: localChanges.hasUnpushedCommits
31140
+ })
31141
+ );
30918
31142
  }
30919
31143
  return runRemoteBuildCurrentDirectory(options, options.targetDir);
30920
31144
  }
@@ -31024,7 +31248,7 @@ function toMakerBuildFailure(error2) {
31024
31248
  ...error2 instanceof Error && error2.stack ? { stack: error2.stack } : {}
31025
31249
  };
31026
31250
  }
31027
- function formatLocalChangesBeforeBuildMessage(files) {
31251
+ function formatLocalChangesBeforeBuildMessage(files, options = {}) {
31028
31252
  const visibleFiles = files.slice(0, 20);
31029
31253
  const hiddenCount = Math.max(0, files.length - visibleFiles.length);
31030
31254
  return [
@@ -31035,10 +31259,14 @@ function formatLocalChangesBeforeBuildMessage(files) {
31035
31259
  "- 提交本地改动并触发构建(以后都是如此):再次调用 maker_build_current_directory,并设置 submit_local_changes_before_build=true 和 remember_build_submit_preference=true;工具会先 commit + push,再继续执行远端 build 并返回构建结果。后续构建遇到本地改动会默认自动提交并继续构建。",
31036
31260
  "- 如果用户明确说不提交、直接构建云端版本,再调用 maker_build_current_directory,并设置 confirm_remote_build_without_submit=true。",
31037
31261
  "",
31262
+ options.hasUnpushedCommits ? `unpushed_commits: ${options.ahead || "yes"}` : "",
31263
+ options.hasUnpushedCommits ? "note: 本地已有 commit 还没有推送到 Maker 远端;需要先 push,远端构建才会包含这些改动。" : "",
31264
+ options.hasUnpushedCommits ? "" : "",
31038
31265
  "local_changes:",
31039
31266
  ...visibleFiles.map((file2) => `- ${file2}`),
31267
+ visibleFiles.length === 0 ? "- (none)" : "",
31040
31268
  ...hiddenCount > 0 ? [`- ... and ${hiddenCount} more`] : []
31041
- ].join("\n");
31269
+ ].filter((line) => line !== "").join("\n");
31042
31270
  }
31043
31271
  function createBuildArgs(projectRoot, options) {
31044
31272
  const buildArgs = {};
@@ -31111,7 +31339,12 @@ function formatBuildResult(result, progressSummary) {
31111
31339
  ...formatProgressSummary(progressSummary),
31112
31340
  "",
31113
31341
  "note: Maker build was not started because submit did not produce a pushed state.",
31114
- ...result.submitResult.failure ? ["", ...formatMakerFailureLines(result.submitResult.failure)] : []
31342
+ ...result.submitResult.failure ? [
31343
+ "",
31344
+ ...formatPushRecoveryLines(result.submitResult),
31345
+ "",
31346
+ ...formatMakerFailureLines(result.submitResult.failure)
31347
+ ] : []
31115
31348
  ].filter(Boolean).join("\n");
31116
31349
  }
31117
31350
  if (result.mode === "build_failed_after_submit") {
@@ -31216,7 +31449,29 @@ function formatPushResult(targetDir, result, progressSummary) {
31216
31449
  submitResult.pushed ? "note: This is an internal contract error: pushed=true requires remote_build or build_failure." : "note: Maker build was not started because no push was performed."
31217
31450
  ].join("\n");
31218
31451
  }
31219
- return [...lines, "", ...formatMakerFailureLines(submitResult.failure)].filter(Boolean).join("\n");
31452
+ return [
31453
+ ...lines,
31454
+ "",
31455
+ ...formatPushRecoveryLines(submitResult),
31456
+ "",
31457
+ ...formatMakerFailureLines(submitResult.failure)
31458
+ ].filter(Boolean).join("\n");
31459
+ }
31460
+ function formatPushRecoveryLines(submitResult) {
31461
+ if (submitResult.pushed || submitResult.status !== "failed_after_commit") {
31462
+ return [];
31463
+ }
31464
+ return [
31465
+ "push_recovery:",
31466
+ "- committed_but_unpushed: yes",
31467
+ submitResult.commitHash ? `- local_commit: ${submitResult.commitHash}` : "",
31468
+ submitResult.ahead ? `- git_state: ${submitResult.ahead}` : "",
31469
+ "- retry_tool: maker_submit_current_directory",
31470
+ "- retry_build_tool: maker_build_current_directory",
31471
+ "- retry_build_args: submit_local_changes_before_build=true",
31472
+ "- do_not_use_generic_git_push: yes",
31473
+ "- user_message: 本地提交已经保留,但还没推送到 Maker 远端;直接重试 Maker 提交/构建工具即可。"
31474
+ ].filter(Boolean);
31220
31475
  }
31221
31476
  function formatMakerBuildFailureLines(failure) {
31222
31477
  return [
@@ -31256,6 +31511,24 @@ function formatToolException(toolName, error2) {
31256
31511
  "next_action: 请只引导用户安装 Git;在 `git --version` 可用之前,不要继续调用 clone、fetch、commit 或 push。"
31257
31512
  ].join("\n");
31258
31513
  }
31514
+ if (error2 instanceof MakerCloneFailedError) {
31515
+ const original = error2.originalError;
31516
+ const originalStack = original instanceof Error ? original.stack : void 0;
31517
+ return [
31518
+ "✗ Maker MCP tool failed",
31519
+ "",
31520
+ `- tool: ${toolName}`,
31521
+ `- error_name: ${original instanceof Error ? original.name : typeof original}`,
31522
+ `- message: ${message}`,
31523
+ "",
31524
+ ...formatClonePartialStateLines(error2.targetDir),
31525
+ "",
31526
+ "debug:",
31527
+ originalStack ? indent(originalStack) : indent(message),
31528
+ "",
31529
+ "next_action: 请根据 partial_state 判断是否直接重试;不要删除用户文件。若用户不懂目录状态,优先建议新建独立目录重新 clone。"
31530
+ ].join("\n");
31531
+ }
31259
31532
  return [
31260
31533
  "✗ Maker MCP tool failed",
31261
31534
  "",
package/dist/proxy.js CHANGED
@@ -29137,7 +29137,7 @@ var LogWriter = class {
29137
29137
  };
29138
29138
 
29139
29139
  // src/mcp-proxy/proxy.ts
29140
- var VERSION = true ? "1.23.1" : "dev";
29140
+ var VERSION = true ? "1.23.2" : "dev";
29141
29141
  var TapTapMCPProxy = class {
29142
29142
  constructor(config2) {
29143
29143
  this.connected = false;
package/dist/server.js CHANGED
@@ -6078,7 +6078,7 @@ class MultiplayerManager {
6078
6078
  // 导出
6079
6079
  // export default MultiplayerManager;
6080
6080
  // module.exports = MultiplayerManager;
6081
- // window.MultiplayerManager = MultiplayerManager;`}]}}};var ws;ws="1.23.1";async function MRe(){return Go(Rm,"api_event_relations")}async function NRe(){return Go(Rm,"protocol_template")}async function SD(){return Go(Rm,"complete_example")}async function jRe(){return`# TapTap 多人联机集成指南
6081
+ // window.MultiplayerManager = MultiplayerManager;`}]}}};var ws;ws="1.23.2";async function MRe(){return Go(Rm,"api_event_relations")}async function NRe(){return Go(Rm,"protocol_template")}async function SD(){return Go(Rm,"complete_example")}async function jRe(){return`# TapTap 多人联机集成指南
6082
6082
 
6083
6083
  ---
6084
6084
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taptap/instant-games-open-mcp",
3
- "version": "1.23.1",
3
+ "version": "1.23.2",
4
4
  "type": "module",
5
5
  "description": "TapTap Open API MCP Server - Documentation and Management APIs for TapTap Minigame and H5 Games (Leaderboard, and more features coming)",
6
6
  "main": "dist/server.js",
@@ -36,3 +36,16 @@ dev-kit entries when possible.
36
36
 
37
37
  These files are local development aids. Do not submit them to Maker Git unless the user explicitly
38
38
  asks and understands they are local environment files.
39
+
40
+ ## Testing And Result Check
41
+
42
+ Keep validation simple for Maker users. 用户可以直接说“提交”或“构建”:
43
+
44
+ - If the user says “提交”, use the Maker submit flow so local changes are committed, pushed, and
45
+ built by the Maker MCP tools.
46
+ - If the user says “构建”, use the Maker build flow. If the tool reports local changes, follow the
47
+ options returned by the tool instead of inventing a separate build script.
48
+ - After submit or build finishes, tell the user to open the TapMaker 网页端查看结果.
49
+
50
+ Do not create local-only test scripts just to verify Maker changes. The expected validation path is
51
+ chat request -> Maker MCP submit/build tool -> TapMaker web result check.
@@ -68,6 +68,22 @@ dialogue/session directory, pass the user's current project directory as `target
68
68
  client does not expose that directory, say the current client did not provide the project directory
69
69
  instead of guessing.
70
70
 
71
+ ### Attached Workspace Selection
72
+
73
+ Some AI clients start MCP from a dialogue/session directory and expose the real project as an
74
+ attached workspace. For Maker status, clone, submit, and build, compare:
75
+
76
+ - the AI dialogue current directory, often containing `dialogues`
77
+ - the attached workspace directories shown by the client
78
+
79
+ If there is a single attached workspace, use that single attached workspace as `target_dir` when
80
+ calling Maker tools. If there are multiple attached workspaces, show the paths and ask the user
81
+ which one is the Maker project directory. Do not treat the dialogue/session directory as the Maker
82
+ project directory, and do not ask the user to clone an app into that directory.
83
+
84
+ If `maker_status` returns `AI client workspace selection`, follow that hint: choose an attached
85
+ workspace first, then call `maker_status(target_dir="<attached project directory>")`.
86
+
71
87
  ## Initialization Workflow
72
88
 
73
89
  Trigger phrases include:
@@ -97,7 +113,7 @@ Workflow:
97
113
  7. If the current directory is still unbound, show every returned Maker app entry to the user and
98
114
  ask the user to choose. Do not summarize the list as only a count, category, or stage. Do not
99
115
  auto-select, even if there is only one app.
100
- 8. Run the working directory compliance check below.
116
+ 8. Run the working directory compliance check below, including the parent Git repository warning.
101
117
  9. After the user chooses an app, call `maker_clone_to_current_directory(app_id)`. The clone
102
118
  tool prepares the AI dev kit automatically before project checkout.
103
119
  10. After clone succeeds, call `maker_status` again or explain that `.maker-mcp/config.json` now binds the directory to the Maker project.
@@ -185,6 +201,25 @@ After the user chooses, pass the concrete `app_id` to `maker_clone_to_current_di
185
201
 
186
202
  ## Working Directory Compliance Check
187
203
 
204
+ Before every clone attempt, call `maker_status(target_dir)` for the user's intended Maker
205
+ development directory. Use that result as the source of truth for Git availability, existing Maker
206
+ binding, outer Git repository detection, and AI dev-kit status.
207
+
208
+ ### Directory Suitability Decision
209
+
210
+ After `maker_status(target_dir)`, decide whether the directory is suitable for clone:
211
+
212
+ - If the directory is already bound to a Maker project, do not clone again unless the user
213
+ explicitly asks to switch or re-clone.
214
+ - If Git is missing, stop and tell the user to install Git first.
215
+ - If `Maker Git directory` reports `inside_parent_git_repo` or `target_is_git_root: no` with an
216
+ outer `git_root`, explain that the directory is under another Git repository. Recommend a
217
+ completely independent directory, such as `~/MakerProjects/<game-name>`.
218
+ - If the directory is unbound and only contains ignored local config folders, continue after the
219
+ user chooses an app.
220
+ - If the directory contains ordinary user files or folders, explain that Maker clone keeps local
221
+ files but may stop on path conflicts. Ask whether to continue here or switch to a clean directory.
222
+
188
223
  Before clone, inspect only the current directory top level.
189
224
  The goal is to avoid surprising overwrites, not to deeply audit game code.
190
225
 
@@ -202,6 +237,17 @@ If the directory contains ordinary user files or folders, explain that Maker ini
202
237
  keep local files, but clone can fail if a local path conflicts with the Maker project. Ask whether
203
238
  to continue in this directory or switch to a clean directory.
204
239
 
240
+ If the current directory is inside a larger Git repository but is not itself a Git root, warn the
241
+ user before clone:
242
+
243
+ - The outer repository may be an existing user project.
244
+ - A Maker project can live under that directory only if the Maker directory gets its own `.git`.
245
+ - Recommend a completely independent directory, such as `~/MakerProjects/<game-name>`, for safer
246
+ local development.
247
+ - If the user explicitly continues, call `maker_clone_to_current_directory`; the MCP clone tool
248
+ must initialize an independent Maker Git repository in the target directory and must not modify
249
+ the outer repository remote.
250
+
205
251
  Do not delete, move, or overwrite user files during this check.
206
252
 
207
253
  ## Clone Directory Safety
@@ -216,6 +262,20 @@ may create local-only files before clone, so explain this in non-technical terms
216
262
 
217
263
  Do not delete or overwrite user files to make clone work unless the user explicitly asks.
218
264
 
265
+ If `maker_clone_to_current_directory` fails and the tool returns `partial_state`, explain the
266
+ state in plain language:
267
+
268
+ - `project_bound: no` usually means clone did not finish; retrying clone is allowed.
269
+ - `git_initialized: yes` with `project_bound: no` means the directory may contain a partial local
270
+ Git setup; retry once, and if it fails again recommend a fresh independent directory.
271
+ - `ai_dev_kit_present: yes` means local AI docs/examples may already be present even though Maker
272
+ project checkout failed.
273
+ - `project_bound: yes` means the directory already has Maker binding; run `maker_status` before
274
+ attempting anything else.
275
+
276
+ Do not delete partial files automatically. For novice users, prefer recommending a new independent
277
+ directory over manual cleanup.
278
+
219
279
  ### `.gitignore` Merge During Clone
220
280
 
221
281
  The Maker clone tool stages the dev-kit managed ignore block in
@@ -278,6 +338,21 @@ If `maker_submit_current_directory` returns a build failure after a successful p
278
338
  - submit/push succeeded
279
339
  - build failed, with the concrete build error
280
340
 
341
+ If submit created a local commit but push failed because the Maker remote was temporarily
342
+ unavailable, do not run a manual generic `git push`. Tell the user to retry
343
+ `maker_submit_current_directory`, or use `maker_build_current_directory` with
344
+ `submit_local_changes_before_build=true` when the user is retrying build. Maker MCP will detect
345
+ committed-but-unpushed local commits and push them before build.
346
+
347
+ When a Maker tool output contains `push_recovery`, follow it exactly:
348
+
349
+ - Tell the user the local commit is preserved but not yet on Maker remote.
350
+ - Do not ask for permission to run a generic `git push`.
351
+ - Retry with `maker_submit_current_directory` for submit requests.
352
+ - Retry with `maker_build_current_directory(submit_local_changes_before_build=true)` for build
353
+ requests.
354
+ - If the failure is `remote_rejected`, ask before pull/rebase; do not create a new branch or PR.
355
+
281
356
  ## Pull And Conflict Handling
282
357
 
283
358
  Before pulling: