@mpgd/cli 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +500 -11
  3. package/dist/microsoft-store-package-acceptance.d.ts +54 -0
  4. package/dist/microsoft-store-package-acceptance.js +787 -0
  5. package/dist/microsoft-store-package-generation-contract.d.ts +129 -0
  6. package/dist/microsoft-store-package-generation-contract.js +3 -0
  7. package/dist/microsoft-store-package-generation-download.d.ts +22 -0
  8. package/dist/microsoft-store-package-generation-download.js +453 -0
  9. package/dist/microsoft-store-package-generation-input.d.ts +3 -0
  10. package/dist/microsoft-store-package-generation-input.js +384 -0
  11. package/dist/microsoft-store-package-generation-integrity.d.ts +5 -0
  12. package/dist/microsoft-store-package-generation-integrity.js +100 -0
  13. package/dist/microsoft-store-package-generation-manifest.d.ts +3 -0
  14. package/dist/microsoft-store-package-generation-manifest.js +67 -0
  15. package/dist/microsoft-store-package-generation-zip.d.ts +1 -0
  16. package/dist/microsoft-store-package-generation-zip.js +180 -0
  17. package/dist/microsoft-store-package-generation.d.ts +24 -0
  18. package/dist/microsoft-store-package-generation.js +430 -0
  19. package/dist/microsoft-store-starter.d.ts +28 -0
  20. package/dist/microsoft-store-starter.js +655 -0
  21. package/dist/microsoft-store-submission.d.ts +79 -0
  22. package/dist/microsoft-store-submission.js +952 -0
  23. package/dist/microsoft-store-supported-locales.d.ts +1 -0
  24. package/dist/microsoft-store-supported-locales.js +33 -0
  25. package/dist/production-target-readiness.js +3 -1
  26. package/package.json +9 -8
  27. package/templates/phaser-game/.agents/skills/release-microsoft-store/SKILL.md +60 -0
  28. package/templates/phaser-game/.agents/skills/release-microsoft-store/agents/openai.yaml +4 -0
  29. package/templates/phaser-game/.agents/skills/use-mpgd-kit/SKILL.md +45 -0
  30. package/templates/phaser-game/.agents/skills/use-mpgd-kit/agents/openai.yaml +4 -0
  31. package/templates/phaser-game/AGENTS.md +34 -0
  32. package/templates/phaser-game/README.md +88 -25
  33. package/templates/phaser-game/agent/acceptance.md +8 -0
  34. package/templates/phaser-game/agent/brief.md +13 -1
  35. package/templates/phaser-game/agent/game-manifest.json +7 -0
  36. package/templates/phaser-game/apps/target-ait/granite.config.ts +35 -0
  37. package/templates/phaser-game/apps/target-ait/index.html +15 -0
  38. package/templates/phaser-game/apps/target-ait/package.json +33 -0
  39. package/templates/phaser-game/apps/target-ait/src/main.ts +34 -0
  40. package/templates/phaser-game/apps/target-ait/src/styles.css +33 -0
  41. package/templates/phaser-game/apps/target-ait/tsconfig.json +8 -0
  42. package/templates/phaser-game/apps/target-ait/vite.config.ts +53 -0
  43. package/templates/phaser-game/docs/MPGD_KIT_WORKFLOWS.md +128 -0
  44. package/templates/phaser-game/gitignore +7 -0
  45. package/templates/phaser-game/mpgd.microsoft-store.json +29 -0
  46. package/templates/phaser-game/mpgd.targets.json +9 -2
  47. package/templates/phaser-game/package.json +11 -9
  48. package/templates/phaser-game/vite.shared.ts +13 -0
