@leonxin/meetgames 0.1.11 → 0.1.13

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 (179) hide show
  1. package/README.md +9 -9
  2. package/dist/cache.d.ts +44 -0
  3. package/dist/cache.d.ts.map +1 -0
  4. package/dist/cache.js +101 -0
  5. package/dist/cache.js.map +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +43 -37
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config/meetSdkDefaultConfig.d.ts +1 -1
  10. package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
  11. package/dist/config/meetSdkDefaultConfig.js +4 -3
  12. package/dist/config/meetSdkDefaultConfig.js.map +1 -1
  13. package/dist/config/meetSdkIosConfig.d.ts.map +1 -1
  14. package/dist/config/meetSdkIosConfig.js +3 -1
  15. package/dist/config/meetSdkIosConfig.js.map +1 -1
  16. package/dist/config/meetSdkRemoteConfig.d.ts +1 -0
  17. package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
  18. package/dist/config/meetSdkRemoteConfig.js +4 -1
  19. package/dist/config/meetSdkRemoteConfig.js.map +1 -1
  20. package/dist/contracts/types.d.ts +11 -0
  21. package/dist/contracts/types.d.ts.map +1 -1
  22. package/dist/core/doctor.js +7 -7
  23. package/dist/core/doctor.js.map +1 -1
  24. package/dist/core/pipeline.d.ts.map +1 -1
  25. package/dist/core/pipeline.js +3 -0
  26. package/dist/core/pipeline.js.map +1 -1
  27. package/dist/core/previewPatches.d.ts +1 -1
  28. package/dist/core/previewPatches.js +2 -2
  29. package/dist/core/previewPatches.js.map +1 -1
  30. package/dist/core/reporter.d.ts.map +1 -1
  31. package/dist/core/reporter.js +4 -0
  32. package/dist/core/reporter.js.map +1 -1
  33. package/dist/core/workspace.d.ts.map +1 -1
  34. package/dist/core/workspace.js +2 -0
  35. package/dist/core/workspace.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/ios/channelConfig.js +1 -1
  41. package/dist/ios/channelConfig.js.map +1 -1
  42. package/dist/ios/codeUtils.d.ts +1 -0
  43. package/dist/ios/codeUtils.d.ts.map +1 -1
  44. package/dist/ios/codeUtils.js +3 -0
  45. package/dist/ios/codeUtils.js.map +1 -1
  46. package/dist/ios/integrate.d.ts.map +1 -1
  47. package/dist/ios/integrate.js +97 -23
  48. package/dist/ios/integrate.js.map +1 -1
  49. package/dist/ios/pbxprojEditor.d.ts.map +1 -1
  50. package/dist/ios/pbxprojEditor.js +123 -6
  51. package/dist/ios/pbxprojEditor.js.map +1 -1
  52. package/dist/ios/sdkBundle.d.ts +1 -6
  53. package/dist/ios/sdkBundle.d.ts.map +1 -1
  54. package/dist/ios/sdkBundle.js +44 -16
  55. package/dist/ios/sdkBundle.js.map +1 -1
  56. package/dist/mcp/server.d.ts.map +1 -1
  57. package/dist/mcp/server.js +12 -6
  58. package/dist/mcp/server.js.map +1 -1
  59. package/dist/mcp/service.d.ts +3 -0
  60. package/dist/mcp/service.d.ts.map +1 -1
  61. package/dist/mcp/service.js +31 -8
  62. package/dist/mcp/service.js.map +1 -1
  63. package/dist/ops/handlers.d.ts.map +1 -1
  64. package/dist/ops/handlers.js +24 -19
  65. package/dist/ops/handlers.js.map +1 -1
  66. package/dist/remote/sdkHomeDownload.d.ts +1 -1
  67. package/dist/remote/sdkHomeDownload.d.ts.map +1 -1
  68. package/dist/remote/sdkHomeDownload.js +27 -6
  69. package/dist/remote/sdkHomeDownload.js.map +1 -1
  70. package/docs/API.md +16 -16
  71. package/docs/CLI.md +21 -22
  72. package/docs/INTEGRATION.md +30 -11
  73. package/docs/MCP.md +1 -1
  74. package/docs/README.md +0 -1
  75. package/docs/archive/api/downloadSDKConfig.md +2 -2
  76. package/docs/archive/api/getChannelConfig-meetgames.md +1 -1
  77. package/docs/archive/product//351/234/200/346/261/202/346/226/207/346/241/243.md +1 -1
  78. package/package.json +2 -5
  79. package/recipes/android-default.yaml +0 -5
  80. package/recipes/integrate-default.yaml +0 -5
  81. package/src/cache.ts +164 -0
  82. package/src/cli.ts +46 -38
  83. package/src/config/meetSdkDefaultConfig.ts +4 -3
  84. package/src/config/meetSdkIosConfig.ts +3 -1
  85. package/src/config/meetSdkRemoteConfig.ts +5 -1
  86. package/src/contracts/types.ts +11 -0
  87. package/src/core/doctor.ts +7 -7
  88. package/src/core/pipeline.ts +3 -0
  89. package/src/core/previewPatches.ts +2 -2
  90. package/src/core/reporter.ts +3 -0
  91. package/src/core/workspace.ts +2 -0
  92. package/src/index.ts +7 -0
  93. package/src/ios/channelConfig.ts +1 -1
  94. package/src/ios/codeUtils.ts +4 -0
  95. package/src/ios/integrate.ts +110 -27
  96. package/src/ios/pbxprojEditor.ts +121 -4
  97. package/src/ios/sdkBundle.ts +41 -18
  98. package/src/mcp/server.ts +12 -6
  99. package/src/mcp/service.ts +39 -8
  100. package/src/ops/handlers.ts +23 -19
  101. package/src/remote/sdkHomeDownload.ts +28 -7
  102. package/tests/doctor.test.ts +4 -2
  103. package/tests/{test-projects-hosts.test.ts → fixtures-hosts.test.ts} +2 -2
  104. package/tests/ios.sdkBundle.test.ts +10 -5
  105. package/tests/mcp.e2e.ts +2 -5
  106. package/tests/meetSdkRemoteConfig.test.ts +25 -0
  107. package/tests/pipeline.android.test.ts +1 -2
  108. package/tests/pipeline.ios.test.ts +133 -20
  109. package/tests/pipeline.preview.patch.test.ts +2 -2
  110. package/tests/sdkVersionConfig.test.ts +3 -2
  111. package/dist/aab-converter/aab-entry.d.ts +0 -3
  112. package/dist/aab-converter/aab-entry.d.ts.map +0 -1
  113. package/dist/aab-converter/aab-entry.js +0 -49
  114. package/dist/aab-converter/aab-entry.js.map +0 -1
  115. package/dist/aab-converter/apksExtractor.d.ts +0 -2
  116. package/dist/aab-converter/apksExtractor.d.ts.map +0 -1
  117. package/dist/aab-converter/apksExtractor.js +0 -108
  118. package/dist/aab-converter/apksExtractor.js.map +0 -1
  119. package/dist/aab-converter/bundletoolRunner.d.ts +0 -15
  120. package/dist/aab-converter/bundletoolRunner.d.ts.map +0 -1
  121. package/dist/aab-converter/bundletoolRunner.js +0 -46
  122. package/dist/aab-converter/bundletoolRunner.js.map +0 -1
  123. package/dist/aab-converter/cliArgs.d.ts +0 -27
  124. package/dist/aab-converter/cliArgs.d.ts.map +0 -1
  125. package/dist/aab-converter/cliArgs.js +0 -170
  126. package/dist/aab-converter/cliArgs.js.map +0 -1
  127. package/dist/aab-converter/convertAabToApk.d.ts +0 -7
  128. package/dist/aab-converter/convertAabToApk.d.ts.map +0 -1
  129. package/dist/aab-converter/convertAabToApk.js +0 -69
  130. package/dist/aab-converter/convertAabToApk.js.map +0 -1
  131. package/dist/aab-converter/resourcePaths.d.ts +0 -4
  132. package/dist/aab-converter/resourcePaths.d.ts.map +0 -1
  133. package/dist/aab-converter/resourcePaths.js +0 -42
  134. package/dist/aab-converter/resourcePaths.js.map +0 -1
  135. package/dist/aab-converter/signingOptions.d.ts +0 -9
  136. package/dist/aab-converter/signingOptions.d.ts.map +0 -1
  137. package/dist/aab-converter/signingOptions.js +0 -21
  138. package/dist/aab-converter/signingOptions.js.map +0 -1
  139. package/dist/aab-converter/types.d.ts +0 -24
  140. package/dist/aab-converter/types.d.ts.map +0 -1
  141. package/dist/aab-converter/types.js +0 -2
  142. package/dist/aab-converter/types.js.map +0 -1
  143. package/dist/shared/fileUtils.d.ts +0 -5
  144. package/dist/shared/fileUtils.d.ts.map +0 -1
  145. package/dist/shared/fileUtils.js +0 -35
  146. package/dist/shared/fileUtils.js.map +0 -1
  147. package/dist/shared/logger.d.ts +0 -10
  148. package/dist/shared/logger.d.ts.map +0 -1
  149. package/dist/shared/logger.js +0 -37
  150. package/dist/shared/logger.js.map +0 -1
  151. package/dist/shared/pathUtils.d.ts +0 -4
  152. package/dist/shared/pathUtils.d.ts.map +0 -1
  153. package/dist/shared/pathUtils.js +0 -22
  154. package/dist/shared/pathUtils.js.map +0 -1
  155. package/dist/shared/processRunner.d.ts +0 -12
  156. package/dist/shared/processRunner.d.ts.map +0 -1
  157. package/dist/shared/processRunner.js +0 -31
  158. package/dist/shared/processRunner.js.map +0 -1
  159. package/docs/AAB_CONVERTER_CLI_PLAN.md +0 -392
  160. package/logs/convert-20260622-155037.log +0 -5
  161. package/logs/convert-20260622-155226.log +0 -6
  162. package/scripts/package-aab-cli-win.mjs +0 -193
  163. package/src/aab-converter/aab-entry.ts +0 -48
  164. package/src/aab-converter/apksExtractor.ts +0 -119
  165. package/src/aab-converter/bundletoolRunner.ts +0 -63
  166. package/src/aab-converter/cliArgs.ts +0 -194
  167. package/src/aab-converter/convertAabToApk.ts +0 -81
  168. package/src/aab-converter/resourcePaths.ts +0 -43
  169. package/src/aab-converter/signingOptions.ts +0 -29
  170. package/src/aab-converter/types.ts +0 -26
  171. package/src/shared/fileUtils.ts +0 -41
  172. package/src/shared/logger.ts +0 -49
  173. package/src/shared/pathUtils.ts +0 -24
  174. package/src/shared/processRunner.ts +0 -43
  175. package/test-projects/README.md +0 -51
  176. package/test-projects/_preview/pipeline.patch +0 -281
  177. package/tests/aab-converter.test.ts +0 -213
  178. /package/{meetsdk-android.json → config/meetsdk-android.json} +0 -0
  179. /package/{meetsdk-ios.json → config/meetsdk-ios.json} +0 -0
