windows-development-sandbox 1.25.1 → 1.27.1

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 (211) hide show
  1. package/config.example.json +12 -3
  2. package/dist/app/features/accounts/services.def.d.ts +1 -1
  3. package/dist/app/features/accounts/services.def.js +1 -1
  4. package/dist/app/features/defs.d.ts +198 -3
  5. package/dist/app/features/defs.js +8 -0
  6. package/dist/app/features/settings/categories.def.js +1 -0
  7. package/dist/app/features/unity/index.d.ts +2 -0
  8. package/dist/app/features/unity/index.js +3 -0
  9. package/dist/app/features/unity/unity.def.d.ts +294 -0
  10. package/dist/app/features/unity/unity.def.js +471 -0
  11. package/dist/app/features/unity/unity.run.d.ts +142 -0
  12. package/dist/app/features/unity/unity.run.js +363 -0
  13. package/dist/app/features/unreal/unreal.run.js +13 -3
  14. package/dist/app/registry.js +6 -0
  15. package/dist/bin/agent-sandbox.js +2 -2
  16. package/dist/bin/{chunk-G3TG4ZT7.js → chunk-4TLSWPG7.js} +1 -1
  17. package/dist/bin/{chunk-3GAXLATK.js → chunk-QUHNXHVG.js} +72 -5
  18. package/dist/bin/{chunk-F4PVBN23.js → chunk-RSIX7C6D.js} +3633 -1972
  19. package/dist/bin/claude-host.js +2 -2
  20. package/dist/bin/claude-sbx.js +2 -2
  21. package/dist/bin/codex-sbx.js +2 -2
  22. package/dist/bin/gemini-sbx.js +2 -2
  23. package/dist/bin/sandbox.js +2 -2
  24. package/dist/bin/sbx-hide.js +2 -2
  25. package/dist/bin/sbx-show.js +2 -2
  26. package/dist/cli/commands/launch/launch.js +14 -1
  27. package/dist/cli/commands/registry.js +3 -0
  28. package/dist/cli/manifest.d.ts +33 -1
  29. package/dist/cli/manifest.js +32 -1
  30. package/dist/cli/menu/coverage-exempt.js +1 -0
  31. package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
  32. package/dist/cli/menu/pages/sandbox-page.js +40 -3
  33. package/dist/cli/menu/views.js +2 -0
  34. package/dist/core/config/defaults.js +16 -3
  35. package/dist/core/schema/accounts.d.ts +3 -0
  36. package/dist/core/schema/accounts.js +1 -0
  37. package/dist/core/schema/config.d.ts +29 -13
  38. package/dist/core/schema/github.d.ts +1 -0
  39. package/dist/core/schema/github.js +3 -0
  40. package/dist/core/schema/pc-installs.d.ts +2 -1
  41. package/dist/core/schema/pc-installs.js +6 -1
  42. package/dist/core/schema/toolchains.d.ts +8 -0
  43. package/dist/core/schema/toolchains.js +19 -4
  44. package/dist/guest/accounts/adapters.js +2 -0
  45. package/dist/guest/accounts/apply.d.ts +4 -2
  46. package/dist/guest/accounts/kinds/perplexityapp.d.ts +7 -0
  47. package/dist/guest/accounts/kinds/perplexityapp.js +53 -0
  48. package/dist/guest/accounts/kinds/unity.d.ts +27 -0
  49. package/dist/guest/accounts/kinds/unity.js +164 -7
  50. package/dist/guest/apps/app-installer.js +18 -0
  51. package/dist/guest/apps/store-app.d.ts +4 -0
  52. package/dist/guest/apps/store-app.js +19 -0
  53. package/dist/guest/apps/store-check.d.ts +8 -0
  54. package/dist/guest/apps/store-check.js +33 -0
  55. package/dist/guest/boot/boot.js +1 -1
  56. package/dist/guest/boot/guide.js +18 -0
  57. package/dist/guest/browser/comet.d.ts +3 -1
  58. package/dist/guest/browser/comet.js +1 -1
  59. package/dist/guest/browser/perplexity-app.d.ts +12 -0
  60. package/dist/guest/browser/perplexity-app.js +60 -0
  61. package/dist/guest/daemon/daemon.js +2 -0
  62. package/dist/guest/devtools/devtool.d.ts +1 -1
  63. package/dist/guest/devtools/registry.js +1 -2
  64. package/dist/guest/entries/tool.js +1 -1
  65. package/dist/guest/setup/addon-mcp.d.ts +7 -2
  66. package/dist/guest/setup/addon-mcp.js +19 -9
  67. package/dist/guest/setup/github-token.js +4 -4
  68. package/dist/guest/setup/unity-agent.d.ts +11 -0
  69. package/dist/guest/setup/unity-agent.js +39 -0
  70. package/dist/guest/toolchains/engines/epic-launcher.d.ts +1 -1
  71. package/dist/guest/toolchains/engines/epic-launcher.js +11 -7
  72. package/dist/guest/toolchains/engines/unity-cli.d.ts +24 -0
  73. package/dist/guest/toolchains/engines/unity-cli.js +74 -0
  74. package/dist/guest/toolchains/engines/unity-hub.d.ts +2 -0
  75. package/dist/guest/toolchains/engines/unity-hub.js +27 -0
  76. package/dist/guest/toolchains/engines/unity-release.d.ts +4 -15
  77. package/dist/guest/toolchains/engines/unity-release.js +17 -5
  78. package/dist/guest/toolchains/engines/unity-status.d.ts +11 -0
  79. package/dist/guest/toolchains/engines/unity-status.js +39 -0
  80. package/dist/guest/toolchains/engines/unity.d.ts +20 -1
  81. package/dist/guest/toolchains/engines/unity.js +250 -3
  82. package/dist/guest/toolchains/engines/unreal-status.js +1 -1
  83. package/dist/guest/toolchains/native/mesa.js +35 -11
  84. package/dist/guest/toolchains/native/unreal.js +1 -0
  85. package/dist/guest/toolchains/plan.js +5 -1
  86. package/dist/guest/toolchains/tools/cli.js +2 -2
  87. package/dist/host/accounts/deliver.d.ts +3 -0
  88. package/dist/host/accounts/deliver.js +23 -0
  89. package/dist/host/accounts/kinds/perplexityapp.d.ts +2 -0
  90. package/dist/host/accounts/kinds/perplexityapp.js +8 -0
  91. package/dist/host/accounts/kinds/unity.d.ts +1 -1
  92. package/dist/host/accounts/kinds/unity.js +60 -8
  93. package/dist/host/accounts/leases.d.ts +2 -1
  94. package/dist/host/accounts/source.d.ts +2 -0
  95. package/dist/host/accounts/source.js +2 -0
  96. package/dist/host/accounts/sources.js +2 -0
  97. package/dist/host/apps/index.d.ts +1 -0
  98. package/dist/host/apps/index.js +2 -0
  99. package/dist/host/apps/store-package.d.ts +51 -0
  100. package/dist/host/apps/store-package.js +209 -0
  101. package/dist/host/github/deliver.d.ts +8 -3
  102. package/dist/host/github/deliver.js +42 -29
  103. package/dist/host/github/index.d.ts +1 -0
  104. package/dist/host/github/index.js +1 -0
  105. package/dist/host/github/pc-login.d.ts +27 -0
  106. package/dist/host/github/pc-login.js +129 -0
  107. package/dist/host/pc-installs/discover.d.ts +4 -0
  108. package/dist/host/pc-installs/discover.js +19 -6
  109. package/dist/host/pc-installs/epic.js +3 -0
  110. package/dist/host/pc-installs/source.d.ts +1 -1
  111. package/dist/host/pc-installs/unity-assets.d.ts +5 -0
  112. package/dist/host/pc-installs/unity-assets.js +18 -0
  113. package/dist/host/pc-installs/unity.d.ts +22 -0
  114. package/dist/host/pc-installs/unity.js +144 -2
  115. package/dist/host/pc-installs/unreal.d.ts +2 -0
  116. package/dist/host/pc-installs/unreal.js +24 -8
  117. package/dist/runtime/agent.js +116 -11
  118. package/dist/runtime/daemon.js +2205 -987
  119. package/dist/runtime/db.js +116 -11
  120. package/dist/runtime/main.js +2578 -1375
  121. package/dist/runtime/netproxy.js +116 -11
  122. package/dist/runtime/tool.js +133 -31
  123. package/dist/runtime/view.js +116 -11
  124. package/dist/selftest/agents-web.test.js +2 -1
  125. package/dist/selftest/engines.test.js +32 -3
  126. package/dist/selftest/github.test.js +64 -1
  127. package/dist/selftest/index.js +10 -0
  128. package/dist/selftest/menu-screens.js +3 -1
  129. package/dist/selftest/mixamo.test.js +1 -1
  130. package/dist/selftest/persisted-installs.test.js +1 -1
  131. package/dist/selftest/service-accounts.test.js +13 -2
  132. package/dist/selftest/store-app.test.d.ts +2 -0
  133. package/dist/selftest/store-app.test.js +162 -0
  134. package/dist/selftest/support/engine-golden.js +7 -0
  135. package/dist/selftest/support/fixtures.d.ts +10 -1
  136. package/dist/selftest/support/unity-sample.d.ts +2 -0
  137. package/dist/selftest/support/unity-sample.js +80 -0
  138. package/dist/selftest/unity-accounts.test.d.ts +2 -0
  139. package/dist/selftest/unity-accounts.test.js +106 -0
  140. package/dist/selftest/unity-agent.test.d.ts +2 -0
  141. package/dist/selftest/unity-agent.test.js +47 -0
  142. package/dist/selftest/unity-page.test.d.ts +2 -0
  143. package/dist/selftest/unity-page.test.js +177 -0
  144. package/dist/selftest/unity-setup.test.d.ts +2 -0
  145. package/dist/selftest/unity-setup.test.js +49 -0
  146. package/dist/selftest/unity.test.js +238 -3
  147. package/dist/shared/accounts/index.d.ts +1 -0
  148. package/dist/shared/accounts/index.js +1 -0
  149. package/dist/shared/accounts/kinds/unity.d.ts +28 -0
  150. package/dist/shared/accounts/kinds/unity.js +88 -0
  151. package/dist/shared/accounts/kinds.d.ts +2 -2
  152. package/dist/shared/accounts/kinds.js +23 -1
  153. package/dist/shared/accounts/payloads.d.ts +52 -0
  154. package/dist/shared/accounts/payloads.js +14 -2
  155. package/dist/shared/apps/catalogue-agents-web.d.ts +7 -0
  156. package/dist/shared/apps/catalogue-agents-web.js +23 -0
  157. package/dist/shared/apps/catalogue-gamedev.d.ts +3 -0
  158. package/dist/shared/apps/catalogue-gamedev.js +31 -0
  159. package/dist/shared/apps/catalogue.d.ts +8 -0
  160. package/dist/shared/apps/index.d.ts +3 -2
  161. package/dist/shared/apps/index.js +3 -2
  162. package/dist/shared/apps/selection.d.ts +6 -0
  163. package/dist/shared/apps/selection.js +9 -0
  164. package/dist/shared/apps/store-package.d.ts +31 -0
  165. package/dist/shared/apps/store-package.js +34 -0
  166. package/dist/shared/channel/schema.d.ts +24 -0
  167. package/dist/shared/channel/secrets.d.ts +17 -0
  168. package/dist/shared/paths/pc-installs.d.ts +1 -1
  169. package/dist/shared/paths/pc-installs.js +1 -0
  170. package/dist/shared/readiness.d.ts +2 -2
  171. package/dist/shared/readiness.js +2 -2
  172. package/dist/shared/unity/asset-cache.d.ts +20 -0
  173. package/dist/shared/unity/asset-cache.js +44 -0
  174. package/dist/shared/unity/cli.d.ts +40 -0
  175. package/dist/shared/unity/cli.js +77 -0
  176. package/dist/shared/unity/editors.d.ts +46 -0
  177. package/dist/shared/unity/editors.js +89 -0
  178. package/dist/shared/unity/guide.d.ts +9 -0
  179. package/dist/shared/unity/guide.js +84 -0
  180. package/dist/shared/unity/index.d.ts +9 -0
  181. package/dist/shared/unity/index.js +11 -0
  182. package/dist/shared/unity/manifest.d.ts +10 -0
  183. package/dist/shared/unity/manifest.js +53 -0
  184. package/dist/shared/unity/mcp.d.ts +8 -0
  185. package/dist/shared/unity/mcp.js +12 -0
  186. package/dist/shared/unity/release.d.ts +28 -0
  187. package/dist/shared/unity/release.js +83 -0
  188. package/dist/shared/unity/status.d.ts +59 -0
  189. package/dist/shared/unity/status.js +45 -0
  190. package/dist/shared/unity/version.d.ts +27 -0
  191. package/dist/shared/unity/version.js +75 -0
  192. package/dist/shared/unreal/status.d.ts +1 -0
  193. package/dist/shared/unreal/status.js +2 -0
  194. package/dist/web/index.html +1 -1
  195. package/dist/web/{main-FNE6XEHA.js → main-VPMYTSUL.js} +67 -67
  196. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  197. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  198. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  199. package/native/scripts/get-store-package.ps1 +58 -0
  200. package/package.json +1 -1
  201. package/sandbox/addons/openupm-cli/package-lock.json +2921 -0
  202. package/sandbox/addons/openupm-cli/package.json +7 -0
  203. package/sandbox/addons/unity-mcp/requirements.in +1 -0
  204. package/sandbox/addons/unity-mcp/requirements.txt +1165 -0
  205. package/sandbox/csharp/AppActivation.cs +38 -0
  206. package/sandbox/scripts/install-store-package.ps1 +28 -0
  207. package/sandbox/scripts/start-store-app.ps1 +29 -0
  208. package/schemas/config.schema.json +61 -6
  209. package/schemas/sandbox-config.schema.json +38 -5
  210. package/dist/guest/devtools/unity.d.ts +0 -2
  211. package/dist/guest/devtools/unity.js +0 -7