@@ -0,0 +1,33 @@
1
+ html,
2
+ body,
3
+ #app {
4
+ width: 100%;
5
+ height: 100%;
6
+ margin: 0;
7
+ }
8
+
9
+ body {
10
+ background: #101820;
11
+ color: #f8fafc;
12
+ font-family:
13
+ Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
14
+ }
15
+
16
+ .shell {
17
+ min-height: 100%;
18
+ display: grid;
19
+ place-content: center;
20
+ gap: 12px;
21
+ padding: 24px;
22
+ box-sizing: border-box;
23
+ text-align: center;
24
+ }
25
+
26
+ h1,
27
+ p {
28
+ margin: 0;
29
+ }
30
+
31
+ code {
32
+ color: #fff7ad;
33
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": ["vite/client", "node"],
5
+ "noEmit": true
6
+ },
7
+ "include": ["src/**/*.ts", "vite.config.ts", "granite.config.ts"]
8
+ }
@@ -0,0 +1,53 @@
1
+ import { readFileSync } from 'node:fs';
2
+
3
+ import aitDevtools from '@ait-co/devtools/unplugin';
4
+ import { extractAitAdBridgeConfig } from '@mpgd/adapter-ait/ad-config';
5
+ import ttsc from '@ttsc/unplugin/vite';
6
+ import { defineConfig } from 'vite';
7
+
8
+ const isTruthyEnv = (value: string | undefined): boolean =>
9
+ value !== undefined && value !== '' && value !== '0' && value.toLowerCase() !== 'false';
10
+ const aitDevtoolsTunnel = isTruthyEnv(process.env.AIT_TUNNEL)
11
+ ? { cdp: isTruthyEnv(process.env.AIT_TUNNEL_CDP) }
12
+ : false;
13
+ const aitAppName = process.env.MPGD_AIT_APP_NAME?.trim() || '__GAME_NAME__';
14
+ const aitAdConfig = readAitAdConfig(process.env.MPGD_AD_PLACEMENTS_FILE);
15
+
16
+ export default defineConfig(({ command, isPreview }) => ({
17
+ define: {
18
+ __MPGD_AIT_APP_NAME__: JSON.stringify(aitAppName),
19
+ __MPGD_AIT_AD_GROUP_IDS__: JSON.stringify(aitAdConfig.adGroupIds),
20
+ __MPGD_AIT_AD_PLACEMENT_TYPES__: JSON.stringify(aitAdConfig.adPlacementTypes),
21
+ },
22
+ plugins: [
23
+ ...(command === 'serve' && !isPreview && process.env.MPGD_AIT_DEVTOOLS !== '0'
24
+ ? [aitDevtools.vite({ mcp: true, tunnel: aitDevtoolsTunnel })]
25
+ : []),
26
+ ttsc({ project: 'tsconfig.json', plugins: false }),
27
+ ],
28
+ build: {
29
+ target: 'es2022',
30
+ outDir: 'dist',
31
+ emptyOutDir: true,
32
+ },
33
+ }));
34
+
35
+ function readAitAdConfig(path: string | undefined): {
36
+ readonly adGroupIds: Readonly<Record<string, string>>;
37
+ readonly adPlacementTypes: Readonly<Record<string, 'rewarded' | 'interstitial'>>;
38
+ } {
39
+ if (path === undefined || path.trim().length === 0) {
40
+ return { adGroupIds: {}, adPlacementTypes: {} };
41
+ }
42
+
43
+ let parsed: unknown;
44
+ try {
45
+ parsed = JSON.parse(readFileSync(path, 'utf8')) as unknown;
46
+ } catch (error) {
47
+ throw new Error(`AIT ad placements file is unreadable or invalid JSON: ${path}`, {
48
+ cause: error,
49
+ });
50
+ }
51
+
52
+ return extractAitAdBridgeConfig(parsed, path);
53
+ }
@@ -0,0 +1,128 @@
1
+ # mpgd-kit workflows
2
+
3
+ This guide is the capability map for this generated game. Start with
4
+ `agent/game-manifest.json`: configured targets are available now; `futureTargets`
5
+ are design directions, not implemented release paths.
6
+
7
+ ## Core boundaries
8
+
9
+ | Concern | Owner |
10
+ | --- | --- |
11
+ | Deterministic rules and state | `src/game` and simulation modules |
12
+ | Rendering and input | `src/scenes` |
13
+ | Platform selection and services | `src/platform` through `PlatformGateway` |
14
+ | Target build ownership | `mpgd.targets.json` |
15
+ | Runtime/effective configuration | `@mpgd/target-config` and target config files |
16
+ | Agent capability and acceptance contract | `agent/` |
17
+
18
+ Do not import platform SDKs into scenes or pure game logic. Add a capability to
19
+ `PlatformGateway`, implement it behind an adapter or wrapper, and provide a
20
+ capability-disabled fallback where the target cannot support it.
21
+
22
+ ## Shared game capabilities
23
+
24
+ ### Assets and icons
25
+
26
+ - Keep Phaser-loadable assets in the game-owned asset manifest.
27
+ - Replace starter icons, then run `pnpm icons:generate`, `pnpm icons:verify`,
28
+ and optionally `pnpm icons:inspect`.
29
+ - Use target icon profiles from `mpgd.targets.json`; do not maintain unrelated
30
+ hand-copied icon sets.
31
+
32
+ ### Localization and orientation
33
+
34
+ - Add game text through the generated i18n messages and resolve locale from the
35
+ effective target configuration.
36
+ - Choose a responsive, preferred, or soft-lock orientation policy before
37
+ building resize and rotate-prompt behavior. Keep the installed web manifest
38
+ orientation aligned with the runtime policy.
39
+
40
+ ### Analytics, saves, commerce, ads, and leaderboards
41
+
42
+ - Emit best-effort analytics through `@mpgd/analytics`; never depend on a debug
43
+ or analytics side effect for game correctness.
44
+ - Route identity, saves, lifecycle, host presentation, commerce, ads, and
45
+ leaderboards through `PlatformGateway`.
46
+ - Use `@mpgd/game-services` and a game-owned backend for purchase ledgers,
47
+ rewarded-ad grants, entitlements, and verified leaderboard records. Client
48
+ success callbacks are requests or pending evidence, never grant authority.
49
+
50
+ ## Build and acceptance loop
51
+
52
+ Use `MPGD_KIT_PATH` or pass `--kit-path` to a nearby kit checkout.
53
+
54
+ ```sh
55
+ pnpm check
56
+ pnpm build
57
+ pnpm icons:verify
58
+ pnpm exec mpgd target doctor --targets-file ./mpgd.targets.json --kit-path ../mpgd-kit --targets default
59
+ pnpm exec mpgd target build-all --targets-file ./mpgd.targets.json --kit-path ../mpgd-kit --targets default --profile staging --ait-variant wrapper
60
+ pnpm exec mpgd target smoke-all --targets-file ./mpgd.targets.json --kit-path ../mpgd-kit --targets default
61
+ pnpm accept
62
+ ```
63
+
64
+ `pnpm accept` records checks, build, graph preflight, optional browser playtest,
65
+ target build/smoke, and optional gameplay E2E results under
66
+ `artifacts/acceptance`. Add a game-owned `playtest` or `gameplay:e2e` driver
67
+ when the release needs stronger browser or state-path evidence.
68
+
69
+ ## Target routing
70
+
71
+ ### Browser preview
72
+
73
+ Use the browser adapter for local and hosted web behavior. Verify installed-PWA
74
+ updates without forcing service-worker activation while old windows remain
75
+ open.
76
+
77
+ ### Microsoft Store
78
+
79
+ This target is optional. Enable it in an existing generated game with:
80
+
81
+ ```sh
82
+ pnpm exec mpgd target init microsoft-store --game . --kit-path ../mpgd-kit
83
+ ```
84
+
85
+ The initializer adds the target, scripts, PWA runtime hook, Store config, and
86
+ `.agents/skills/release-microsoft-store/SKILL.md` without overwriting conflicts.
87
+ Use that skill for the complete release and evidence sequence.
88
+
89
+ ### Verse8
90
+
91
+ Build through the Verse8 adapter. Keep host credentials and authenticated cloud
92
+ state behind target services. Treat client commerce as pending; authoritative
93
+ grants belong in a game-owned Agent8 server purchase event with consume-once
94
+ catalog handling and verified completion logic for leaderboards.
95
+
96
+ ### Apps in Toss
97
+
98
+ Use official Apps in Toss documentation/MCP before SDK or review-flow changes.
99
+ Keep SDK imports in the wrapper/adapter, declare permission-gated Web APIs in
100
+ the game-owned config, and create a game-owned production wrapper instead of
101
+ shipping the kit reference wrapper.
102
+
103
+ ### Reddit Devvit
104
+
105
+ Keep the app in `apps/target-devvit`, use official Devvit documentation/MCP,
106
+ and keep SDK calls behind the adapter or wrapper. Preserve separate lightweight
107
+ inline and expanded game modes, avoid trapping feed scroll, and validate login,
108
+ init, upload, and playtest with the generated scripts.
109
+
110
+ ### Android and iOS
111
+
112
+ Use a game-owned Capacitor shell for production. Keep native plugin imports in
113
+ the shell, adapters, or native plugins; configure signing outside source
114
+ control. Validate the web game and effective target config before native store
115
+ packaging.
116
+
117
+ ### Future targets
118
+
119
+ For Telegram, Tauri, or another platform, first add a target-config entry and
120
+ adapter behind `PlatformGateway`, then add build, smoke, agent manifest, and
121
+ acceptance coverage. Do not let a new SDK leak into existing game logic.
122
+
123
+ ## Handoff evidence
124
+
125
+ Keep source revision, config, build/smoke results, gameplay evidence, target
126
+ preflight, artifact hashes, and target acceptance reports together. A generic
127
+ kit smoke test proves the reusable contract only; it does not replace
128
+ game-owned production credentials, deployment, signing, or store evidence.
@@ -1,8 +1,15 @@
1
1
  node_modules/