@@ -93,7 +93,7 @@ GET https://test-business-api.meetgames.com/customer/topsdk/console/meetgames/ch
93
93
  | `thirdDataPlatform.firebaseUrl` | Firebase / `firebaseUrl` 字段 |
94
94
  | `parameterConfig` | 支付 / Google Play 服务账号等,与 `channel_payment`、parameter 表相关 |
95
95
 
96
- 完整 Gradle 集成仍依赖工具侧 [`meetsdk-android.json`](../../meetsdk-android.json) 合并版本与依赖。
96
+ 完整 Gradle 集成仍依赖工具侧 [`config/meetsdk-android.json`](../../config/meetsdk-android.json) 合并版本与依赖。
97
97
 
98
98
  ## 脱敏样例
99
99
 
@@ -77,7 +77,7 @@ addManifestPlaceholders([
77
77
  #### 新方式
78
78
 
79
79
  - 远程 JSON 决定**接入哪些可选模块**(guest、email、facebook、google-iap、appsflyer 等)。
80
- - 工具内置 [`meetsdk-android.json`](../meetsdk-android.json) 提供**固定** SDK 版本、仓库 URL、`classpath`、Firebase plugin、各模块 `dependencies`。
80
+ - 工具内置 [`config/meetsdk-android.json`](../../config/meetsdk-android.json) 提供**固定** SDK 版本、仓库 URL、`classpath`、Firebase plugin、各模块 `dependencies`。
81
81
  - `integrate` 合并后写入根工程与 App Module 的 Gradle(标记块 upsert,避免重复插入)。
82
82
 
83
83
  **示例(由工具生成,非人工维护)**
package/package.json CHANGED
@@ -1,17 +1,14 @@
1
1
  {
2
2
  "name": "@leonxin/meetgames",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "meetgames": "dist/entry.js",
8
- "meetgames-mcp": "dist/mcp-entry.js",
9
- "meetgames-aab": "dist/aab-converter/aab-entry.js"
8
+ "meetgames-mcp": "dist/mcp-entry.js"
10
9
  },
11
10
  "scripts": {
12
11
  "build": "tsc -p tsconfig.json",
13
- "build:aab": "tsc -p tsconfig.json",
14
- "package:aab-win-zip": "node scripts/package-aab-cli-win.mjs",
15
12
  "test": "vitest run",
16
13
  "test:mcp": "npm run build && npm run test:mcp:run",
17
14
  "test:mcp:run": "vitest run --config vitest.mcp.config.ts",
@@ -8,8 +8,3 @@ steps:
8
8
  args:
9
9
  permissions:
10
10
  - android.permission.ACCESS_NETWORK_STATE
11
- - op: files.copyBundled
12
- platform: android
13
- args:
14
- from: android/sample.txt
15
- to: vendor/meet-integrate/sample.txt
@@ -6,11 +6,6 @@ steps:
6
6
  - op: files.downloadGoogleServicesJson
7
7
  platform: android
8
8
  args: {}
9
- - op: files.copyBundled
10
- platform: android
11
- args:
12
- from: android/sample.txt
13
- to: vendor/meet-integrate/sample.txt
14
9
  - op: ios.integrateTopSdk
15
10
  platform: ios
16
11
  args: {}
package/src/cache.ts ADDED
@@ -0,0 +1,164 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { MEETSDK_REMOTE_CONFIG_FILENAME } from "./config/meetSdkRemoteConfig.js";
6
+
7
+ export const MEET_SDK_TOOL_CACHE_ROOT = path.join(os.homedir(), ".cache", "meet-sdk-tool");
8
+
9
+ function iosSdkZipFileName(version: string): string {
10
+ return `topSDK-ios--V${version}.zip`;
11
+ }
12
+
13
+ function safeSegment(value: string): string {
14
+ const cleaned = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
15
+ return cleaned || "unknown";
16
+ }
17
+
18
+ function sha256Hex(value: string, length = 16): string {
19
+ return crypto.createHash("sha256").update(value).digest("hex").slice(0, length);
20
+ }
21
+
22
+ function writeFileAtomic(absPath: string, content: string | Buffer): void {
23
+ ensureCacheRoot();
24
+ fs.mkdirSync(path.dirname(absPath), { recursive: true });
25
+ const tmp = path.join(path.dirname(absPath), `.${path.basename(absPath)}.${process.pid}.${Date.now()}.tmp`);
26
+ fs.writeFileSync(tmp, content);
27
+ fs.renameSync(tmp, absPath);
28
+ }
29
+
30
+ export function ensureCacheRoot(): string {
31
+ fs.mkdirSync(MEET_SDK_TOOL_CACHE_ROOT, { recursive: true, mode: 0o700 });
32
+ try {
33
+ fs.chmodSync(MEET_SDK_TOOL_CACHE_ROOT, 0o700);
34
+ } catch {
35
+ // Best-effort on filesystems that do not support POSIX modes.
36
+ }
37
+ return MEET_SDK_TOOL_CACHE_ROOT;
38
+ }
39
+
40
+ export function resolveRemoteConfigCachePath(params: {
41
+ env: string;
42
+ appId: string;
43
+ channelType: string;
44
+ }): string {
45
+ return path.join(
46
+ MEET_SDK_TOOL_CACHE_ROOT,
47
+ "configs",
48
+ safeSegment(params.env),
49
+ safeSegment(params.appId),
50
+ safeSegment(params.channelType),
51
+ MEETSDK_REMOTE_CONFIG_FILENAME
52
+ );
53
+ }
54
+
55
+ export function writeRemoteConfigCache(params: {
56
+ env: string;
57
+ appId: string;
58
+ channelType: string;
59
+ requestUrl: string;
60
+ rawText: string;
61
+ warnings?: readonly string[];
62
+ }): { configPath: string; metadataPath: string } {
63
+ const fetchedAt = new Date().toISOString();
64
+ const metadata = `${JSON.stringify(
65
+ {
66
+ fetchedAt,
67
+ env: params.env,
68
+ appId: params.appId,
69
+ channelType: params.channelType,
70
+ requestUrl: params.requestUrl,
71
+ sha256: crypto.createHash("sha256").update(params.rawText).digest("hex"),
72
+ warnings: params.warnings ?? [],
73
+ },
74
+ null,
75
+ 2
76
+ )}\n`;
77
+ const configPath = resolveRemoteConfigCachePath(params);
78
+ const metadataPath = path.join(path.dirname(configPath), "metadata.json");
79
+
80
+ writeFileAtomic(configPath, params.rawText);
81
+ writeFileAtomic(metadataPath, metadata);
82
+
83
+ return { configPath, metadataPath };
84
+ }
85
+
86
+ function pluginsHash(plugins: readonly string[]): string {
87
+ return sha256Hex(plugins.join(","), 12);
88
+ }
89
+
90
+ export function resolveIosSdkCacheLayout(params: {
91
+ version: string;
92
+ packageType: string;
93
+ plugins: readonly string[];
94
+ }): { baseDir: string; zipPath: string; extractDir: string; metadataPath: string; lockDir: string } {
95
+ const baseDir = path.join(
96
+ MEET_SDK_TOOL_CACHE_ROOT,
97
+ "sdk",
98
+ "ios",
99
+ safeSegment(params.packageType),
100
+ safeSegment(params.version),
101
+ pluginsHash(params.plugins)
102
+ );
103
+ return {
104
+ baseDir,
105
+ zipPath: path.join(baseDir, iosSdkZipFileName(params.version)),
106
+ extractDir: path.join(baseDir, "extracted"),
107
+ metadataPath: path.join(baseDir, "metadata.json"),
108
+ lockDir: path.join(baseDir, ".lock"),
109
+ };
110
+ }
111
+
112
+ export function writeIosSdkCacheMetadata(params: {
113
+ metadataPath: string;
114
+ version: string;
115
+ date?: string;
116
+ packageType: string;
117
+ plugins: readonly string[];
118
+ versionUrl: string;
119
+ downloadApiUrl: string;
120
+ sdkZipUrl: string;
121
+ zipPath: string;
122
+ extractDir: string;
123
+ resolvedSdkRoot: string;
124
+ }): void {
125
+ const zipSha256 = fs.existsSync(params.zipPath)
126
+ ? crypto.createHash("sha256").update(fs.readFileSync(params.zipPath)).digest("hex")
127
+ : "";
128
+ writeFileAtomic(
129
+ params.metadataPath,
130
+ `${JSON.stringify(
131
+ {
132
+ fetchedAt: new Date().toISOString(),
133
+ version: params.version,
134
+ date: params.date,
135
+ packageType: params.packageType,
136
+ plugins: params.plugins,
137
+ versionUrl: params.versionUrl,
138
+ downloadApiUrl: params.downloadApiUrl,
139
+ sdkZipUrl: params.sdkZipUrl,
140
+ zipPath: params.zipPath,
141
+ extractDir: params.extractDir,
142
+ resolvedSdkRoot: params.resolvedSdkRoot,
143
+ zipSha256,
144
+ },
145
+ null,
146
+ 2
147
+ )}\n`
148
+ );
149
+ }
150
+
151
+ export function withCacheLock<T>(lockDir: string, fn: () => Promise<T>): Promise<T> {
152
+ fs.mkdirSync(path.dirname(lockDir), { recursive: true });
153
+ try {
154
+ fs.mkdirSync(lockDir);
155
+ } catch (e) {
156
+ if ((e as NodeJS.ErrnoException).code === "EEXIST") {
157
+ throw new Error(`cache path is locked by another meet-sdk-tool process: ${lockDir}`);
158
+ }
159
+ throw e;
160
+ }
161
+ return fn().finally(() => {
162
+ fs.rmSync(lockDir, { recursive: true, force: true });
163
+ });
164
+ }
package/src/cli.ts CHANGED
@@ -20,7 +20,6 @@ import {
20
20
  import type { Manifest } from "./contracts/types.js";
21
21
  import {
22
22
  validateDownloadSdkConfigForWrite,
23
- writeDownloadSdkConfigRaw,
24
23
  } from "./config/fetchConfigWrite.js";
25
24
  import {
26
25
  MEETSDK_REMOTE_CONFIG_FILENAME,
@@ -28,6 +27,11 @@ import {
28
27
  tryParseAsMeetSdkRemoteConfig,
29
28
  type MeetSdkRemoteConfig,
30
29
  } from "./config/meetSdkRemoteConfig.js";
30
+ import {
31
+ MEET_SDK_TOOL_CACHE_ROOT,
32
+ resolveRemoteConfigCachePath,
33
+ writeRemoteConfigCache,
34
+ } from "./cache.js";
31
35
 
32
36
  const EXIT = {
33
37
  OK: 0,
@@ -62,7 +66,6 @@ interface Parsed {
62
66
  iosSdkVersion: string;
63
67
  iosSdkPlugins: string;
64
68
  iosSdkPackageType: string;
65
- iosSdkOutputDir: string;
66
69
  }
67
70
 
68
71
  function printHelp(): void {
@@ -70,35 +73,35 @@ function printHelp(): void {
70
73
  meetgames — Android-first integration CLI (TypeScript)
71
74
 
72
75
  Usage:
73
- meetgames integrate [--project-root <path>] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
76
+ meetgames integrate [--project-root <path>] [--app-id ID] [--channel-type TYPE] [--env prod|pre|test] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
74
77
  meetgames fetch-config [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--verbose]
75
- meetgames download-ios-sdk [--version VERSION] [--plugins csv] [--package-type native|unity|cocos] [--sdk-api-base-url URL] [--output-dir <path>] [--verbose]
78
+ meetgames download-ios-sdk [--version VERSION] [--plugins csv] [--package-type native|unity|cocos] [--sdk-api-base-url URL] [--verbose]
76
79
  meetgames setup [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
77
80
  meetgames doctor [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] --project-root <path> [--app-target <target>] [--verbose]
78
81
 
79
82
  Notes:
80
83
  - Source code is TypeScript only; published bin runs compiled output under dist/.
81
84
  - iOS: copies frameworks to topSDK/, edits project.pbxproj & Info.plist, injects AppDelegate (.m/.mm) when present (topsdk-tool-ios parity).
82
- - fetch-config calls TOPSDK downloadSDKConfig and writes the response body unchanged to <project-root>/meetsdk-remote-config.json.
83
- - setup runs fetch-config then integrate in one process (same flags as both subcommands).
85
+ - fetch-config calls TOPSDK downloadSDKConfig and writes the response body unchanged under ${MEET_SDK_TOOL_CACHE_ROOT}.
86
+ - setup runs fetch-config, then download-ios-sdk for iOS projects, then integrate in one process.
84
87
  - doctor / setup / integrate require --project-root and auto-select exactly one platform from that root.
85
- - doctor first fetches downloadSDKConfig to <project-root>/meetsdk-remote-config.json, then validates the detected platform integration.
88
+ - doctor first fetches downloadSDKConfig to the cache, then validates the detected platform integration.
86
89
  - integrate uses recipes/integrate-default.yaml, filtered to the detected platform before execution.
87
- - iOS SDK is read from bundled/ios-sdk/ in the tool package (native iOS only).
88
- - Android integrate/doctor reads the latest SDK version from sdk-home and stores it in meetsdk-android.json.
89
- - download-ios-sdk calls sdk-home getDownLoadUrl, saves the iOS SDK zip under bundled/ios-sdk/, extracts it there, and stores the resolved version in meetsdk-ios.json.
90
+ - iOS SDK is read from ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
91
+ - Android integrate/doctor reads the latest SDK version from sdk-home and stores it in config/meetsdk-android.json.
92
+ - download-ios-sdk calls sdk-home getDownLoadUrl, saves and extracts the iOS SDK under ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
90
93
  - fetch-config requires --app-secret (or TOPSDK_APP_SECRET) to sign downloadSDKConfig; appSecret is never read from meetsdk-remote-config.json.
91
94
  - When analytics.firebase is enabled, Android downloads google-services.json to the detected/selected app module; iOS downloads GoogleService-Info.plist next to Info.plist.
92
- - fetch-config writes to <project-root>/meetsdk-remote-config.json.
93
- - fetch-config requires --channel-type (or channel in local meetsdk-remote-config.json / TOPSDK_CHANNEL_TYPE); not inferred from Android/iOS detection.
94
- - Recipe op gradle.applyMeetSdkRemoteConfig reads meetsdk-remote-config.json and writes TOPSDK marker blocks to root + app build.gradle (same idea as sdk-integration-agent gradleEditor).
95
+ - fetch-config writes to ${MEET_SDK_TOOL_CACHE_ROOT}/configs/<env>/<appId>/<channelType>/meetsdk-remote-config.json.
96
+ - integrate/doctor read the cache entry selected by --env, --app-id, and --channel-type; without those flags they only read an existing project-root meetsdk-remote-config.json for compatibility.
97
+ - Recipe op gradle.applyMeetSdkRemoteConfig reads cached meetsdk-remote-config.json and writes TOPSDK marker blocks to root + app build.gradle (same idea as sdk-integration-agent gradleEditor).
95
98
 
96
99
  Options (global where noted):
97
100
  --project-root Host project directory (default: cwd); for iOS it may point to the project root or directly to a .xcodeproj directory
98
101
  --app-target App target to integrate/check: Android application Gradle module (e.g. :app or launcher) or iOS App target name
99
- --app-id fetch-config override; default reads topsdk.appId from meetsdk-remote-config.json
102
+ --app-id fetch-config/integrate/doctor cache selector; default TOPSDK_APP_ID
100
103
  --app-secret fetch-config: required appSecret for downloadSDKConfig sign (or env TOPSDK_APP_SECRET)
101
- --channel-type fetch-config: channelType query param for downloadSDKConfig (required unless channel in local file or TOPSDK_CHANNEL_TYPE)
104
+ --channel-type fetch-config/integrate/doctor cache selector; default TOPSDK_CHANNEL_TYPE
102
105
  --env fetch-config: prod(正式服,默认)| pre | test(开发调试)
103
106
  TOPSDK_API_BASE_URL fetch-config: 覆盖 API 根地址(如 http://localhost:18080/ 联调本机 console)
104
107
  MEETGAMES_SDK_HOME_API_BASE_URL 覆盖 sdk-home API 根地址(默认 https://business-api.meetgames.com);用于 Android 最新版本查询和 iOS SDK 下载
@@ -106,10 +109,9 @@ Options (global where noted):
106
109
  --version download-ios-sdk: 指定 iOS SDK 版本;不传时从 /sdk/home/version 读取最新 iOS 版本
107
110
  --plugins download-ios-sdk: 逗号分隔插件列表;默认与下载页 iOS 默认选择一致
108
111
  --package-type download-ios-sdk: native(默认)| unity | cocos
109
- --output-dir download-ios-sdk: 解压目标目录;默认 <package-root>/bundled/ios-sdk
110
112
  --dry-run integrate: compute changes and patch preview without writing host project files (default is write to disk)
111
113
  --report-file Write JSON report to path
112
- --patch-file integrate: write unified diff to this path (works with --dry-run). If under <pkg>/test-projects/_preview/, all existing files in that dir are removed first so only the latest patch remains.
114
+ --patch-file integrate: write unified diff to this path (works with --dry-run). If under <pkg>/preview-patches/, all existing files in that dir are removed first so only the latest patch remains.
113
115
  --verbose Verbose logs and full patch preview
114
116
 
115
117
  Subcommand notes:
@@ -139,7 +141,6 @@ function parseArgv(argv: string[]): Parsed {
139
141
  iosSdkVersion: "",
140
142
  iosSdkPlugins: "",
141
143
  iosSdkPackageType: "",
142
- iosSdkOutputDir: "",
143
144
  };
144
145
  const rest = argv.slice(2);
145
146
  if (!rest.length || (rest[0]?.startsWith("-") ?? false)) {
@@ -201,12 +202,6 @@ function parseArgv(argv: string[]): Parsed {
201
202
  i += 1;
202
203
  continue;
203
204
  }
204
- if (t === "--output-dir") {
205
- out.iosSdkOutputDir = path.resolve(rest[i + 1] ?? "");
206
- if (!out.iosSdkOutputDir || rest[i + 1]?.startsWith("-")) fail("--output-dir requires a directory path", EXIT.INVALID_ARGS);
207
- i += 1;
208
- continue;
209
- }
210
205
  if (t === "--env") {
211
206
  const v = (rest[i + 1] ?? "").toLowerCase();
212
207
  i += 1;
@@ -254,6 +249,13 @@ function resolvedAppTarget(parsed: Parsed): string {
254
249
  return parsed.appTarget;
255
250
  }
256
251
 
252
+ function cachedRemoteConfigPathFromArgs(parsed: Parsed): string {
253
+ const appId = parsed.topsdkAppId || process.env.TOPSDK_APP_ID || "";
254
+ const channelType = parsed.topsdkChannelType || process.env.TOPSDK_CHANNEL_TYPE || "";
255
+ if (!appId || !channelType) return "";
256
+ return resolveRemoteConfigCachePath({ env: parsed.topsdkEnv, appId, channelType });
257
+ }
258
+
257
259
  function selectedPlatformContext(parsed: Parsed): {
258
260
  platform: "android" | "ios";
259
261
  ctx: ReturnType<typeof buildWorkspaceContext>;
@@ -262,6 +264,7 @@ function selectedPlatformContext(parsed: Parsed): {
262
264
  const ctx = buildWorkspaceContext(parsed.projectRoot, resolvePackageRoot(), {
263
265
  appTarget: resolvedAppTarget(parsed),
264
266
  sdkHomeApiBaseUrl: parsed.sdkHomeApiBaseUrl || undefined,
267
+ remoteConfigPath: cachedRemoteConfigPathFromArgs(parsed) || undefined,
265
268
  });
266
269
  const detected = detectSinglePlatform(ctx);
267
270
  if (!detected.ok) fail(detected.error, EXIT.PROJECT_ERROR);
@@ -282,13 +285,7 @@ async function cmdDoctor(parsed: Parsed): Promise<void> {
282
285
  if (!report.ok) process.exit(EXIT.CONFIG_ERROR);
283
286
  }
284
287
 
285
- /** 固定缓存路径:宿主工程根目录下的 meetsdk-remote-config.json */
286
- function meetSdkRemoteConfigCachePath(projectRoot: string): string {
287
- return path.join(projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
288
- }
289
-
290
- function readLocalMeetSdkRemoteConfig(projectRoot: string): MeetSdkRemoteConfig | null {
291
- const configPath = meetSdkRemoteConfigCachePath(projectRoot);
288
+ function readLocalMeetSdkRemoteConfig(configPath: string): MeetSdkRemoteConfig | null {
292
289
  if (!fs.existsSync(configPath)) return null;
293
290
  try {
294
291
  return tryParseAsMeetSdkRemoteConfig(JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown);
@@ -298,8 +295,8 @@ function readLocalMeetSdkRemoteConfig(projectRoot: string): MeetSdkRemoteConfig
298
295
  }
299
296
 
300
297
  async function cmdFetchConfig(parsed: Parsed): Promise<void> {
301
- const out = meetSdkRemoteConfigCachePath(parsed.projectRoot);
302
- const localConfig = readLocalMeetSdkRemoteConfig(parsed.projectRoot);
298
+ const selectedConfigPath = cachedRemoteConfigPathFromArgs(parsed);
299
+ const localConfig = selectedConfigPath ? readLocalMeetSdkRemoteConfig(selectedConfigPath) : null;
303
300
 
304
301
  const appId = parsed.topsdkAppId || localConfig?.topsdk.appId || process.env.TOPSDK_APP_ID || "";
305
302
  const appSecret = parsed.topsdkAppSecret || process.env.TOPSDK_APP_SECRET || "";
@@ -347,10 +344,18 @@ async function cmdFetchConfig(parsed: Parsed): Promise<void> {
347
344
  console.warn(`[meetgames] warning: ${warning}`);
348
345
  }
349
346
 
350
- writeDownloadSdkConfigRaw(out, rawText);
351
- console.log(`[meetgames] wrote ${MEETSDK_REMOTE_CONFIG_FILENAME} (downloadSDKConfig response, unmodified): ${out}`);
347
+ const written = writeRemoteConfigCache({
348
+ env: parsed.topsdkEnv,
349
+ appId,
350
+ channelType,
351
+ requestUrl,
352
+ rawText,
353
+ warnings: validation.warnings,
354
+ });
355
+ console.log(`[meetgames] wrote ${MEETSDK_REMOTE_CONFIG_FILENAME} (downloadSDKConfig response, unmodified): ${written.configPath}`);
352
356
  if (parsed.verbose) {
353
357
  console.log(`[meetgames] GET ${requestUrl}`);
358
+ console.log(`[meetgames] metadata: ${written.metadataPath}`);
354
359
  }
355
360
  }
356
361
 
@@ -396,9 +401,13 @@ async function cmdIntegrate(parsed: Parsed): Promise<void> {
396
401
  }
397
402
 
398
403
  async function cmdSetup(parsed: Parsed): Promise<void> {
399
- selectedPlatformContext(parsed);
404
+ const { platform } = selectedPlatformContext(parsed);
400
405
  console.log("[meetgames] setup: fetching remote config…");
401
406
  await cmdFetchConfig(parsed);
407
+ if (platform === "ios") {
408
+ console.log("[meetgames] setup: downloading iOS SDK…");
409
+ await cmdDownloadIosSdk(parsed);
410
+ }
402
411
  console.log("[meetgames] setup: integrating project…");
403
412
  await cmdIntegrate(parsed);
404
413
  }
@@ -428,7 +437,6 @@ async function cmdDownloadIosSdk(parsed: Parsed): Promise<void> {
428
437
  version: parsed.iosSdkVersion || undefined,
429
438
  plugins,
430
439
  packageType,
431
- outputDir: parsed.iosSdkOutputDir || undefined,
432
440
  });
433
441
  } catch (e) {
434
442
  fail(e instanceof Error ? e.message : String(e), EXIT.NETWORK_ERROR);
@@ -437,7 +445,7 @@ async function cmdDownloadIosSdk(parsed: Parsed): Promise<void> {
437
445
  console.log(`[meetgames] downloaded iOS SDK ${result.version} zip: ${result.zipPath}`);
438
446
  console.log(`[meetgames] extracted iOS SDK to: ${result.extractDir}`);
439
447
  console.log(`[meetgames] resolved iOS SDK root: ${result.resolvedSdkRoot}`);
440
- console.log(`[meetgames] updated iOS SDK config: ${result.iosConfigPath}`);
448
+ console.log(`[meetgames] wrote iOS SDK metadata: ${result.cacheMetadataPath}`);
441
449
  if (parsed.verbose) {
442
450
  console.log(`[meetgames] GET ${result.versionUrl}`);
443
451
  console.log(`[meetgames] GET ${result.downloadApiUrl}`);
@@ -6,13 +6,14 @@ import { defaultSdkHomeApiBaseUrl, fetchSdkHomeVersions, type SdkHomePlatformVer
6
6
 
7
7
  /** Built-in Android SDK defaults (repos and per-plugin dependencies). */
8
8
  export const MEETSDK_ANDROID_DEFAULTS_FILENAME = "meetsdk-android.json";
9
+ const MEETSDK_CONFIG_DIR = "config";
9
10
 
10
11
  const defaultConfigPath = fileURLToPath(
11
- new URL(`../../${MEETSDK_ANDROID_DEFAULTS_FILENAME}`, import.meta.url)
12
+ new URL(`../../${MEETSDK_CONFIG_DIR}/${MEETSDK_ANDROID_DEFAULTS_FILENAME}`, import.meta.url)
12
13
  );
13
14
 
14
15
  export function resolveMeetSdkAndroidConfigPath(packageRoot?: string): string {
15
- return packageRoot ? path.join(packageRoot, MEETSDK_ANDROID_DEFAULTS_FILENAME) : defaultConfigPath;
16
+ return packageRoot ? path.join(packageRoot, MEETSDK_CONFIG_DIR, MEETSDK_ANDROID_DEFAULTS_FILENAME) : defaultConfigPath;
16
17
  }
17
18
 
18
19
  export function loadBuiltInMeetSdkDefaultConfig(options: { packageRoot?: string } = {}): MeetSdkDefaultConfig {
@@ -79,7 +80,7 @@ export function syncMeetSdkAndroidVersionToConfig(params: {
79
80
 
80
81
  /**
81
82
  * Built-in Android SDK defaults with the SDK version resolved at runtime from sdk-home.
82
- * The version is also persisted to `meetsdk-android.json` so the package config
83
+ * The version is also persisted to `config/meetsdk-android.json` so the package config
83
84
  * reflects the latest SDK version discovered from the download center.
84
85
  */
85
86
  export async function loadMeetSdkDefaultConfigWithLatestAndroidVersion(options: {
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
4
  export const MEETSDK_IOS_CONFIG_FILENAME = "meetsdk-ios.json";
5
+ const MEETSDK_CONFIG_DIR = "config";
5
6
 
6
7
  export interface MeetSdkIosConfig {
7
8
  topsdk: {
@@ -27,7 +28,7 @@ function normalizePlugins(value: unknown): string[] | undefined {
27
28
  }
28
29
 
29
30
  export function resolveMeetSdkIosConfigPath(packageRoot: string): string {
30
- return path.join(packageRoot, MEETSDK_IOS_CONFIG_FILENAME);
31
+ return path.join(packageRoot, MEETSDK_CONFIG_DIR, MEETSDK_IOS_CONFIG_FILENAME);
31
32
  }
32
33
 
33
34
  export function tryParseAsMeetSdkIosConfig(raw: unknown): MeetSdkIosConfig | null {
@@ -57,6 +58,7 @@ export function loadMeetSdkIosConfig(packageRoot: string): MeetSdkIosConfig {
57
58
 
58
59
  export function writeMeetSdkIosConfig(packageRoot: string, config: MeetSdkIosConfig): string {
59
60
  const configPath = resolveMeetSdkIosConfigPath(packageRoot);
61
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
60
62
  fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
61
63
  return configPath;
62
64
  }
@@ -154,6 +154,7 @@ export type MeetSdkAnalyticsFirebaseModule = false | MeetSdkAnalyticsFirebaseCre
154
154
  export interface MeetSdkAnalyticsAdjustCredentials {
155
155
  appId: string;
156
156
  clientId?: string;
157
+ eventUrl?: string;
157
158
  enableSandbox: boolean;
158
159
  dependencies?: MeetSdkGradleDependency[];
159
160
  }
@@ -532,6 +533,7 @@ function parseAnalyticsAdjustModule(v: unknown): MeetSdkAnalyticsAdjustModule |
532
533
  if (!isRecord(v)) return null;
533
534
  return {
534
535
  appId: str(v.appCode),
536
+ eventUrl: optionalStr(v.eventUrl),
535
537
  enableSandbox: "enableSandbox" in v ? bool(v.enableSandbox) : false,
536
538
  dependencies: parseDependencies(v.dependencies),
537
539
  };
@@ -556,7 +558,8 @@ function parseAnalyticsAppsflyerModule(v: unknown): MeetSdkAnalyticsAppsflyerMod
556
558
  if (!isRecord(v)) return null;
557
559
  return {
558
560
  devKey: str(v.devKey),
559
- appleAppId: optionalStr(v.appleAppId),
561
+ clientId: optionalStr(v.clientId),
562
+ appleAppId: optionalStr(v.appleAppId ?? v.appId),
560
563
  enableDebugLog: "enableDebugLog" in v ? bool(v.enableDebugLog) : false,
561
564
  repositories: Array.isArray(v.repositories) ? v.repositories.map((x) => String(x)) : undefined,
562
565
  dependencies: parseDependencies(v.dependencies),
@@ -810,6 +813,7 @@ export function mapTopSdkGetSdkConfigToMeetSdkRemoteConfig(
810
813
  out.sdkModules.analytics.adjust = {
811
814
  appId: str(item.appId ?? item.appToken ?? item.clientId),
812
815
  clientId: optionalStr(item.clientId),
816
+ eventUrl: optionalStr(item.eventUrl ?? item.event_url),
813
817
  enableSandbox: bool(item.enableSandbox ?? item.adjustEnableSandbox),
814
818
  };
815
819
  break;
@@ -53,6 +53,10 @@ export interface WorkspaceContext {
53
53
  packageRoot: string;
54
54
  /** sdk-home API root used for latest Android/iOS SDK version discovery. */
55
55
  sdkHomeApiBaseUrl?: string;
56
+ /** Cached meetsdk-remote-config.json path for this project. */
57
+ remoteConfigPath?: string;
58
+ /** Cached iOS SDK root used as the source for integration resources. */
59
+ iosSdkRoot?: string;
56
60
  android?: AndroidDetectResult;
57
61
  /** Reserved: populated via placeholder until iOS tooling ships. */
58
62
  ios?: IOSDetectResult;
@@ -64,6 +68,10 @@ export interface WorkspaceContextOptions {
64
68
  appTarget?: string;
65
69
  /** sdk-home API root; defaults to the production MeetGames business API. */
66
70
  sdkHomeApiBaseUrl?: string;
71
+ /** Override the cached remote config path. */
72
+ remoteConfigPath?: string;
73
+ /** Override the iOS SDK source root. */
74
+ iosSdkRoot?: string;
67
75
  }
68
76
 
69
77
  export interface ManifestStep {
@@ -101,6 +109,8 @@ export interface StepResult {
101
109
  ok: boolean;
102
110
  /** Relative paths from project root that were touched or would be touched */
103
111
  changedFiles: string[];
112
+ /** Human-readable operation logs. iOS integration keeps topsdk-tool-ios style logs here. */
113
+ logs?: string[];
104
114
  warnings: string[];
105
115
  errors: string[];
106
116
  }
@@ -111,6 +121,7 @@ export interface PipelineReport {
111
121
  stepsRun: number;
112
122
  stepsSkipped: number;
113
123
  results: StepResult[];
124
+ logs?: string[];
114
125
  warnings: string[];
115
126
  errors: string[];
116
127
  }
@@ -58,8 +58,8 @@ function addCheck(report: DoctorReport, name: string, ok: boolean, details?: str
58
58
  if (!ok) report.errors.push(details ? `${name}: ${details}` : name);
59
59
  }
60
60
 
61
- function readJsonConfig(projectRoot: string): MeetSdkRemoteConfig | null {
62
- const abs = path.join(projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
61
+ function readJsonConfig(configPath: string): MeetSdkRemoteConfig | null {
62
+ const abs = configPath;
63
63
  if (!fs.existsSync(abs)) return null;
64
64
  try {
65
65
  return tryParseAsMeetSdkRemoteConfig(JSON.parse(fs.readFileSync(abs, "utf8")) as unknown);
@@ -345,7 +345,7 @@ async function checkIos(ctx: WorkspaceContext, report: DoctorReport, config: Mee
345
345
  addCheck(report, "ios.detect", false, "iOS project not detected");
346
346
  return;
347
347
  }
348
- const sdkRoot = resolveIosSdkRoot(ctx.packageRoot);
348
+ const sdkRoot = ctx.iosSdkRoot ?? resolveIosSdkRoot(ctx.packageRoot);
349
349
  const channelConfig = buildChannelConfigMap(config);
350
350
  const coreConfigs = listSdkCoreConfigs(sdkRoot);
351
351
  const pluginConfigs: LoadedPluginConfig[] = [];
@@ -359,7 +359,7 @@ async function checkIos(ctx: WorkspaceContext, report: DoctorReport, config: Mee
359
359
  }
360
360
  const loadedConfigs = [...coreConfigs, ...pluginConfigs];
361
361
  const resourceErrors = loadedConfigs.flatMap(validateLoadedPluginResourcesForDoctor);
362
- addCheck(report, "ios.bundledSdkResources", resourceErrors.length === 0, resourceErrors.join(", ") || "bundled SDK resources complete");
362
+ addCheck(report, "ios.sdkResources", resourceErrors.length === 0, resourceErrors.join(", ") || "SDK resources complete");
363
363
  const missingRequired = validateRequiredChannelConfigs(pluginConfigs, channelConfig);
364
364
  addCheck(report, "ios.remoteParams", missingRequired.length === 0, missingRequired.join(", ") || "all required plugin params present");
365
365
 
@@ -460,7 +460,7 @@ async function checkIos(ctx: WorkspaceContext, report: DoctorReport, config: Mee
460
460
  }
461
461
 
462
462
  export async function runDoctor(ctx: WorkspaceContext, platform: "android" | "ios"): Promise<DoctorReport> {
463
- const configPath = path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
463
+ const configPath = ctx.remoteConfigPath ?? path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
464
464
  const report: DoctorReport = {
465
465
  projectRoot: ctx.projectRoot,
466
466
  platform,
@@ -470,8 +470,8 @@ export async function runDoctor(ctx: WorkspaceContext, platform: "android" | "io
470
470
  warnings: [],
471
471
  errors: [],
472
472
  };
473
- const config = readJsonConfig(ctx.projectRoot);
474
- addCheck(report, "remoteConfig.existsAndParses", Boolean(config), MEETSDK_REMOTE_CONFIG_FILENAME);
473
+ const config = readJsonConfig(configPath);
474
+ addCheck(report, "remoteConfig.existsAndParses", Boolean(config), configPath);
475
475
  if (!config) {
476
476
  report.ok = false;
477
477
  return report;
@@ -51,6 +51,7 @@ export async function runPipeline(
51
51
  options: RunPipelineOptions
52
52
  ): Promise<RunPipelineResult> {
53
53
  const results: StepResult[] = [];
54
+ const logs: string[] = [];
54
55
  const warnings: string[] = [];
55
56
  const errors: string[] = [];
56
57
  let stepsRun = 0;
@@ -76,6 +77,7 @@ export async function runPipeline(
76
77
  const r = await Promise.resolve(handler(ctx, store, step.args ?? {}, options.dryRun, binaryCopies));
77
78
  results.push(r);
78
79
  stepsRun += 1;
80
+ logs.push(...(r.logs ?? []));
79
81
  warnings.push(...r.warnings);
80
82
  if (!r.ok) {
81
83
  errors.push(...r.errors);
@@ -99,6 +101,7 @@ export async function runPipeline(
99
101
  stepsRun,
100
102
  stepsSkipped,
101
103
  results,
104
+ logs,
102
105
  warnings,
103
106
  errors,
104
107
  };
@@ -3,11 +3,11 @@ import path from "node:path";
3
3
 
4
4
  /** Default directory for `pipeline.patch` / `cli-preview.patch` (gitignored). */
5
5
  export function resolveDefaultPreviewPatchDir(packageRoot: string): string {
6
- return path.join(packageRoot, "test-projects", "_preview");
6
+ return path.join(packageRoot, "preview-patches");
7
7
  }
8
8
 
9
9
  /**
10
- * Before writing a new patch under `test-projects/_preview/`, remove all existing files there
10
+ * Before writing a new patch under `preview-patches/`, remove all existing files there
11
11
  * so only the latest command output remains.
12
12
  */
13
13
  export function clearPreviewPatchFilesIfTargetInside(packageRoot: string, patchFileAbs: string): void {
@@ -3,6 +3,9 @@ import type { PipelineReport } from "../contracts/types.js";
3
3
  export function printReport(report: PipelineReport, patch: string, verbose: boolean): void {
4
4
  console.log(`[meetgames] dryRun=${report.dryRun}`);
5
5
  console.log(`[meetgames] steps run: ${report.stepsRun}, skipped: ${report.stepsSkipped}`);
6
+ if (report.logs?.length) {
7
+ for (const line of report.logs) console.log(line);
8
+ }
6
9
  if (report.warnings.length) {
7
10
  for (const w of report.warnings) console.log(`[meetgames] warning: ${w}`);
8
11
  }