@@ -1,9 +1,9 @@
1
- export declare const SERVICE_KINDS: readonly ["epic", "steam", "unity", "cfx", "keystore", "play", "expo", "appstore", "perplexity", "comet"];
1
+ export declare const SERVICE_KINDS: readonly ["epic", "steam", "unity", "cfx", "keystore", "play", "expo", "appstore", "perplexity", "comet", "perplexityapp"];
2
2
  export type ServiceKind = (typeof SERVICE_KINDS)[number];
3
3
  /** The toolchains a sign-in can serve (each is a key of `toolchains`). */
4
4
  export type ToolchainUser = 'unreal' | 'steam' | 'unity' | 'fivem' | 'android' | 'flutter' | 'reactNative' | 'godot' | 'dotnet';
5
5
  /** The apps a sign-in can serve: on when one of APP_USERS' apps is in apps.install. */
6
- export type AppUser = 'perplexity' | 'comet';
6
+ export type AppUser = 'perplexity' | 'comet' | 'perplexityapp';
7
7
  /** What a sign-in serves (it is handed over only when one of them is on for the boot). */
8
8
  export type UsedBy = ToolchainUser | AppUser;
9
9
  /** The toolchains a sign-in can serve. */
@@ -13,6 +13,7 @@ export const SERVICE_KINDS = [
13
13
  'appstore',
14
14
  'perplexity',
15
15
  'comet',
16
+ 'perplexityapp',
16
17
  ];
