@taptap/instant-games-open-mcp 1.23.0 → 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
@@ -28711,6 +28711,14 @@ var DEV_KIT_IGNORE_BEGIN = "# >>> TapTap Maker AI dev kit (local only) >>>";
28711
28711
  var DEV_KIT_IGNORE_END = "# <<< TapTap Maker AI dev kit (local only) <<<";
28712
28712
  var DEV_KIT_GITIGNORE_STAGING_FILE = ".gitignore.dev-kit-before-clone";
28713
28713
  var DEV_KIT_REQUIRED_ENTRIES = ["CLAUDE.md", "examples", "templates", "urhox-libs"];
28714
+ var DEV_KIT_MANAGED_ENTRY_CANDIDATES = [
28715
+ ".emmylua",
28716
+ "CLAUDE.md",
28717
+ "engine-docs",
28718
+ "examples",
28719
+ "templates",
28720
+ "urhox-libs"
28721
+ ];
28714
28722
  var SKIPPED_TOP_LEVEL_ENTRIES = /* @__PURE__ */ new Set(["scripts", ".DS_Store", "ai-dev-kit.zip"]);
28715
28723
  function inspectAiDevKit(targetDir) {
28716
28724
  const resolvedTargetDir = path4.resolve(targetDir);
@@ -28728,6 +28736,12 @@ function inspectAiDevKit(targetDir) {
28728
28736
  ready: missingEntries.length === 0
28729
28737
  };
28730
28738
  }