2
2
  dist/
3
3
  apps/*/dist/
4
+ apps/target-ait/.ait_relay
5
+ apps/target-ait/.ait_urls
6
+ apps/target-ait/.granite/
7
+ apps/target-ait/generated/
8
+ apps/target-ait/public/assets/
9
+ apps/target-ait/public/game/
4
10
  apps/target-devvit/generated/
5
11
  artifacts/
12
+ release-input/
6
13
  release-output/
7
14
  .mpgd.targets.generated.json
8
15
  .mpgd/
@@ -0,0 +1,29 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "productIdentity": {
4
+ "packageId": "REPLACE_ME",
5
+ "publisherId": "CN=REPLACE_ME",
6
+ "publisherDisplayName": "REPLACE_ME",
7
+ "reservedName": "REPLACE_ME"
8
+ },
9
+ "listing": {
10
+ "category": "Games",
11
+ "supportUrl": "https://example.com/support",
12
+ "personalData": {
13
+ "accessedOrTransmitted": true,
14
+ "privacyPolicyUrl": "https://example.com/privacy"
15
+ },
16
+ "locales": {
17
+ "en-US": {
18
+ "description": "REPLACE_ME",
19
+ "screenshots": ["store-assets/en-US/01.png"]
20
+ }
21
+ }
22
+ },
23
+ "ageRating": {
24
+ "questionnaireCompleted": false
25
+ },
26
+ "commerce": {
27
+ "mode": "disabled"
28
+ }
29
+ }
@@ -42,10 +42,17 @@
42
42
  "ait": {
43
43
  "kind": "apps-in-toss",
44
44
  "gameApp": ".",
45
- "wrapperApp": "${MPGD_KIT_PATH}/apps/target-ait",
45
+ "wrapperApp": "apps/target-ait",
46
46
  "adapter": "ait",
47
+ "authoritativeGameServices": false,
48
+ "metadata": {
49
+ "appName": "__GAME_NAME__",
50
+ "displayName": "__GAME_TITLE__",
51
+ "primaryColor": "#101820",
52
+ "sdkMajor": 2
53
+ },
47
54
  "icon": { "profile": "ait" },
48
- "webDir": "${MPGD_KIT_PATH}/apps/target-ait/public/game",
55
+ "webDir": "apps/target-ait/public/game",
49
56
  "artifact": ".ait"
50
57
  },
51
58
  "reddit": {
@@ -6,7 +6,7 @@
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "dev": "__WORKSPACE_I18N_BUILD_PREFIX__vite --host 0.0.0.0",
9
- "dev:ait": "APP_TARGET=ait APP_VERSION=0.0.0-dev BUILD_ID=ait-sandbox sh -c '__WORKSPACE_I18N_BUILD_PREFIX__vite --host 0.0.0.0'",
9
+ "dev:ait": "APP_TARGET=ait MPGD_CONFIG_TARGET=ait MPGD_PLATFORM_TARGETS_FILE=./mpgd.targets.json APP_VERSION=0.0.0-dev BUILD_ID=ait-sandbox sh -c '__WORKSPACE_I18N_BUILD_PREFIX__vite --host 0.0.0.0'",
10
10
  "build": "__WORKSPACE_I18N_BUILD_PREFIX__vite build",
11
11
  "accept": "node ./tools/run-game-acceptance.mjs",
12
12
  "icons:generate": "pnpm exec mpgd game icons generate . --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
@@ -17,19 +17,21 @@
17
17
  "build:ait": "pnpm exec mpgd target build ait staging --variant wrapper --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
18
18
  "build:ait:package": "pnpm exec mpgd target build ait production --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
19
19
  "smoke:ait": "pnpm exec mpgd target smoke ait --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
20
- "ait:wrapper:dev": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run dev",
21
- "ait:wrapper:dev:plain": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run dev:plain",
22
- "ait:wrapper:dev:phone": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run dev:phone",
23
- "ait:devtools:mcp": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run devtools:mcp",
24
- "ait:devtools:mcp:mobile": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run devtools:mcp:mobile",
20
+ "ait:wrapper:dev": "pnpm --dir apps/target-ait run dev",
21
+ "ait:wrapper:dev:plain": "pnpm --dir apps/target-ait run dev:plain",
22
+ "ait:wrapper:dev:phone": "pnpm --dir apps/target-ait run dev:phone",
23
+ "ait:devtools:mcp": "pnpm --dir apps/target-ait run devtools:mcp",
24
+ "ait:devtools:mcp:mobile": "pnpm --dir apps/target-ait run devtools:mcp:mobile",
25
25
  "ait:console:login": "aitcc login",
26
26
  "ait:console:whoami": "aitcc whoami",
27
27
  "ait:console:init": "aitcc app init",
28
28
  "ait:console:register": "aitcc app register",
29
29
  "ait:console:status": "aitcc app status",
30
30
  "ait:console:deploy": "aitcc app deploy",
31
- "build:microsoft-store": "pnpm exec mpgd target build microsoft-store production --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
32
- "smoke:microsoft-store": "pnpm exec mpgd target smoke microsoft-store --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
31
+ "build:microsoft-store": "pnpm exec mpgd target build microsoft-store production --targets-file ./mpgd.targets.json --kit-path \"${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}\"",
32
+ "smoke:microsoft-store": "pnpm exec mpgd target smoke microsoft-store --targets-file ./mpgd.targets.json --kit-path \"${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}\"",
33
+ "preflight:microsoft-store": "pnpm exec mpgd target preflight microsoft-store --targets-file ./mpgd.targets.json --kit-path \"${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}\"",
34
+ "package:microsoft-store": "pnpm exec mpgd target generate-package microsoft-store --targets-file ./mpgd.targets.json",
33
35
  "build:verse8": "pnpm exec mpgd target build verse8 production --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
34
36
  "smoke:verse8": "pnpm exec mpgd target smoke verse8 --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
35
37
  "build:devvit": "pnpm exec mpgd target build reddit production --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
@@ -56,7 +58,7 @@
56
58
  },
57
59
  "dependencies": {
58
60
  "@ait-co/polyfill": "^0.1.17",
59
- "@apps-in-toss/web-framework": "^2.10.4",
61
+ "@apps-in-toss/web-framework": "^2.10.6",
60
62
  "@mpgd/adapter-ait": "__MPGD_DEPENDENCY_VERSION_ADAPTER_AIT__",
61
63
  "@mpgd/adapter-browser": "__MPGD_DEPENDENCY_VERSION_ADAPTER_BROWSER__",
62
64
  "@mpgd/adapter-capacitor": "__MPGD_DEPENDENCY_VERSION_ADAPTER_CAPACITOR__",
@@ -7,6 +7,7 @@ import type { UserConfig } from 'vite';
7
7
  interface RuntimePlatformTargetMetadata {
8
8
  readonly kind: string;
9
9
  readonly adapter: string;
10
+ readonly authoritativeGameServices?: boolean;
10
11
  readonly integrations?: Record<string, unknown>;
11
12
  }
12
13
 
@@ -174,9 +175,21 @@ function readRuntimePlatformTarget(
174
175
  throw new Error(`Platform target ${configTarget} integrations must be an object.`);
175
176
  }
176
177
 
178
+ if (
179
+ target.authoritativeGameServices !== undefined
180
+ && typeof target.authoritativeGameServices !== 'boolean'
181
+ ) {
182
+ throw new Error(
183
+ `Platform target ${configTarget} authoritativeGameServices must be a boolean.`,
184
+ );
185
+ }
186
+
177
187
  return {
178
188
  kind: target.kind,
179
189
  adapter: target.adapter,
190
+ ...(target.authoritativeGameServices === undefined
191
+ ? {}
192
+ : { authoritativeGameServices: target.authoritativeGameServices }),
180
193
  ...(target.integrations === undefined ? {} : { integrations: target.integrations }),
181
194
  };
182
195
  }