17
18
  /** The toolchains a sign-in can serve. */
18
19
  export const USED_BY = [
@@ -30,6 +31,7 @@ export const USED_BY = [
30
31
  export const APP_USERS = {
31
32
  perplexity: ['perplexity-mcp'],
32
33
  comet: ['comet'],
34
+ perplexityapp: ['perplexity-desktop'],
33
35
  };
34
36
  export const ACCOUNT_SOURCES = ['pc', 'file', 'typed', 'sandbox'];
35
37
  const AGENT_CAN_USE = 'The agent in the sandbox can use this sign-in while it is there.';
@@ -77,7 +79,9 @@ export const SERVICE_SPECS = {
77
79
  warnings: [
78
80
  AGENT_CAN_USE,
79
81
  ONE_PLACE,
80
- 'A Pro seat is handed back when the sandbox stops cleanly; a sandbox closed abruptly may keep it until you return it.',
82
+ 'Unity Personal is activated by signing in: sign in to Unity once in a sandbox and the licence it makes is kept for the next ones (if Unity refuses it there, sign in again).',
83
+ 'A Plus or Pro serial is activated in each sandbox and handed back when the sandbox stops cleanly; a sandbox closed abruptly may keep the seat until you remove it at id.unity.com (My Seats).',
84
+ 'A licence file taken from this PC may not work in a sandbox: Unity ties it to the computer.',
81
85
  ],
82
86
  fields: [
83
87
  { name: 'email', label: 'Unity ID email', secret: false, optional: true },
@@ -206,6 +210,23 @@ export const SERVICE_SPECS = {
206
210
  ],
207
211
  fields: [],
208
212
  },
213
+ perplexityapp: {
214
+ kind: 'perplexityapp',
215
+ label: 'Perplexity desktop app',
216
+ usedBy: ['perplexityapp'],
217
+ sources: ['sandbox'],
218
+ singleHolder: false,
219
+ returns: true,
220
+ maxBytes: 256 * 1024,
221
+ warnings: [
222
+ AGENT_CAN_USE +
223
+ ' It can act as you in the Perplexity app and spend your Perplexity Computer credits; the app acts on the pages it reads, which can try to steer it.',
224
+ "Your sign-in in the Perplexity app can't be copied from this PC: Windows locks it to your PC account. Sign in once inside a sandbox and it is kept for the next ones.",
225
+ 'Only the perplexity.ai sign-in cookies are kept: never saved passwords, other sites, localStorage or history.',
226
+ 'Several sandboxes can use it at once: the sign-in the last one hands back is kept.',
227
+ ],
228
+ fields: [],
229
+ },
209
230
  };
210
231
  /** Where a sandbox leaves a renewed sign-in, under the data folder: state\accounts\<kind>.json. */
211
232
  export const HANDOFF_PARTS = ['state', 'accounts'];
@@ -218,6 +239,7 @@ export function isServiceKind(value) {
218
239
  const APP_USER_TEXT = {
219
240
  perplexity: 'the Perplexity MCP app',
220
241
  comet: 'the Comet app',
242
+ perplexityapp: 'the Perplexity desktop app',
221
243
  };
222
244
  /** What a sign-in serves, for a sentence: "unreal", "reactNative or flutter", "the Comet app". */
223
245
  export function usedByText(usedBy) {
@@ -17,6 +17,7 @@ export declare const SteamPayloadSchema: z.ZodObject<{
17
17
  /** A Unity licence file (Unity_lic.ulf), and the Unity ID to sign in with when it has to be made again. */
18
18
  export declare const UnityPayloadSchema: z.ZodObject<{
19
19
  ulf: z.ZodOptional<z.ZodString>;
20
+ entitlement: z.ZodOptional<z.ZodString>;
20
21
  email: z.ZodOptional<z.ZodString>;
21
22
  password: z.ZodOptional<z.ZodString>;
22
23
  serial: z.ZodOptional<z.ZodString>;
@@ -91,6 +92,23 @@ export declare const CometPayloadSchema: z.ZodObject<{
91
92
  }>>;
92
93
  }, z.core.$strict>>;
93
94
  }, z.core.$strict>;
95
+ /** The Perplexity desktop app's sign-in: the same perplexity.ai cookies as Comet's. */
96
+ export declare const PerplexityAppPayloadSchema: z.ZodObject<{
97
+ cookies: z.ZodArray<z.ZodObject<{
98
+ name: z.ZodString;
99
+ value: z.ZodString;
100
+ domain: z.ZodString;
101
+ path: z.ZodString;
102
+ expires: z.ZodOptional<z.ZodNumber>;
103
+ secure: z.ZodBoolean;
104
+ httpOnly: z.ZodBoolean;
105
+ sameSite: z.ZodOptional<z.ZodEnum<{
106
+ Strict: "Strict";
107
+ Lax: "Lax";
108
+ None: "None";
109
+ }>>;
110
+ }, z.core.$strict>>;
111
+ }, z.core.$strict>;
94
112
  export declare const PAYLOADS: {
95
113
  readonly epic: z.ZodObject<{
96
114
  data: z.ZodString;
@@ -106,6 +124,7 @@ export declare const PAYLOADS: {
106
124
  }, z.core.$strict>;
107
125
  readonly unity: z.ZodObject<{
108
126
  ulf: z.ZodOptional<z.ZodString>;
127
+ entitlement: z.ZodOptional<z.ZodString>;
109
128
  email: z.ZodOptional<z.ZodString>;
110
129
  password: z.ZodOptional<z.ZodString>;
111
130
  serial: z.ZodOptional<z.ZodString>;
@@ -151,6 +170,22 @@ export declare const PAYLOADS: {
151
170
  }>>;
152
171
  }, z.core.$strict>>;
153
172
  }, z.core.$strict>;
173
+ readonly perplexityapp: z.ZodObject<{
174
+ cookies: z.ZodArray<z.ZodObject<{
175
+ name: z.ZodString;
176
+ value: z.ZodString;
177
+ domain: z.ZodString;
178
+ path: z.ZodString;
179
+ expires: z.ZodOptional<z.ZodNumber>;
180
+ secure: z.ZodBoolean;
181
+ httpOnly: z.ZodBoolean;
182
+ sameSite: z.ZodOptional<z.ZodEnum<{
183
+ Strict: "Strict";
184
+ Lax: "Lax";
185
+ None: "None";
186
+ }>>;
187
+ }, z.core.$strict>>;
188
+ }, z.core.$strict>;
154
189
  };
155
190
  export type Payload<K extends ServiceKind> = z.output<(typeof PAYLOADS)[K]>;
156
191
  export type AnyPayload = Payload<ServiceKind>;
@@ -173,6 +208,7 @@ export declare const ServiceAccountsSchema: z.ZodObject<{
173
208
  }, z.core.$strict>>;
174
209
  unity: z.ZodOptional<z.ZodObject<{
175
210
  ulf: z.ZodOptional<z.ZodString>;
211
+ entitlement: z.ZodOptional<z.ZodString>;
176
212
  email: z.ZodOptional<z.ZodString>;
177
213
  password: z.ZodOptional<z.ZodString>;
178
214
  serial: z.ZodOptional<z.ZodString>;
@@ -218,6 +254,22 @@ export declare const ServiceAccountsSchema: z.ZodObject<{
218
254
  }>>;
219
255
  }, z.core.$strict>>;
220
256
  }, z.core.$strict>>;
257
+ perplexityapp: z.ZodOptional<z.ZodObject<{
258
+ cookies: z.ZodArray<z.ZodObject<{
259
+ name: z.ZodString;
260
+ value: z.ZodString;
261
+ domain: z.ZodString;
262
+ path: z.ZodString;
263
+ expires: z.ZodOptional<z.ZodNumber>;
264
+ secure: z.ZodBoolean;
265
+ httpOnly: z.ZodBoolean;
266
+ sameSite: z.ZodOptional<z.ZodEnum<{
267
+ Strict: "Strict";
268
+ Lax: "Lax";
269
+ None: "None";
270
+ }>>;
271
+ }, z.core.$strict>>;
272
+ }, z.core.$strict>>;
221
273
  }, z.core.$strict>;
222
274
  export type ServiceAccounts = z.output<typeof ServiceAccountsSchema>;
223
275
  /** A launch's id (generate.ts: "<ms>-<6 hex>"). */
@@ -33,16 +33,24 @@ export const SteamPayloadSchema = z.strictObject({
33
33
  client: base64(256 * KB).optional(),
34
34
  });
35
35
  /** A Unity licence file (Unity_lic.ulf), and the Unity ID to sign in with when it has to be made again. */
36
- export const UnityPayloadSchema = z.strictObject({
36
+ export const UnityPayloadSchema = z
37
+ .strictObject({
37
38
  ulf: z
38
39
  .string()
39
40
  .min(1)
40
41
  .max(128 * KB)
41
42
  .optional(),
43
+ /** The named-user licence (UnityEntitlementLicense.xml) a Unity sign-in makes. */
44
+ entitlement: z
45
+ .string()
46
+ .min(1)
47
+ .max(128 * KB)
48
+ .optional(),
42
49
  email: z.string().email().max(256).optional(),
43
50
  password: secretText(1024).optional(),
44
51
  serial: secretText(64).optional(),
45
- });
52
+ })
53
+ .refine((p) => Object.keys(p).length > 0, 'empty Unity sign-in');
46
54
  /** A FiveM / RedM server licence key from the Cfx.re keymaster, and an optional Steam Web API key. */
47
55
  export const CfxPayloadSchema = z.strictObject({
48
56
  licenseKey: z
@@ -125,6 +133,8 @@ export const CometCookieSchema = z.strictObject({
125
133
  export const CometPayloadSchema = z.strictObject({
126
134
  cookies: z.array(CometCookieSchema).min(1).max(MAX_COMET_COOKIES),
127
135
  });
136
+ /** The Perplexity desktop app's sign-in: the same perplexity.ai cookies as Comet's. */
137
+ export const PerplexityAppPayloadSchema = CometPayloadSchema;
128
138
  export const PAYLOADS = {
129
139
  epic: EpicPayloadSchema,
130
140
  steam: SteamPayloadSchema,
@@ -136,6 +146,7 @@ export const PAYLOADS = {
136
146
  appstore: AppstorePayloadSchema,
137
147
  perplexity: PerplexityPayloadSchema,
138
148
  comet: CometPayloadSchema,
149
+ perplexityapp: PerplexityAppPayloadSchema,
139
150
  };
140
151
  /** The secrets-file field: the sign-ins this launch hands over, each optional. */
141
152
  export const ServiceAccountsSchema = z.strictObject({
@@ -149,6 +160,7 @@ export const ServiceAccountsSchema = z.strictObject({
149
160
  appstore: AppstorePayloadSchema.optional(),
150
161
  perplexity: PerplexityPayloadSchema.optional(),
151
162
  comet: CometPayloadSchema.optional(),
163
+ perplexityapp: PerplexityAppPayloadSchema.optional(),
152
164
  });
153
165
  /** A launch's id (generate.ts: "<ms>-<6 hex>"). */
154
166
  export const LaunchIdSchema = z.string().regex(/^[A-Za-z0-9-]{1,64}$/);
@@ -14,4 +14,11 @@ export declare const COMET_DOWNLOAD_URL = "https://www.perplexity.ai/rest/browse
14
14
  * subject with E=<contact address> first (E=..., CN="PERPLEXITY AI, INC.", O=...), so CN is not at the start.
15
15
  */
16
16
  export declare const COMET_SIGNER: AppSigner;
17
+ /**
18
+ * The Perplexity desktop app is Store-only (its old installer is gone): product 9P9XG917PWCJ, an MSIX of about 300 MB.
19
+ * The package is fetched on this PC with your own Store tooling and installed in the sandbox with Add-AppxPackage.
20
+ */
21
+ export declare const PERPLEXITY_DESKTOP_PRODUCT_ID = "9P9XG917PWCJ";
22
+ export declare const PERPLEXITY_DESKTOP_PACKAGE = "PerplexityAI.PerplexityApp";
23
+ export declare const PERPLEXITY_DESKTOP_FAMILY = "PerplexityAI.PerplexityApp_3jh4kjrg4dzr2";
17
24
  export declare const AGENTS_WEB_APPS: readonly AppEntry[];
@@ -15,6 +15,13 @@ export const COMET_SIGNER = {
15
15
  subject: ['(^|, )CN="?PERPLEXITY AI, INC\\.?"?(,|$)', '(^|, )O="?PERPLEXITY AI, INC\\.?"?(,|$)'],
16
16
  issuer: ['^CN=GlobalSign GCC R45 EV CodeSigning CA 2020(,|$)'],
17
17
  };
18
+ /**
19
+ * The Perplexity desktop app is Store-only (its old installer is gone): product 9P9XG917PWCJ, an MSIX of about 300 MB.
20
+ * The package is fetched on this PC with your own Store tooling and installed in the sandbox with Add-AppxPackage.
21
+ */
22
+ export const PERPLEXITY_DESKTOP_PRODUCT_ID = '9P9XG917PWCJ';
23
+ export const PERPLEXITY_DESKTOP_PACKAGE = 'PerplexityAI.PerplexityApp';
24
+ export const PERPLEXITY_DESKTOP_FAMILY = 'PerplexityAI.PerplexityApp_3jh4kjrg4dzr2';
18
25
  /** Microsoft Edge, already in every sandbox: the browser Chrome DevTools MCP starts. */
19
26
  const EDGE_EXE = 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe';
20
27
  export const AGENTS_WEB_APPS = [
@@ -62,6 +69,22 @@ export const AGENTS_WEB_APPS = [
62
69
  signer: COMET_SIGNER,
63
70
  userOnly: true,
64
71
  },
72
+ {
73
+ id: 'perplexity-desktop',
74
+ name: 'Perplexity (desktop app)',
75
+ category: 'agents',
76
+ about: "Perplexity's desktop app, with Perplexity Computer, from the Microsoft Store. The package comes from this PC (winget with your own Microsoft Store access) and is kept on the data disk; the sandbox installs it on every boot. With accounts.perplexityapp.share on, your sign-in made in a sandbox is kept for the next ones (it cannot be copied from this PC). It acts on what it reads: use it only on what you would let it act on.",
77
+ size: '300 MB',
78
+ source: {
79
+ store: {
80
+ productId: PERPLEXITY_DESKTOP_PRODUCT_ID,
81
+ packageName: PERPLEXITY_DESKTOP_PACKAGE,
82
+ family: PERPLEXITY_DESKTOP_FAMILY,
83
+ },
84
+ },
85
+ exe: '',
86
+ userOnly: true,
87
+ },
65
88
  {
66
89
  id: 'comet-mcp',
67
90
  name: 'Comet MCP',
@@ -1,2 +1,5 @@
1
1
  import type { AppEntry } from './catalogue.js';
2
+ /** Pinned packages, installed from the lock files in sandbox\addons\<id> (renewing them: docs/toolchains.md). */
3
+ export declare const UNITY_MCP_VERSION = "10.3.0";
4
+ export declare const OPENUPM_CLI_VERSION = "4.5.3";
2
5
  export declare const GAMEDEV_APPS: readonly AppEntry[];
@@ -1,3 +1,6 @@
1
+ /** Pinned packages, installed from the lock files in sandbox\addons\<id> (renewing them: docs/toolchains.md). */
2
+ export const UNITY_MCP_VERSION = '10.3.0';
3
+ export const OPENUPM_CLI_VERSION = '4.5.3';
1
4
  export const GAMEDEV_APPS = [
2
5
  {
3
6
  id: 'krita',
@@ -68,4 +71,32 @@ export const GAMEDEV_APPS = [
68
71
  source: { github: 'nomacs/nomacs', asset: '^nomacs-portable-win\\.zip$' },
69
72
  exe: 'nomacs.exe',
70
73
  },
74
+ {
75
+ id: 'unity-mcp',
76
+ name: 'MCP for Unity',
77
+ category: 'agents',
78
+ about: 'Lets Claude Code and Codex work in an open Unity editor (CoplayDev/unity-mcp 10.3.0, MIT; Unity 2021.3 to 6.x). Your project needs its package (Unity page: Add the editor bridge). Telemetry is off.',
79
+ size: '60 MB',
80
+ source: { locked: 'uv', package: 'mcpforunityserver', version: UNITY_MCP_VERSION },
81
+ exe: 'mcp-for-unity.exe',
82
+ service: true,
83
+ mcp: {
84
+ name: 'sbx-unity-mcp',
85
+ program: true,
86
+ args: ['--transport', 'stdio'],
87
+ env: { DISABLE_TELEMETRY: '1', UNITY_MCP_DISABLE_TELEMETRY: '1', MCP_DISABLE_TELEMETRY: '1' },
88
+ codex: true,
89
+ },
90
+ plugsInto: 'Claude Code and Codex as the MCP server sbx-unity-mcp',
91
+ userOnly: true,
92
+ },
93
+ {
94
+ id: 'openupm-cli',
95
+ name: 'openupm-cli',
96
+ category: 'gamedev',
97
+ about: 'Adds OpenUPM packages to Unity projects from the command line (openupm 4.5.3, BSD-3-Clause).',
98
+ size: '15 MB',
99
+ source: { locked: 'npm', package: 'openupm-cli', version: OPENUPM_CLI_VERSION },
100
+ exe: 'openupm.cmd',
101
+ },
71
102
  ];
@@ -28,6 +28,14 @@ export type AppSource = {
28
28
  /** Nothing to download: a remote MCP server (AddonMcp.url). */
29
29
  | {
30
30
  remote: true;
31
+ }
32
+ /** A Microsoft Store app: this PC fetches the package with its own Store tooling; the sandbox installs it. */
33
+ | {
34
+ store: {
35
+ productId: string;
36
+ packageName: string;
37
+ family: string;
38
+ };
31
39
  };
32
40
  /**
33
41
  * An MCP server an add-on adds to the sandbox's Claude Code (and Codex, with `codex`): `node <its folder>\<script>
@@ -1,7 +1,8 @@
1
1
  export { type AddonMcp, type AppCategory, APP_CATEGORIES, type AppSource, type AppEntry, APPS, appById, CCUSAGE_VERSION, CONTEXT7_MCP_VERSION, HEADROOM_VERSION, PLAYWRIGHT_MCP_VERSION, RTK_VERSION, } from './catalogue.js';
2
2
  export { ASSOCIATIONS, associationPlan } from './associations.js';
3
3
  export { previewGuideLine } from './preview.js';
4
- export { exeMatcher, appsToInstall, appsNeedMesa, appsNeedUv } from './selection.js';
4
+ export { exeMatcher, appsToInstall, appsNeedMesa, appsNeedUv, storeApps } from './selection.js';
5
5
  export { signerMatches, type AppSigner, type Signature } from '../signer.js';
6
- export { AGENTS_WEB_APPS, BROWSER_USE_VERSION, CHROME_DEVTOOLS_MCP_VERSION, COMET_DOWNLOAD_URL, COMET_MCP_VERSION, COMET_SIGNER, PERPLEXITY_COMPUTER_MCP_URL, PERPLEXITY_MCP_VERSION, } from './catalogue-agents-web.js';
6
+ export { AGENTS_WEB_APPS, BROWSER_USE_VERSION, CHROME_DEVTOOLS_MCP_VERSION, COMET_DOWNLOAD_URL, PERPLEXITY_DESKTOP_FAMILY, PERPLEXITY_DESKTOP_PACKAGE, PERPLEXITY_DESKTOP_PRODUCT_ID, COMET_MCP_VERSION, COMET_SIGNER, PERPLEXITY_COMPUTER_MCP_URL, PERPLEXITY_MCP_VERSION, } from './catalogue-agents-web.js';
7
7
  export { ADDON_MCP_PREFIX, addonGuideLine, addonMcpServer, type AddonPlace, claudeManagedSettings, codexWithAddonMcpServers, type CodexMcpServer, HEADROOM_ENV, HEADROOM_PORT, HEADROOM_UPSTREAM, headroomArgs, headroomEnv, headroomGuideLine, headroomUrl, type ManagedSettings, type McpServerConfig, rtkHookCommand, RTK_GUIDE_LINE, withAddonMcpServers, } from './agent-addons.js';
8
+ export { isStorePackageFile, STORE_PACKAGE_MANIFEST, StorePackageFileSchema, StorePackageManifestSchema, storePackageRole, type StorePackageFile, type StorePackageManifest, } from './store-package.js';
@@ -1,7 +1,8 @@
1
1
  export { APP_CATEGORIES, APPS, appById, CCUSAGE_VERSION, CONTEXT7_MCP_VERSION, HEADROOM_VERSION, PLAYWRIGHT_MCP_VERSION, RTK_VERSION, } from './catalogue.js';
2
2
  export { ASSOCIATIONS, associationPlan } from './associations.js';
3
3
  export { previewGuideLine } from './preview.js';
4
- export { exeMatcher, appsToInstall, appsNeedMesa, appsNeedUv } from './selection.js';
4
+ export { exeMatcher, appsToInstall, appsNeedMesa, appsNeedUv, storeApps } from './selection.js';
5
5
  export { signerMatches } from '../signer.js';
6
- export { AGENTS_WEB_APPS, BROWSER_USE_VERSION, CHROME_DEVTOOLS_MCP_VERSION, COMET_DOWNLOAD_URL, COMET_MCP_VERSION, COMET_SIGNER, PERPLEXITY_COMPUTER_MCP_URL, PERPLEXITY_MCP_VERSION, } from './catalogue-agents-web.js';
6
+ export { AGENTS_WEB_APPS, BROWSER_USE_VERSION, CHROME_DEVTOOLS_MCP_VERSION, COMET_DOWNLOAD_URL, PERPLEXITY_DESKTOP_FAMILY, PERPLEXITY_DESKTOP_PACKAGE, PERPLEXITY_DESKTOP_PRODUCT_ID, COMET_MCP_VERSION, COMET_SIGNER, PERPLEXITY_COMPUTER_MCP_URL, PERPLEXITY_MCP_VERSION, } from './catalogue-agents-web.js';
7
7
  export { ADDON_MCP_PREFIX, addonGuideLine, addonMcpServer, claudeManagedSettings, codexWithAddonMcpServers, HEADROOM_ENV, HEADROOM_PORT, HEADROOM_UPSTREAM, headroomArgs, headroomEnv, headroomGuideLine, headroomUrl, rtkHookCommand, RTK_GUIDE_LINE, withAddonMcpServers, } from './agent-addons.js';
8
+ export { isStorePackageFile, STORE_PACKAGE_MANIFEST, StorePackageFileSchema, StorePackageManifestSchema, storePackageRole, } from './store-package.js';
@@ -11,3 +11,9 @@ export declare function appsToInstall(apps: Config['apps'], gitAccess: GitAccess
11
11
  export declare function appsNeedUv(apps: Config['apps'] | undefined): boolean;
12
12
  /** Does any chosen app draw with OpenGL (so the Mesa step must run first)? */
13
13
  export declare function appsNeedMesa(apps: Config['apps'] | undefined): boolean;
14
+ /** The chosen apps that come from the Microsoft Store: what this PC has to fetch for them. */
15
+ export declare function storeApps(install: readonly string[]): {
16
+ id: string;
17
+ productId: string;
18
+ packageName: string;
19
+ }[];
@@ -47,3 +47,12 @@ export function appsNeedUv(apps) {
47
47
  export function appsNeedMesa(apps) {
48
48
  return Boolean(apps?.install.some((id) => appById(id)?.needs?.includes('mesa')));
49
49
  }
50
+ /** The chosen apps that come from the Microsoft Store: what this PC has to fetch for them. */
51
+ export function storeApps(install) {
52
+ return install.flatMap((id) => {
53
+ const source = appById(id)?.source;
54
+ return source !== undefined && 'store' in source
55
+ ? [{ id, productId: source.store.productId, packageName: source.store.packageName }]
56
+ : [];
57
+ });
58
+ }
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ export declare const StorePackageFileSchema: z.ZodObject<{
3
+ name: z.ZodString;
4
+ role: z.ZodEnum<{
5
+ main: "main";
6
+ dependency: "dependency";
7
+ }>;
8
+ sha256: z.ZodString;
9
+ bytes: z.ZodNumber;
10
+ }, z.core.$strict>;
11
+ export type StorePackageFile = z.output<typeof StorePackageFileSchema>;
12
+ /** store-package.json: next to the package files, on this PC's cache and in the sandbox's data folder. */
13
+ export declare const StorePackageManifestSchema: z.ZodObject<{
14
+ productId: z.ZodString;
15
+ fetchedAt: z.ZodString;
16
+ files: z.ZodArray<z.ZodObject<{
17
+ name: z.ZodString;
18
+ role: z.ZodEnum<{
19
+ main: "main";
20
+ dependency: "dependency";
21
+ }>;
22
+ sha256: z.ZodString;
23
+ bytes: z.ZodNumber;
24
+ }, z.core.$strict>>;
25
+ }, z.core.$strict>;
26
+ export type StorePackageManifest = z.output<typeof StorePackageManifestSchema>;
27
+ export declare const STORE_PACKAGE_MANIFEST = "store-package.json";
28
+ /** Whether a file name is a package file this feature handles. */
29
+ export declare function isStorePackageFile(name: string): boolean;
30
+ /** The app itself (named <package name>_<version>_...), as opposed to a framework it depends on (VCLibs ...). */
31
+ export declare function storePackageRole(fileName: string, packageName: string): 'main' | 'dependency';
@@ -0,0 +1,34 @@
1
+ // A Microsoft Store app handed to the sandbox as package files (.msix and its dependencies). The PC fetches them with
2
+ // its own Store tooling (host/apps/store-package.ts) and the sandbox installs them with Add-AppxPackage.
3
+ // Pure, web-safe: the shape of the manifest that travels with the files, and which file is the app itself.
4
+ import { z } from 'zod';
5
+ const GB = 1024 * 1024 * 1024;
6
+ const FILE_NAME = /^[A-Za-z0-9._~+-]{1,200}\.(msix|appx|msixbundle|appxbundle)$/i;
7
+ export const StorePackageFileSchema = z.strictObject({
8
+ name: z.string().regex(FILE_NAME),
9
+ role: z.enum(['main', 'dependency']),
10
+ sha256: z.string().regex(/^[0-9a-f]{64}$/),
11
+ bytes: z
12
+ .number()
13
+ .int()
14
+ .positive()
15
+ .max(2 * GB),
16
+ });
17
+ /** store-package.json: next to the package files, on this PC's cache and in the sandbox's data folder. */
18
+ export const StorePackageManifestSchema = z
19
+ .strictObject({
20
+ productId: z.string().regex(/^[A-Z0-9]{12}$/),
21
+ fetchedAt: z.string().max(40),
22
+ files: z.array(StorePackageFileSchema).min(1).max(24),
23
+ })
24
+ .refine((m) => m.files.filter((f) => f.role === 'main').length === 1, 'exactly one file must be the app itself')
25
+ .refine((m) => new Set(m.files.map((f) => f.name.toLowerCase())).size === m.files.length, 'file names repeat');
26
+ export const STORE_PACKAGE_MANIFEST = 'store-package.json';
27
+ /** Whether a file name is a package file this feature handles. */
28
+ export function isStorePackageFile(name) {
29
+ return FILE_NAME.test(name);
30
+ }
31
+ /** The app itself (named <package name>_<version>_...), as opposed to a framework it depends on (VCLibs ...). */
32
+ export function storePackageRole(fileName, packageName) {
33
+ return fileName.toLowerCase().startsWith(packageName.toLowerCase() + '_') ? 'main' : 'dependency';
34
+ }
@@ -126,6 +126,14 @@ export declare const ProjectSpecSchema: z.ZodObject<{
126
126
  modules: z.ZodArray<z.ZodString>;
127
127
  hub: z.ZodBoolean;
128
128
  keepVersions: z.ZodNumber;
129
+ mcp: z.ZodBoolean;
130
+ agentSkills: z.ZodBoolean;
131
+ cliVersion: z.ZodString;
132
+ assetCache: z.ZodEnum<{
133
+ pc: "pc";
134
+ persisted: "persisted";
135
+ local: "local";
136
+ }>;
129
137
  }, z.core.$strict>;
130
138
  godot: z.ZodObject<{
131
139
  enabled: z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>;
@@ -362,6 +370,14 @@ export declare const GuestRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
362
370
  modules: z.ZodArray<z.ZodString>;
363
371
  hub: z.ZodBoolean;
364
372
  keepVersions: z.ZodNumber;
373
+ mcp: z.ZodBoolean;
374
+ agentSkills: z.ZodBoolean;
375
+ cliVersion: z.ZodString;
376
+ assetCache: z.ZodEnum<{
377
+ pc: "pc";
378
+ persisted: "persisted";
379
+ local: "local";
380
+ }>;
365
381
  }, z.core.$strict>;
366
382
  godot: z.ZodObject<{
367
383
  enabled: z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>;
@@ -618,6 +634,14 @@ export declare const GuestRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
618
634
  modules: z.ZodArray<z.ZodString>;
619
635
  hub: z.ZodBoolean;
620
636
  keepVersions: z.ZodNumber;
637
+ mcp: z.ZodBoolean;
638
+ agentSkills: z.ZodBoolean;
639
+ cliVersion: z.ZodString;
640
+ assetCache: z.ZodEnum<{
641
+ pc: "pc";
642
+ persisted: "persisted";
643
+ local: "local";
644
+ }>;
621
645
  }, z.core.$strict>;
622
646
  godot: z.ZodObject<{
623
647
  enabled: z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>;
@@ -25,6 +25,7 @@ export declare const SecretsFileSchema: z.ZodObject<{
25
25
  }, z.core.$strict>>;
26
26
  unity: z.ZodOptional<z.ZodObject<{
27
27
  ulf: z.ZodOptional<z.ZodString>;
28
+ entitlement: z.ZodOptional<z.ZodString>;
28
29
  email: z.ZodOptional<z.ZodString>;
29
30
  password: z.ZodOptional<z.ZodString>;
30
31
  serial: z.ZodOptional<z.ZodString>;
@@ -70,6 +71,22 @@ export declare const SecretsFileSchema: z.ZodObject<{
70
71
  }>>;
71
72
  }, z.core.$strict>>;
72
73
  }, z.core.$strict>>;
74
+ perplexityapp: z.ZodOptional<z.ZodObject<{
75
+ cookies: z.ZodArray<z.ZodObject<{
76
+ name: z.ZodString;
77
+ value: z.ZodString;
78
+ domain: z.ZodString;
79
+ path: z.ZodString;
80
+ expires: z.ZodOptional<z.ZodNumber>;
81
+ secure: z.ZodBoolean;
82
+ httpOnly: z.ZodBoolean;
83
+ sameSite: z.ZodOptional<z.ZodEnum<{
84
+ Strict: "Strict";
85
+ Lax: "Lax";
86
+ None: "None";
87
+ }>>;
88
+ }, z.core.$strict>>;
89
+ }, z.core.$strict>>;
73
90
  }, z.core.$strict>>;
74
91
  liveFoldersKey: z.ZodOptional<z.ZodString>;
75
92
  }, z.core.$strict>;
@@ -1,6 +1,6 @@
1
1
  /** Where this PC's installs appear in the sandbox (reserved: RESERVED_GUEST). */
2
2
  export declare const PC_INSTALLS_GUEST = "C:\\PcInstalls";
3
- export type PcInstallKind = 'steam-game' | 'steam-library' | 'epic-game' | 'unreal' | 'unreal-vault' | 'unity';
3
+ export type PcInstallKind = 'steam-game' | 'steam-library' | 'epic-game' | 'unreal' | 'unreal-vault' | 'unity' | 'unity-assets';
4
4
  export interface PcInstall {
5
5
  readonly kind: PcInstallKind;
6
6
  /** The Steam app ID or library (library1), the Epic app name, the engine (UE_5.4) or editor version. */
@@ -11,6 +11,7 @@ const AREA = {
11
11
  unreal: 'unreal',
12
12
  'unreal-vault': 'unreal',
13
13
  unity: 'unity',
14
+ 'unity-assets': 'unity',
14
15
  };
15
16
  /** The guest folder of one install: C:\PcInstalls\steam\<appid>, \epic\<AppName>, \unreal\UE_5.4, \unity\<ver>. */
16
17
  export function pcInstallGuest(kind, id) {
@@ -1,8 +1,8 @@
1
1
  export declare const NOT_READY: {
2
2
  /** Toolchains whose step is a stub: their settings rows are hidden and "auto" never turns them on. */
3
- readonly toolchains: readonly ["unity", "godot", "android", "flutter", "dart", "reactNative"];
3
+ readonly toolchains: readonly ["godot", "android", "flutter", "dart", "reactNative"];
4
4
  /** Service sign-ins whose host or guest side is a stub: the menu and the web do not list them. */
5
- readonly kinds: readonly ["unity", "keystore", "play", "expo", "appstore"];
5
+ readonly kinds: readonly ["keystore", "play", "expo", "appstore"];
6
6
  };
7
7
  export declare const isToolchainReady: (name: string) => boolean;
8
8
  export declare const isKindReady: (kind: string) => boolean;
@@ -2,9 +2,9 @@
2
2
  // entries here (the end of round 2 leaves it empty). Pure.
3
3
  export const NOT_READY = {
4
4
  /** Toolchains whose step is a stub: their settings rows are hidden and "auto" never turns them on. */
5
- toolchains: ['unity', 'godot', 'android', 'flutter', 'dart', 'reactNative'],
5
+ toolchains: ['godot', 'android', 'flutter', 'dart', 'reactNative'],
6
6
  /** Service sign-ins whose host or guest side is a stub: the menu and the web do not list them. */
7
- kinds: ['unity', 'keystore', 'play', 'expo', 'appstore'],
7
+ kinds: ['keystore', 'play', 'expo', 'appstore'],
8
8
  };
9
9
  export const isToolchainReady = (name) => !NOT_READY.toolchains.includes(name);
10
10
  export const isKindReady = (kind) => !NOT_READY.kinds.includes(kind);
@@ -0,0 +1,20 @@
1
+ export declare function assetStoreDir(root: string): string;
2
+ /** The cache roots of this PC that hold an Asset Store-5.x folder: the environment's first, then %APPDATA%\Unity. */
3
+ export declare function pcAssetCacheDirs(pc: {
4
+ readonly appData: string;
5
+ readonly envValue?: string | undefined;
6
+ }, isDir: (dir: string) => boolean): string[];
7
+ export interface AssetFs {
8
+ list(dir: string): string[];
9
+ isDir(dir: string): boolean;
10
+ /** A file's size, or null when it is a folder or missing. */
11
+ size(file: string): number | null;
12
+ }
13
+ export interface AssetPackage {
14
+ readonly publisher: string;
15
+ readonly category: string;
16
+ readonly name: string;
17
+ readonly sizeBytes: number;
18
+ }
19
+ /** The .unitypackage files in an Asset Store-5.x folder (three levels deep), sorted, at most 2000. */
20
+ export declare function assetPackages(dir: string, fs: AssetFs): AssetPackage[];
@@ -0,0 +1,44 @@
1
+ // The Unity Asset Store's download cache: <root>\Asset Store-5.x\<publisher>\<category>\<name>.unitypackage. The root
2
+ // is ASSETSTORE_CACHE_PATH, else %APPDATA%\Unity. Pure apart from the reads it is given; every walk is bounded.
3
+ import path from 'node:path';
4
+ const win = path.win32;
5
+ const MAX_PACKAGES = 2000;
6
+ const MAX_ROOTS = 2;
7
+ export function assetStoreDir(root) {
8
+ return root + '\\Asset Store-5.x';
9
+ }
10
+ /** The cache roots of this PC that hold an Asset Store-5.x folder: the environment's first, then %APPDATA%\Unity. */
11
+ export function pcAssetCacheDirs(pc, isDir) {
12
+ const all = [pc.envValue?.trim() ?? '', pc.appData ? win.join(pc.appData, 'Unity') : ''].filter(Boolean);
13
+ return all
14
+ .map((d) => win.normalize(d).replace(/\\+$/, ''))
15
+ .filter((d, i, a) => a.findIndex((o) => o.toLowerCase() === d.toLowerCase()) === i)
16
+ .filter((d) => isDir(assetStoreDir(d)))
17
+ .slice(0, MAX_ROOTS);
18
+ }
19
+ /** The .unitypackage files in an Asset Store-5.x folder (three levels deep), sorted, at most 2000. */
20
+ export function assetPackages(dir, fs) {
21
+ const found = [];
22
+ const sorted = (d) => fs.list(d).sort((a, b) => a.localeCompare(b));
23
+ for (const publisher of sorted(dir)) {
24
+ const pdir = win.join(dir, publisher);
25
+ if (!fs.isDir(pdir))
26
+ continue;
27
+ for (const category of sorted(pdir)) {
28
+ const cdir = win.join(pdir, category);
29
+ if (!fs.isDir(cdir))
30
+ continue;
31
+ for (const file of sorted(cdir)) {
32
+ if (!/\.unitypackage$/i.test(file))
33
+ continue;
34
+ const size = fs.size(win.join(cdir, file));
35
+ if (size === null)
36
+ continue;
37
+ found.push({ publisher, category, name: file.replace(/\.unitypackage$/i, ''), sizeBytes: size });
38
+ if (found.length >= MAX_PACKAGES)
39
+ return found;
40
+ }
41
+ }
42
+ }
43
+ return found;
44
+ }