28739
+ function listPresentDevKitManagedEntries(targetDir) {
28740
+ const resolvedTargetDir = path4.resolve(targetDir);
28741
+ return DEV_KIT_MANAGED_ENTRY_CANDIDATES.filter(
28742
+ (entry) => fs3.existsSync(path4.join(resolvedTargetDir, entry))
28743
+ );
28744
+ }
28731
28745
  async function installAiDevKit(options = {}) {
28732
28746
  const targetDir = path4.resolve(options.targetDir || ".");
28733
28747
  fs3.mkdirSync(targetDir, { recursive: true });
@@ -28824,7 +28838,7 @@ async function downloadAndExtractDevKit(url2) {
28824
28838
  }
28825
28839
  function extractZip(zipPath, targetDir) {
28826
28840
  if (process.platform === "win32") {
28827
- const result2 = spawnSync2(
28841
+ const result = spawnSync2(
28828
28842
  "powershell.exe",
28829
28843
  [
28830
28844
  "-NoProfile",
@@ -28838,15 +28852,52 @@ function extractZip(zipPath, targetDir) {
28838
28852
  ],
28839
28853
  { encoding: "utf8" }
28840
28854
  );
28841
- if (result2.status !== 0) {
28842
- throw new Error(`Failed to extract AI dev kit zip: ${result2.stderr || result2.stdout}`);
28855
+ if (result.status !== 0) {
28856
+ throw new Error(`Failed to extract AI dev kit zip: ${formatSpawnFailure(result)}`);
28843
28857
  }
28844
28858
  return;
28845
28859
  }
28846
- const result = spawnSync2("unzip", ["-q", zipPath, "-d", targetDir], { encoding: "utf8" });
28847
- if (result.status !== 0) {
28848
- throw new Error(`Failed to extract AI dev kit zip: ${result.stderr || result.stdout}`);
28860
+ const unzipResult = spawnSync2("unzip", ["-q", zipPath, "-d", targetDir], { encoding: "utf8" });
28861
+ if (unzipResult.status === 0) {
28862
+ return;
28863
+ }
28864
+ const pythonFailures = [];
28865
+ for (const pythonCommand of ["python3", "python"]) {
28866
+ const pythonResult = spawnSync2(
28867
+ pythonCommand,
28868
+ ["-c", PYTHON_ZIP_EXTRACT_SCRIPT, zipPath, targetDir],
28869
+ { encoding: "utf8" }
28870
+ );
28871
+ if (pythonResult.status === 0) {
28872
+ return;
28873
+ }
28874
+ pythonFailures.push(`${pythonCommand}: ${formatSpawnFailure(pythonResult)}`);
28849
28875
  }
28876
+ throw new Error(
28877
+ [
28878
+ `Failed to extract AI dev kit zip: unzip: ${formatSpawnFailure(unzipResult)}`,
28879
+ ...pythonFailures
28880
+ ].join("; ")
28881
+ );
28882
+ }
28883
+ var PYTHON_ZIP_EXTRACT_SCRIPT = String.raw`
28884
+ import os
28885
+ import sys
28886
+ import zipfile
28887
+
28888
+ zip_path = sys.argv[1]
28889
+ target_dir = os.path.abspath(sys.argv[2])
28890
+
28891
+ with zipfile.ZipFile(zip_path) as archive:
28892
+ for member in archive.infolist():
28893
+ destination = os.path.abspath(os.path.join(target_dir, member.filename))
28894
+ if os.path.commonpath([target_dir, destination]) != target_dir:
28895
+ raise RuntimeError("Blocked unsafe zip entry: " + member.filename)
28896
+ archive.extractall(target_dir)
28897
+ `;
28898
+ function formatSpawnFailure(result) {
28899
+ var _a2;
28900
+ return ((_a2 = result.error) == null ? void 0 : _a2.message) || String(result.stderr || "").trim() || String(result.stdout || "").trim() || `exit status ${result.status ?? "unknown"}`;
28850
28901
  }
28851
28902
  function resolveDevKitRoot(sourceDir) {
28852
28903
  const directEntries = fs3.existsSync(sourceDir) ? fs3.readdirSync(sourceDir) : [];
@@ -29008,7 +29059,7 @@ async function cloneMakerProject(options) {
29008
29059
  let authUrl = makeAuthenticatedGitUrl(gitUrl, pat.token);
29009
29060
  let retriedWithNewPat = false;
29010
29061
  let transientRetries = 0;
29011
- if (isGitRepo(target) && hasGitHead(target)) {
29062
+ if (isOwnGitRoot(target) && hasGitHead(target)) {
29012
29063
  (_d = options.onProgress) == null ? void 0 : _d.call(options, {
29013
29064
  progress: 10,
29014
29065
  total: 100,
@@ -29061,7 +29112,7 @@ async function cloneMakerProject(options) {
29061
29112
  warnings
29062
29113
  };
29063
29114
  }
29064
- if (isGitRepo(target)) {
29115
+ if (isOwnGitRoot(target)) {
29065
29116
  warnings.push(
29066
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."
29067
29118
  );
@@ -29107,6 +29158,7 @@ async function cloneMakerProject(options) {
29107
29158
  }
29108
29159
  try {
29109
29160
  ensureGitHeadCheckedOut(target);
29161
+ ensureOwnGitRoot(target);
29110
29162
  } catch (error2) {
29111
29163
  throw withPreCloneWarnings(error2, warnings);
29112
29164
  }
@@ -29140,14 +29192,9 @@ async function pushMakerProject(options) {
29140
29192
  phase: "prepare",
29141
29193
  message: "Preparing Maker project push"
29142
29194
  });
29143
- const cwd = path5.resolve(options.cwd);
29144
- if (!isGitRepo(cwd)) {
29145
- throw new Error(`${cwd} is not a git repository.`);
29146
- }
29147
- const configPath = path5.join(cwd, ".maker-mcp", "config.json");
29148
- if (!fs4.existsSync(configPath)) {
29149
- throw new Error(`${cwd} is not bound to a Maker project. .maker-mcp/config.json is missing.`);
29150
- }
29195
+ const requestedCwd = path5.resolve(options.cwd);
29196
+ const workspace = resolveUsableMakerGitWorkspace(requestedCwd);
29197
+ const cwd = workspace.projectRoot;
29151
29198
  const project = loadProjectConfig(cwd);
29152
29199
  if (!(project == null ? void 0 : project.project_id)) {
29153
29200
  throw new Error(`${cwd} Maker project config does not contain project_id.`);
@@ -29168,7 +29215,8 @@ async function pushMakerProject(options) {
29168
29215
  });
29169
29216
  const statusBefore = await readGit(["status", "--porcelain"], cwd);
29170
29217
  const branch = await currentBranch(cwd, options.branch);
29171
- if (!statusBefore.trim() && !options.allowEmpty) {
29218
+ const unpushed = await readUnpushedCommitState(cwd, branch);
29219
+ if (!statusBefore.trim() && !options.allowEmpty && !unpushed.hasUnpushedCommits) {
29172
29220
  (_c = options.onProgress) == null ? void 0 : _c.call(options, {
29173
29221
  progress: 100,
29174
29222
  total: 100,
@@ -29183,7 +29231,12 @@ async function pushMakerProject(options) {
29183
29231
  status: "clean"
29184
29232
  };
29185
29233
  }
29186
- 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) {
29187
29240
  (_e = options.onProgress) == null ? void 0 : _e.call(options, {
29188
29241
  progress: 20,
29189
29242
  total: 100,
@@ -29199,33 +29252,31 @@ async function pushMakerProject(options) {
29199
29252
  message: "Staging all local changes"
29200
29253
  });
29201
29254
  await runGit(["add", "-A"], { cwd });
29202
- }
29203
- const staged = await readGit(["diff", "--cached", "--name-only"], cwd);
29204
- let committed = false;
29205
- let commitHash;
29206
- const message = options.message || generateCommitMessage(statusBefore);
29207
- if (staged.trim() || options.allowEmpty) {
29208
- (_g = options.onProgress) == null ? void 0 : _g.call(options, {
29209
- progress: 45,
29210
- total: 100,
29211
- phase: "commit",
29212
- message: "Creating local Maker project commit"
29213
- });
29214
- await runGit(
29215
- [
29216
- "-c",
29217
- "user.email=maker-mcp@local",
29218
- "-c",
29219
- "user.name=taptap-maker",
29220
- "commit",
29221
- ...options.allowEmpty ? ["--allow-empty"] : [],
29222
- "-m",
29223
- message
29224
- ],
29225
- { cwd }
29226
- );
29227
- committed = true;
29228
- 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
+ }
29229
29280
  }
29230
29281
  try {
29231
29282
  (_h = options.onProgress) == null ? void 0 : _h.call(options, {
@@ -29243,7 +29294,7 @@ async function pushMakerProject(options) {
29243
29294
  commitHash,
29244
29295
  message,
29245
29296
  pushed: false,
29246
- status: committed ? "failed_after_commit" : "clean",
29297
+ status: committed || unpushed.hasUnpushedCommits ? "failed_after_commit" : "clean",
29247
29298
  failure,
29248
29299
  ahead: await readAheadState(cwd)
29249
29300
  };
@@ -29265,28 +29316,23 @@ async function pushMakerProject(options) {
29265
29316
  }
29266
29317
  async function readMakerProjectLocalChanges(cwd) {
29267
29318
  ensureGitAvailable();
29268
- const requestedDir = path5.resolve(cwd);
29269
- if (!isGitRepo(requestedDir)) {
29270
- throw new Error(`${requestedDir} is not a git repository.`);
29271
- }
29272
- const projectRoot = (await readGit(["rev-parse", "--show-toplevel"], requestedDir)).trim();
29273
- const configPath = path5.join(projectRoot, ".maker-mcp", "config.json");
29274
- if (!fs4.existsSync(configPath)) {
29275
- throw new Error(
29276
- `${projectRoot} is not bound to a Maker project. .maker-mcp/config.json is missing.`
29277
- );
29278
- }
29319
+ const { projectRoot } = resolveUsableMakerGitWorkspace(cwd);
29279
29320
  const rawStatus = await readGit(["status", "--porcelain", "-z"], projectRoot);
29280
- const files = parseGitStatusFiles(rawStatus).filter(
29281
- (file2) => file2 !== ".maker-mcp" && !file2.startsWith(".maker-mcp/")
29282
- );
29321
+ const files = parseGitStatusFiles(rawStatus).filter((file2) => !isIgnoredBuildGuardChange(file2));
29322
+ const branch = await currentBranch(projectRoot);
29323
+ const unpushed = await readUnpushedCommitState(projectRoot, branch);
29283
29324
  return {
29284
- hasChanges: files.length > 0,
29325
+ hasChanges: files.length > 0 || unpushed.hasUnpushedCommits,
29285
29326
  projectRoot,
29286
29327
  files,
29287
- rawStatus
29328
+ rawStatus,
29329
+ hasUnpushedCommits: unpushed.hasUnpushedCommits,
29330
+ ahead: unpushed.ahead
29288
29331
  };
29289
29332
  }
29333
+ function isIgnoredBuildGuardChange(file2) {
29334
+ return file2 === ".gitignore" || file2 === ".maker-mcp" || file2.startsWith(".maker-mcp/");
29335
+ }
29290
29336
  function ensureTargetCanBindApp(target, appId) {
29291
29337
  const existingConfig = loadProjectConfig(target);
29292
29338
  if (!(existingConfig == null ? void 0 : existingConfig.project_id) || existingConfig.project_id === appId) {
@@ -29342,6 +29388,28 @@ async function readAheadState(cwd) {
29342
29388
  return void 0;
29343
29389
  }
29344
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
+ }
29345
29413
  function toMakerGitFailure(error2, stage) {
29346
29414
  if (error2 instanceof MakerGitError) {
29347
29415
  return error2.failure;
@@ -29399,13 +29467,13 @@ function nextActionForFailure(classification) {
29399
29467
  case "auth":
29400
29468
  return "刷新 Maker PAT 后重试 maker_submit_current_directory;如果仍失败,请确认 PAT 是否过期或缺少 Maker git 权限。";
29401
29469
  case "remote_transient":
29402
- 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。";
29403
29471
  case "remote_rejected":
29404
- return "远端已有新提交。不要新建分支或要任务号,先询问用户是否 pull/rebase 当前 Maker 远端变更,再重试 push。";
29472
+ return "远端已有新提交。不要新建分支、不要要任务号、不要手动执行通用 git push;先询问用户是否 pull/rebase 当前 Maker 远端变更,再重试 maker_submit_current_directory。";
29405
29473
  case "local":
29406
29474
  return "本地目录或权限异常。检查当前目录是否是 Maker git repo,以及 Codex 是否有目录写权限。";
29407
29475
  default:
29408
- return "保留本地提交,不要重复提交;把错误详情反馈给用户,并在确认后重试 push。";
29476
+ return "保留本地提交,不要重复提交;把错误详情反馈给用户,并在确认后重试 maker_submit_current_directory。";
29409
29477
  }
29410
29478
  }
29411
29479
  function pushGit(args, cwd, onProgress) {
@@ -29667,12 +29735,139 @@ async function assertNoCheckoutFileConflicts(cwd, branch) {
29667
29735
  async function setOrigin(cwd, authUrl) {
29668
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 }));
29669
29737
  }
29670
- 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) {
29671
29848
  try {
29672
- const gitDir = readGitSync(["-C", repoDir, "rev-parse", "--git-dir"]);
29673
- return gitDir.trim().length > 0;
29849
+ return path5.resolve(readGitSync(["-C", cwd, "rev-parse", "--show-toplevel"]).trim());
29674
29850
  } catch {
29675
- 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;
29676
29871
  }
29677
29872
  }
29678
29873
  function hasGitHead(repoDir) {
@@ -30031,14 +30226,23 @@ function getBundledSkillSourceDir(skillName) {
30031
30226
  }
30032
30227
 
30033
30228
  // src/maker/server/mcp.ts
30034
- var VERSION = true ? "1.23.0" : "dev";
30229
+ var VERSION = true ? "1.23.2" : "dev";
30035
30230
  var DEFAULT_PROXY_PACKAGE = "@taptap/instant-games-open-mcp@1.22.0";
30036
30231
  var DEFAULT_BUILD_TIMEOUT_MS = 10 * 60 * 1e3;
30037
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
+ };
30038
30242
  var tools = [
30039
30243
  {
30040
30244
  name: "maker_exchange_pat",
30041
- description: "Save a Maker PAT for local Maker API, Git, and TapTap token operations. After saving PAT, this tool fetches TapTap token and lists available Maker apps.",
30245
+ description: "Save a Maker PAT for local Maker API, Git, and TapTap token operations. After saving PAT, this tool fetches TapTap token and returns a user-facing Maker app list. If the current directory is unbound, show every returned app entry to the user and ask them to choose; do not summarize the list as a count only.",
30042
30246
  inputSchema: {
30043
30247
  type: "object",
30044
30248
  properties: {
@@ -30052,7 +30256,7 @@ var tools = [
30052
30256
  },
30053
30257
  {
30054
30258
  name: "maker_list_apps",
30055
- description: "List Maker apps available to the cached or provided Maker PAT. Use this for unbound Maker directory initialization or explicit app-list requests. If maker_status already reports the current directory is bound, treat this list as reference only and do not ask which app to clone unless the user explicitly wants to switch or re-clone.",
30259
+ description: "List Maker apps available to the cached or provided Maker PAT. Use this for unbound Maker directory initialization or explicit app-list requests. If the current directory is unbound, show every returned app entry to the user and ask them to choose; do not summarize the list as a count only. If maker_status already reports the current directory is bound, treat this list as reference only and do not ask which app to clone unless the user explicitly wants to switch or re-clone.",
30056
30260
  inputSchema: {
30057
30261
  type: "object",
30058
30262
  properties: {
@@ -30065,7 +30269,7 @@ var tools = [
30065
30269
  },
30066
30270
  {
30067
30271
  name: "maker_status",
30068
- description: "Show local Maker MCP status for the user current working directory: Git availability, PAT/TapTap token status, project binding, AI dev kit status, bundled skill document paths, validation checklist, and available apps when the current directory is unbound and PAT exists. If the MCP process cwd differs from the user current working directory, pass target_dir with the user current working directory.",
30272
+ description: "Show local Maker MCP status for the user current working directory: Git availability, PAT/TapTap token status, project binding, AI dev kit status, bundled skill document paths, validation checklist, and available apps when the current directory is unbound and PAT exists. If the current directory is unbound and apps are returned, show every app entry to the user; do not summarize the list as a count only. If the MCP process cwd differs from the user current working directory, pass target_dir with the user current working directory.",
30069
30273
  inputSchema: {
30070
30274
  type: "object",
30071
30275
  properties: {
@@ -30238,7 +30442,12 @@ async function startMakerMcpServer() {
30238
30442
  let nextText;
30239
30443
  try {
30240
30444
  const projects = await listMakerProjects({ pat: args.manual_pat });
30241
- nextText = ["已自动列出可用 Maker Apps:", "", formatProjectList(projects)].join("\n");
30445
+ nextText = [
30446
+ "已自动列出可用 Maker Apps。",
30447
+ "当前目录未绑定时,请逐项展示下面完整列表,不要只总结数量;然后让用户选择编号或 app_id。",
30448
+ "",
30449
+ formatProjectList(projects)
30450
+ ].join("\n");
30242
30451
  } catch (error2) {
30243
30452
  nextText = [
30244
30453
  "自动列出 Maker Apps 失败。",
@@ -30284,13 +30493,23 @@ async function startMakerMcpServer() {
30284
30493
  throw new McpError(ErrorCode.InvalidParams, "app_id is required");
30285
30494
  }
30286
30495
  const targetDir = resolveMakerToolTargetDir(args.target_dir);
30496
+ ensureGitAvailable();
30287
30497
  const progressReporter = createToolProgressReporter(
30288
30498
  (_a2 = request.params._meta) == null ? void 0 : _a2.progressToken,
30289
30499
  extra,
30290
30500
  "Maker clone"
30291
30501
  );
30292
30502
  let result;
30293
- let devKitResult;
30503
+ let devKitResult = {
30504
+ targetDir,
30505
+ sourceDir: targetDir,
30506
+ installedEntries: [],
30507
+ skippedEntries: [],
30508
+ gitignorePath: path7.join(targetDir, ".gitignore"),
30509
+ stagedGitignorePath: path7.join(targetDir, DEV_KIT_GITIGNORE_STAGING_FILE)
30510
+ };
30511
+ let devKitState = "prepared";
30512
+ let devKitError = "";
30294
30513
  let progressSummary;
30295
30514
  try {
30296
30515
  progressReporter.report({
@@ -30299,14 +30518,45 @@ async function startMakerMcpServer() {
30299
30518
  phase: "dev_kit",
30300
30519
  message: "Preparing local AI dev kit before Maker clone"
30301
30520
  });
30302
- devKitResult = await installAiDevKit({
30303
- targetDir
30304
- });
30521
+ const devKitStatus = inspectAiDevKit(targetDir);
30522
+ if (devKitStatus.ready) {
30523
+ const presentManagedEntries = listPresentDevKitManagedEntries(targetDir);
30524
+ writeDevKitStagedGitignore(
30525
+ path7.join(targetDir, DEV_KIT_GITIGNORE_STAGING_FILE),
30526
+ presentManagedEntries
30527
+ );
30528
+ devKitState = "already_ready";
30529
+ devKitResult = {
30530
+ targetDir,
30531
+ sourceDir: targetDir,
30532
+ installedEntries: presentManagedEntries,
30533
+ skippedEntries: [],
30534
+ gitignorePath: path7.join(targetDir, ".gitignore"),
30535
+ stagedGitignorePath: path7.join(targetDir, DEV_KIT_GITIGNORE_STAGING_FILE)
30536
+ };
30537
+ } else {
30538
+ try {
30539
+ devKitResult = await installAiDevKit({
30540
+ targetDir
30541
+ });
30542
+ } catch (error2) {
30543
+ const presentManagedEntries = listPresentDevKitManagedEntries(targetDir);
30544
+ if (presentManagedEntries.length > 0) {
30545
+ writeDevKitStagedGitignore(
30546
+ path7.join(targetDir, DEV_KIT_GITIGNORE_STAGING_FILE),
30547
+ presentManagedEntries
30548
+ );
30549
+ }
30550
+ devKitState = "failed_non_blocking";
30551
+ devKitError = error2 instanceof Error ? error2.message : String(error2);
30552
+ devKitResult.installedEntries = presentManagedEntries;
30553
+ }
30554
+ }
30305
30555
  progressReporter.report({
30306
30556
  progress: 5,
30307
30557
  total: 100,
30308
30558
  phase: "dev_kit",
30309
- message: "Local AI dev kit prepared"
30559
+ message: devKitState === "failed_non_blocking" ? "Local AI dev kit preparation failed; continuing Maker clone" : "Local AI dev kit prepared"
30310
30560
  });
30311
30561
  result = await cloneMakerProject({
30312
30562
  appId: args.app_id,
@@ -30319,7 +30569,7 @@ async function startMakerMcpServer() {
30319
30569
  progressSummary = progressReporter.finish();
30320
30570
  } catch (error2) {
30321
30571
  progressReporter.finish();
30322
- throw error2;
30572
+ throw new MakerCloneFailedError(targetDir, error2);
30323
30573
  }
30324
30574
  return {
30325
30575
  content: [
@@ -30333,7 +30583,11 @@ async function startMakerMcpServer() {
30333
30583
  `- target_dir: ${result.targetDir}`,
30334
30584
  `- status: ${result.status}`,
30335
30585
  `- retried_with_new_pat: ${result.retriedWithNewPat ? "yes" : "no"}`,
30336
- "- ai_dev_kit: prepared",
30586
+ `- ai_dev_kit: ${devKitState}`,
30587
+ ...devKitError ? [
30588
+ `- ai_dev_kit_error: ${devKitError}`,
30589
+ "- ai_dev_kit_next_step: run maker_status after clone to retry dev kit restoration"
30590
+ ] : [],
30337
30591
  `- ai_dev_kit_installed_entries: ${devKitResult.installedEntries.join(", ") || "(none)"}`,
30338
30592
  `- ai_dev_kit_skipped_entries: ${devKitResult.skippedEntries.join(", ") || "(none)"}`,
30339
30593
  ...formatProgressSummary(progressSummary),
@@ -30433,6 +30687,7 @@ async function formatStatus(options = {}) {
30433
30687
  var _a2;
30434
30688
  const targetDir = resolveMakerToolTargetDir(options.targetDir);
30435
30689
  const identify = identifyMakerProject({ cwd: targetDir });
30690
+ const gitDirectoryStatus = inspectMakerDirectoryGitStatus(targetDir);
30436
30691
  const pat = loadPat();
30437
30692
  let tapAuth = loadTapAuth();
30438
30693
  const makerPatTokensUrl = getMakerPatTokensUrl();
@@ -30459,7 +30714,7 @@ async function formatStatus(options = {}) {
30459
30714
  "目标目录已绑定 Maker 项目。",
30460
30715
  "请继续在当前绑定项目上执行状态、提交、构建等操作;不要再引导用户 clone,除非用户明确要求切换或重新拉取项目。",
30461
30716
  "本地 Maker 工作流请优先参考 taptap-maker-local skill;MCP tools 只负责保存 PAT、列 app、clone、submit 和 build 等机器动作。"
30462
- ].join("\n") : pat ? await formatAutoProjectListFromPat() : formatIdentifyHint();
30717
+ ].join("\n") : isLikelyAiDialogueDirectory(targetDir) ? formatAiDialogueDirectoryHint(targetDir) : pat ? await formatAutoProjectListFromPat() : formatIdentifyHint();
30463
30718
  return [
30464
30719
  "TapTap Maker MCP status",
30465
30720
  "",
@@ -30476,6 +30731,8 @@ async function formatStatus(options = {}) {
30476
30731
  "",
30477
30732
  formatGitEnvironmentStatus(git),
30478
30733
  "",
30734
+ formatMakerGitDirectoryStatus(gitDirectoryStatus),
30735
+ "",
30479
30736
  pat ? "" : ["Auth next step", "", `Maker PAT 缺失。PAT 页面:${makerPatTokensUrl}`].join("\n"),
30480
30737
  "",
30481
30738
  tapAuthRefreshText,
@@ -30487,6 +30744,41 @@ async function formatStatus(options = {}) {
30487
30744
  projectSection
30488
30745
  ].filter(Boolean).join("\n");
30489
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
+ }
30490
30782
  function resolveMakerToolTargetDir(targetDir) {
30491
30783
  if (targetDir) {
30492
30784
  return path7.resolve(targetDir);
@@ -30546,7 +30838,7 @@ async function formatAutoProjectListFromPat() {
30546
30838
  const projects = await listMakerProjects();
30547
30839
  return [
30548
30840
  "本地已有 Maker PAT,当前目录尚未绑定 Maker 项目。",
30549
- "当前目录未绑定时,可从下面的 Maker Apps 中选择一个进行 clone;选择、解释和 clone 顺序请参考 taptap-maker-local skill。",
30841
+ "当前目录未绑定时,必须逐项展示下面完整 Maker Apps 列表,不要只总结数量;选择、解释和 clone 顺序请参考 taptap-maker-local skill。",
30550
30842
  "",
30551
30843
  formatProjectList(projects)
30552
30844
  ].join("\n");
@@ -30575,6 +30867,8 @@ function formatProjectList(projects) {
30575
30867
  return [
30576
30868
  "Maker apps",
30577
30869
  "",
30870
+ "请把下面每一个 app 条目展示给用户,不要只说共有多少个。",
30871
+ "",
30578
30872
  ...projects.map(
30579
30873
  (project, index) => `${index + 1}. ${project.id}${project.name ? ` ${project.name}` : ""}${project.user_id ? ` user_id=${project.user_id}` : ""}${project.gameType ? ` gameType=${project.gameType}` : ""}${project.stage ? ` stage=${project.stage}` : ""}${project.createdAt ? ` createdAt=${project.createdAt}` : ""}${project.lastConversationAt ? ` lastConversationAt=${project.lastConversationAt}` : ""}`
30580
30874
  ),
@@ -30603,6 +30897,33 @@ function formatCloneWarnings(warnings) {
30603
30897
  ""
30604
30898
  ];
30605
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
+ }
30606
30927
  function createRemoteProxyContext(options) {
30607
30928
  const identify = identifyMakerProject({ cwd: options.targetDir });
30608
30929
  if (!identify.projectRoot || !identify.projectId) {
@@ -30812,7 +31133,12 @@ async function buildCurrentDirectory(options) {
30812
31133
  buildLocalChangesPolicy
30813
31134
  };
30814
31135
  }
30815
- throw new Error(formatLocalChangesBeforeBuildMessage(localChanges.files));
31136
+ throw new Error(
31137
+ formatLocalChangesBeforeBuildMessage(localChanges.files, {
31138
+ ahead: localChanges.ahead,
31139
+ hasUnpushedCommits: localChanges.hasUnpushedCommits
31140
+ })
31141
+ );
30816
31142
  }
30817
31143
  return runRemoteBuildCurrentDirectory(options, options.targetDir);
30818
31144
  }
@@ -30922,7 +31248,7 @@ function toMakerBuildFailure(error2) {
30922
31248
  ...error2 instanceof Error && error2.stack ? { stack: error2.stack } : {}
30923
31249
  };
30924
31250
  }
30925
- function formatLocalChangesBeforeBuildMessage(files) {
31251
+ function formatLocalChangesBeforeBuildMessage(files, options = {}) {
30926
31252
  const visibleFiles = files.slice(0, 20);
30927
31253
  const hiddenCount = Math.max(0, files.length - visibleFiles.length);
30928
31254
  return [
@@ -30933,10 +31259,14 @@ function formatLocalChangesBeforeBuildMessage(files) {
30933
31259
  "- 提交本地改动并触发构建(以后都是如此):再次调用 maker_build_current_directory,并设置 submit_local_changes_before_build=true 和 remember_build_submit_preference=true;工具会先 commit + push,再继续执行远端 build 并返回构建结果。后续构建遇到本地改动会默认自动提交并继续构建。",
30934
31260
  "- 如果用户明确说不提交、直接构建云端版本,再调用 maker_build_current_directory,并设置 confirm_remote_build_without_submit=true。",
30935
31261
  "",
31262
+ options.hasUnpushedCommits ? `unpushed_commits: ${options.ahead || "yes"}` : "",
31263
+ options.hasUnpushedCommits ? "note: 本地已有 commit 还没有推送到 Maker 远端;需要先 push,远端构建才会包含这些改动。" : "",
31264
+ options.hasUnpushedCommits ? "" : "",
30936
31265
  "local_changes:",
30937
31266
  ...visibleFiles.map((file2) => `- ${file2}`),
31267
+ visibleFiles.length === 0 ? "- (none)" : "",
30938
31268
  ...hiddenCount > 0 ? [`- ... and ${hiddenCount} more`] : []
30939
- ].join("\n");
31269
+ ].filter((line) => line !== "").join("\n");
30940
31270
  }
30941
31271
  function createBuildArgs(projectRoot, options) {
30942
31272
  const buildArgs = {};
@@ -31009,7 +31339,12 @@ function formatBuildResult(result, progressSummary) {
31009
31339
  ...formatProgressSummary(progressSummary),
31010
31340
  "",
31011
31341
  "note: Maker build was not started because submit did not produce a pushed state.",
31012
- ...result.submitResult.failure ? ["", ...formatMakerFailureLines(result.submitResult.failure)] : []
31342
+ ...result.submitResult.failure ? [
31343
+ "",
31344
+ ...formatPushRecoveryLines(result.submitResult),
31345
+ "",
31346
+ ...formatMakerFailureLines(result.submitResult.failure)
31347
+ ] : []
31013
31348
  ].filter(Boolean).join("\n");
31014
31349
  }
31015
31350
  if (result.mode === "build_failed_after_submit") {
@@ -31114,7 +31449,29 @@ function formatPushResult(targetDir, result, progressSummary) {
31114
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."
31115
31450
  ].join("\n");
31116
31451
  }
31117
- 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);
31118
31475
  }
31119
31476
  function formatMakerBuildFailureLines(failure) {
31120
31477
  return [
@@ -31154,6 +31511,24 @@ function formatToolException(toolName, error2) {
31154
31511
  "next_action: 请只引导用户安装 Git;在 `git --version` 可用之前,不要继续调用 clone、fetch、commit 或 push。"
31155
31512
  ].join("\n");
31156
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
+ }
31157
31532
  return [
31158
31533
  "✗ Maker MCP tool failed",
31159
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.0" : "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.0";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.0",
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:
@@ -94,9 +110,10 @@ Workflow:
94
110
  Do not run editor-specific CLI install commands.
95
111
  5. If PAT is missing, ask the user to open the PAT page shown by `maker_status`, create a PAT, and send it back.
96
112
  6. When the user provides PAT, call `maker_exchange_pat(manual_pat)`.
97
- 7. If the current directory is still unbound, show the returned Maker app list and ask the user to
98
- choose. Do not auto-select, even if there is only one app.
99
- 8. Run the working directory compliance check below.
113
+ 7. If the current directory is still unbound, show every returned Maker app entry to the user and
114
+ ask the user to choose. Do not summarize the list as only a count, category, or stage. Do not
115
+ auto-select, even if there is only one app.
116
+ 8. Run the working directory compliance check below, including the parent Git repository warning.
100
117
  9. After the user chooses an app, call `maker_clone_to_current_directory(app_id)`. The clone
101
118
  tool prepares the AI dev kit automatically before project checkout.
102
119
  10. After clone succeeds, call `maker_status` again or explain that `.maker-mcp/config.json` now binds the directory to the Maker project.
@@ -170,8 +187,9 @@ If the current directory is already bound, app lists from `maker_exchange_pat`,
170
187
  `maker_status` are reference only. Do not ask which app to clone. Continue operating on the current
171
188
  bound project unless the user explicitly requests a different project.
172
189
 
173
- When app selection is needed, display the app list and ask the user to choose by index, app id, or
174
- name.
190
+ When app selection is needed, display every app entry from the tool result and ask the user to
191
+ choose by index, app id, or name. Do not replace the list with a summary such as "10 apps are
192
+ available".
175
193
 
176
194
  Do not auto-select:
177
195
 
@@ -183,6 +201,25 @@ After the user chooses, pass the concrete `app_id` to `maker_clone_to_current_di
183
201
 
184
202
  ## Working Directory Compliance Check
185
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
+
186
223
  Before clone, inspect only the current directory top level.
187
224
  The goal is to avoid surprising overwrites, not to deeply audit game code.
188
225
 
@@ -200,6 +237,17 @@ If the directory contains ordinary user files or folders, explain that Maker ini
200
237
  keep local files, but clone can fail if a local path conflicts with the Maker project. Ask whether
201
238
  to continue in this directory or switch to a clean directory.
202
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
+
203
251
  Do not delete, move, or overwrite user files during this check.
204
252
 
205
253
  ## Clone Directory Safety
@@ -214,6 +262,20 @@ may create local-only files before clone, so explain this in non-technical terms
214
262
 
215
263
  Do not delete or overwrite user files to make clone work unless the user explicitly asks.
216
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
+
217
279
  ### `.gitignore` Merge During Clone
218
280
 
219
281
  The Maker clone tool stages the dev-kit managed ignore block in
@@ -276,6 +338,21 @@ If `maker_submit_current_directory` returns a build failure after a successful p
276
338
  - submit/push succeeded
277
339
  - build failed, with the concrete build error
278
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
+
279
356
  ## Pull And Conflict Handling
280
357
 
281
358
  Before pulling:
@@ -104,7 +104,7 @@ Get-ChildItem $NpxDir -Directory -ErrorAction SilentlyContinue | ForEach-Object
104
104
  $env:TAPTAP_MCP_ENV = 'rnd'
105
105
  $log = Join-Path $env:TEMP 'taptap-mcp-warmup.log'
106
106
  $proc = Start-Process -FilePath npx `
107
- -ArgumentList '-y','--prefer-online','-p','@taptap/instant-games-open-mcp@beta','taptap-maker' `
107
+ -ArgumentList '-y','-p','@taptap/instant-games-open-mcp@beta','taptap-maker' `
108
108
  -RedirectStandardOutput $log -RedirectStandardError "$log.err" `
109
109
  -WindowStyle Hidden -PassThru
110
110
  Start-Sleep -Seconds 25
@@ -189,7 +189,7 @@ done
189
189
  根据用户 MCP 配置选默认 bin 或指定 bin(`taptap-maker`)。下例以 `taptap-maker` 为例,默认 bin 去掉 `-p ... taptap-maker`,直接写 `@taptap/instant-games-open-mcp@beta`。
190
190
 
191
191
  ```bash
192
- TAPTAP_MCP_ENV=rnd npx -y --prefer-online -p @taptap/instant-games-open-mcp@beta taptap-maker \
192
+ TAPTAP_MCP_ENV=rnd npx -y -p @taptap/instant-games-open-mcp@beta taptap-maker \
193
193
  < /dev/null > /tmp/taptap-mcp-warmup.log 2>&1 &
194
194
  PID=$!; sleep 25; kill $PID 2>/dev/null; wait 2>/dev/null
195
195
  ```