primitive-admin 1.1.0-alpha.7 → 1.1.0-alpha.71

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 (438) hide show
  1. package/README.md +404 -80
  2. package/assets/skill/skills/primitive-platform/SKILL.md +808 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +294 -21
  5. package/dist/bin/primitive.js.map +1 -1
  6. package/dist/src/commands/admins.d.ts +2 -0
  7. package/dist/src/commands/admins.js +138 -19
  8. package/dist/src/commands/admins.js.map +1 -1
  9. package/dist/src/commands/analytics.d.ts +2 -0
  10. package/dist/src/commands/analytics.js +544 -55
  11. package/dist/src/commands/analytics.js.map +1 -1
  12. package/dist/src/commands/apps.d.ts +2 -0
  13. package/dist/src/commands/apps.js +51 -96
  14. package/dist/src/commands/apps.js.map +1 -1
  15. package/dist/src/commands/auth.d.ts +2 -0
  16. package/dist/src/commands/auth.js +177 -7
  17. package/dist/src/commands/auth.js.map +1 -1
  18. package/dist/src/commands/blob-buckets.d.ts +2 -0
  19. package/dist/src/commands/blob-buckets.js +330 -0
  20. package/dist/src/commands/blob-buckets.js.map +1 -0
  21. package/dist/src/commands/catalog.d.ts +2 -0
  22. package/dist/src/commands/catalog.js +37 -38
  23. package/dist/src/commands/catalog.js.map +1 -1
  24. package/dist/src/commands/collection-type-configs.d.ts +2 -0
  25. package/dist/src/commands/collection-type-configs.js +92 -0
  26. package/dist/src/commands/collection-type-configs.js.map +1 -0
  27. package/dist/src/commands/collections.d.ts +2 -0
  28. package/dist/src/commands/collections.js +565 -0
  29. package/dist/src/commands/collections.js.map +1 -0
  30. package/dist/src/commands/comparisons.d.ts +2 -0
  31. package/dist/src/commands/comparisons.js +6 -6
  32. package/dist/src/commands/comparisons.js.map +1 -1
  33. package/dist/src/commands/config.d.ts +46 -0
  34. package/dist/src/commands/config.js +479 -0
  35. package/dist/src/commands/config.js.map +1 -0
  36. package/dist/src/commands/connections.d.ts +2 -0
  37. package/dist/src/commands/connections.js +100 -0
  38. package/dist/src/commands/connections.js.map +1 -0
  39. package/dist/src/commands/cron-triggers.d.ts +2 -0
  40. package/dist/src/commands/cron-triggers.js +265 -0
  41. package/dist/src/commands/cron-triggers.js.map +1 -0
  42. package/dist/src/commands/database-type-configs.d.ts +2 -0
  43. package/dist/src/commands/database-type-configs.js +171 -0
  44. package/dist/src/commands/database-type-configs.js.map +1 -0
  45. package/dist/src/commands/database-types.d.ts +2 -0
  46. package/dist/src/commands/database-types.js +471 -0
  47. package/dist/src/commands/database-types.js.map +1 -0
  48. package/dist/src/commands/databases.d.ts +65 -0
  49. package/dist/src/commands/databases.js +2140 -112
  50. package/dist/src/commands/databases.js.map +1 -1
  51. package/dist/src/commands/documents.d.ts +2 -0
  52. package/dist/src/commands/documents.js +1357 -19
  53. package/dist/src/commands/documents.js.map +1 -1
  54. package/dist/src/commands/email-templates.d.ts +2 -0
  55. package/dist/src/commands/email-templates.js +174 -0
  56. package/dist/src/commands/email-templates.js.map +1 -0
  57. package/dist/src/commands/env.d.ts +23 -0
  58. package/dist/src/commands/env.js +333 -0
  59. package/dist/src/commands/env.js.map +1 -0
  60. package/dist/src/commands/feature-flags.d.ts +14 -0
  61. package/dist/src/commands/feature-flags.js +116 -0
  62. package/dist/src/commands/feature-flags.js.map +1 -0
  63. package/dist/src/commands/group-type-configs.d.ts +2 -0
  64. package/dist/src/commands/group-type-configs.js +86 -0
  65. package/dist/src/commands/group-type-configs.js.map +1 -0
  66. package/dist/src/commands/groups.d.ts +2 -0
  67. package/dist/src/commands/groups.js +38 -99
  68. package/dist/src/commands/groups.js.map +1 -1
  69. package/dist/src/commands/guides.d.ts +223 -0
  70. package/dist/src/commands/guides.js +617 -65
  71. package/dist/src/commands/guides.js.map +1 -1
  72. package/dist/src/commands/init.d.ts +25 -0
  73. package/dist/src/commands/init.js +1605 -208
  74. package/dist/src/commands/init.js.map +1 -1
  75. package/dist/src/commands/integrations.d.ts +2 -0
  76. package/dist/src/commands/integrations.js +380 -178
  77. package/dist/src/commands/integrations.js.map +1 -1
  78. package/dist/src/commands/llm.d.ts +2 -0
  79. package/dist/src/commands/llm.js +4 -2
  80. package/dist/src/commands/llm.js.map +1 -1
  81. package/dist/src/commands/locks.d.ts +8 -0
  82. package/dist/src/commands/locks.js +160 -0
  83. package/dist/src/commands/locks.js.map +1 -0
  84. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  85. package/dist/src/commands/metadata-category-configs.js +112 -0
  86. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  87. package/dist/src/commands/metadata.d.ts +2 -0
  88. package/dist/src/commands/metadata.js +281 -0
  89. package/dist/src/commands/metadata.js.map +1 -0
  90. package/dist/src/commands/prompts.d.ts +2 -0
  91. package/dist/src/commands/prompts.js +225 -584
  92. package/dist/src/commands/prompts.js.map +1 -1
  93. package/dist/src/commands/rule-sets.d.ts +3 -0
  94. package/dist/src/commands/rule-sets.js +272 -0
  95. package/dist/src/commands/rule-sets.js.map +1 -0
  96. package/dist/src/commands/scripts.d.ts +20 -0
  97. package/dist/src/commands/scripts.js +554 -0
  98. package/dist/src/commands/scripts.js.map +1 -0
  99. package/dist/src/commands/secrets.d.ts +2 -0
  100. package/dist/src/commands/secrets.js +108 -0
  101. package/dist/src/commands/secrets.js.map +1 -0
  102. package/dist/src/commands/sessions.d.ts +2 -0
  103. package/dist/src/commands/sessions.js +75 -0
  104. package/dist/src/commands/sessions.js.map +1 -0
  105. package/dist/src/commands/skill.d.ts +2 -0
  106. package/dist/src/commands/skill.js +29 -0
  107. package/dist/src/commands/skill.js.map +1 -0
  108. package/dist/src/commands/sync-app-settings.d.ts +158 -0
  109. package/dist/src/commands/sync-app-settings.js +330 -0
  110. package/dist/src/commands/sync-app-settings.js.map +1 -0
  111. package/dist/src/commands/sync.d.ts +2323 -0
  112. package/dist/src/commands/sync.js +15065 -843
  113. package/dist/src/commands/sync.js.map +1 -1
  114. package/dist/src/commands/tokens.d.ts +2 -0
  115. package/dist/src/commands/tokens.js +130 -21
  116. package/dist/src/commands/tokens.js.map +1 -1
  117. package/dist/src/commands/users.d.ts +2 -0
  118. package/dist/src/commands/users.js +532 -23
  119. package/dist/src/commands/users.js.map +1 -1
  120. package/dist/src/commands/vars.d.ts +8 -0
  121. package/dist/src/commands/vars.js +96 -0
  122. package/dist/src/commands/vars.js.map +1 -0
  123. package/dist/src/commands/waitlist.d.ts +2 -0
  124. package/dist/src/commands/waitlist.js +10 -10
  125. package/dist/src/commands/waitlist.js.map +1 -1
  126. package/dist/src/commands/webhooks.d.ts +2 -0
  127. package/dist/src/commands/webhooks.js +562 -0
  128. package/dist/src/commands/webhooks.js.map +1 -0
  129. package/dist/src/commands/workflows.d.ts +116 -0
  130. package/dist/src/commands/workflows.js +1583 -681
  131. package/dist/src/commands/workflows.js.map +1 -1
  132. package/dist/src/lib/access-rule-display.d.ts +21 -0
  133. package/dist/src/lib/access-rule-display.js +34 -0
  134. package/dist/src/lib/access-rule-display.js.map +1 -0
  135. package/dist/src/lib/api-client.d.ts +1936 -0
  136. package/dist/src/lib/api-client.js +1826 -138
  137. package/dist/src/lib/api-client.js.map +1 -1
  138. package/dist/src/lib/app-settings-descriptor.d.ts +263 -0
  139. package/dist/src/lib/app-settings-descriptor.js +575 -0
  140. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  141. package/dist/src/lib/auth-flow.d.ts +8 -0
  142. package/dist/src/lib/batch.d.ts +26 -0
  143. package/dist/src/lib/batch.js +32 -0
  144. package/dist/src/lib/batch.js.map +1 -0
  145. package/dist/src/lib/block-layout.d.ts +160 -0
  146. package/dist/src/lib/block-layout.js +451 -0
  147. package/dist/src/lib/block-layout.js.map +1 -0
  148. package/dist/src/lib/canonical-json.d.ts +12 -0
  149. package/dist/src/lib/canonical-json.js +35 -0
  150. package/dist/src/lib/canonical-json.js.map +1 -0
  151. package/dist/src/lib/channel.d.ts +30 -0
  152. package/dist/src/lib/channel.js +68 -0
  153. package/dist/src/lib/channel.js.map +1 -0
  154. package/dist/src/lib/cli-manifest.d.ts +68 -0
  155. package/dist/src/lib/cli-manifest.js +71 -0
  156. package/dist/src/lib/cli-manifest.js.map +1 -0
  157. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +101 -0
  158. package/dist/src/lib/codegen-shared/generatedFiles.js +191 -0
  159. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  160. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  161. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  162. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  163. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +68 -0
  164. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +168 -0
  165. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  166. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  167. package/dist/src/lib/config-object-descriptor.js +658 -0
  168. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  169. package/dist/src/lib/config-payload.d.ts +85 -0
  170. package/dist/src/lib/config-payload.js +116 -0
  171. package/dist/src/lib/config-payload.js.map +1 -0
  172. package/dist/src/lib/config-surface.d.ts +130 -0
  173. package/dist/src/lib/config-surface.js +300 -0
  174. package/dist/src/lib/config-surface.js.map +1 -0
  175. package/dist/src/lib/config-toml.d.ts +10 -0
  176. package/dist/src/lib/config-toml.js +42 -0
  177. package/dist/src/lib/config-toml.js.map +1 -0
  178. package/dist/src/lib/config.d.ts +53 -0
  179. package/dist/src/lib/config.js +92 -53
  180. package/dist/src/lib/config.js.map +1 -1
  181. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  182. package/dist/src/lib/confirm-prompt.js +110 -0
  183. package/dist/src/lib/confirm-prompt.js.map +1 -0
  184. package/dist/src/lib/constants.d.ts +11 -0
  185. package/dist/src/lib/constants.js +12 -0
  186. package/dist/src/lib/constants.js.map +1 -0
  187. package/dist/src/lib/crash-handlers.d.ts +20 -0
  188. package/dist/src/lib/crash-handlers.js +49 -0
  189. package/dist/src/lib/crash-handlers.js.map +1 -0
  190. package/dist/src/lib/credentials-store.d.ts +89 -0
  191. package/dist/src/lib/credentials-store.js +330 -0
  192. package/dist/src/lib/credentials-store.js.map +1 -0
  193. package/dist/src/lib/csv.d.ts +47 -0
  194. package/dist/src/lib/csv.js +172 -0
  195. package/dist/src/lib/csv.js.map +1 -0
  196. package/dist/src/lib/data-input.d.ts +23 -0
  197. package/dist/src/lib/data-input.js +50 -0
  198. package/dist/src/lib/data-input.js.map +1 -0
  199. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  200. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  201. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  202. package/dist/src/lib/db-codegen/dbGenerator.d.ts +67 -0
  203. package/dist/src/lib/db-codegen/dbGenerator.js +170 -0
  204. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  205. package/dist/src/lib/db-codegen/dbNaming.d.ts +87 -0
  206. package/dist/src/lib/db-codegen/dbNaming.js +180 -0
  207. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  208. package/dist/src/lib/db-codegen/dbTemplates.d.ts +272 -0
  209. package/dist/src/lib/db-codegen/dbTemplates.js +480 -0
  210. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  211. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +73 -0
  212. package/dist/src/lib/db-codegen/dbTsTypes.js +139 -0
  213. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  214. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  215. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  216. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  217. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  218. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  219. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  220. package/dist/src/lib/env-resolver-core.d.ts +147 -0
  221. package/dist/src/lib/env-resolver-core.js +265 -0
  222. package/dist/src/lib/env-resolver-core.js.map +1 -0
  223. package/dist/src/lib/env-resolver.d.ts +84 -0
  224. package/dist/src/lib/env-resolver.js +133 -0
  225. package/dist/src/lib/env-resolver.js.map +1 -0
  226. package/dist/src/lib/fetch.d.ts +5 -0
  227. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  228. package/dist/src/lib/generated-allowlist.js +277 -0
  229. package/dist/src/lib/generated-allowlist.js.map +1 -0
  230. package/dist/src/lib/generated-config-surfaces.d.ts +682 -0
  231. package/dist/src/lib/generated-config-surfaces.js +4058 -0
  232. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  233. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  234. package/dist/src/lib/generated-template-lint.js +624 -0
  235. package/dist/src/lib/generated-template-lint.js.map +1 -0
  236. package/dist/src/lib/init-adopt.d.ts +16 -0
  237. package/dist/src/lib/init-adopt.js +34 -0
  238. package/dist/src/lib/init-adopt.js.map +1 -0
  239. package/dist/src/lib/init-assets.d.ts +39 -0
  240. package/dist/src/lib/init-assets.js +97 -0
  241. package/dist/src/lib/init-assets.js.map +1 -0
  242. package/dist/src/lib/init-config.d.ts +98 -0
  243. package/dist/src/lib/init-config.js +186 -0
  244. package/dist/src/lib/init-config.js.map +1 -0
  245. package/dist/src/lib/init-ios-links.d.ts +50 -0
  246. package/dist/src/lib/init-ios-links.js +153 -0
  247. package/dist/src/lib/init-ios-links.js.map +1 -0
  248. package/dist/src/lib/init-plan.d.ts +80 -0
  249. package/dist/src/lib/init-plan.js +95 -0
  250. package/dist/src/lib/init-plan.js.map +1 -0
  251. package/dist/src/lib/init-production-env.d.ts +48 -0
  252. package/dist/src/lib/init-production-env.js +59 -0
  253. package/dist/src/lib/init-production-env.js.map +1 -0
  254. package/dist/src/lib/init-schema.d.ts +74 -0
  255. package/dist/src/lib/init-schema.js +358 -0
  256. package/dist/src/lib/init-schema.js.map +1 -0
  257. package/dist/src/lib/init-xcode.d.ts +33 -0
  258. package/dist/src/lib/init-xcode.js +114 -0
  259. package/dist/src/lib/init-xcode.js.map +1 -0
  260. package/dist/src/lib/integration-request-config.d.ts +30 -0
  261. package/dist/src/lib/integration-request-config.js +145 -0
  262. package/dist/src/lib/integration-request-config.js.map +1 -0
  263. package/dist/src/lib/local-state.d.ts +55 -0
  264. package/dist/src/lib/local-state.js +167 -0
  265. package/dist/src/lib/local-state.js.map +1 -0
  266. package/dist/src/lib/log-inspection.d.ts +568 -0
  267. package/dist/src/lib/log-inspection.js +639 -0
  268. package/dist/src/lib/log-inspection.js.map +1 -0
  269. package/dist/src/lib/migration-nag.d.ts +49 -0
  270. package/dist/src/lib/migration-nag.js +163 -0
  271. package/dist/src/lib/migration-nag.js.map +1 -0
  272. package/dist/src/lib/object-status-filter.d.ts +22 -0
  273. package/dist/src/lib/object-status-filter.js +45 -0
  274. package/dist/src/lib/object-status-filter.js.map +1 -0
  275. package/dist/src/lib/output.d.ts +109 -0
  276. package/dist/src/lib/output.js +191 -8
  277. package/dist/src/lib/output.js.map +1 -1
  278. package/dist/src/lib/package-manager.d.ts +140 -0
  279. package/dist/src/lib/package-manager.js +305 -0
  280. package/dist/src/lib/package-manager.js.map +1 -0
  281. package/dist/src/lib/paginate.d.ts +83 -0
  282. package/dist/src/lib/paginate.js +95 -0
  283. package/dist/src/lib/paginate.js.map +1 -0
  284. package/dist/src/lib/platform-owned.d.ts +63 -0
  285. package/dist/src/lib/platform-owned.js +85 -0
  286. package/dist/src/lib/platform-owned.js.map +1 -0
  287. package/dist/src/lib/project-config.d.ts +97 -0
  288. package/dist/src/lib/project-config.js +217 -0
  289. package/dist/src/lib/project-config.js.map +1 -0
  290. package/dist/src/lib/query-operators.d.ts +43 -0
  291. package/dist/src/lib/query-operators.js +80 -0
  292. package/dist/src/lib/query-operators.js.map +1 -0
  293. package/dist/src/lib/record-filter.d.ts +18 -0
  294. package/dist/src/lib/record-filter.js +55 -0
  295. package/dist/src/lib/record-filter.js.map +1 -0
  296. package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
  297. package/dist/src/lib/refresh-admin-credentials.js +103 -0
  298. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  299. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  300. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  301. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  302. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  303. package/dist/src/lib/resolve-init-server.js +77 -0
  304. package/dist/src/lib/resolve-init-server.js.map +1 -0
  305. package/dist/src/lib/resolve-platform.d.ts +74 -0
  306. package/dist/src/lib/resolve-platform.js +105 -0
  307. package/dist/src/lib/resolve-platform.js.map +1 -0
  308. package/dist/src/lib/run-status.d.ts +19 -0
  309. package/dist/src/lib/run-status.generated.d.ts +39 -0
  310. package/dist/src/lib/run-status.generated.js +66 -0
  311. package/dist/src/lib/run-status.generated.js.map +1 -0
  312. package/dist/src/lib/run-status.js +19 -0
  313. package/dist/src/lib/run-status.js.map +1 -0
  314. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  315. package/dist/src/lib/server-text-normalization.js +90 -0
  316. package/dist/src/lib/server-text-normalization.js.map +1 -0
  317. package/dist/src/lib/server-url.d.ts +22 -0
  318. package/dist/src/lib/server-url.js +33 -0
  319. package/dist/src/lib/server-url.js.map +1 -0
  320. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  321. package/dist/src/lib/signing-secret-status.js +116 -0
  322. package/dist/src/lib/signing-secret-status.js.map +1 -0
  323. package/dist/src/lib/skill-installer.d.ts +25 -0
  324. package/dist/src/lib/skill-installer.js +266 -0
  325. package/dist/src/lib/skill-installer.js.map +1 -0
  326. package/dist/src/lib/snapshots.d.ts +99 -0
  327. package/dist/src/lib/snapshots.js +357 -0
  328. package/dist/src/lib/snapshots.js.map +1 -0
  329. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +113 -0
  330. package/dist/src/lib/swift-codegen/dbGenerator.js +914 -0
  331. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  332. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  333. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  334. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  335. package/dist/src/lib/swift-codegen/generator.d.ts +94 -0
  336. package/dist/src/lib/swift-codegen/generator.js +440 -0
  337. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  338. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  339. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  340. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  341. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +94 -0
  342. package/dist/src/lib/swift-codegen/siblingSymbols.js +155 -0
  343. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  344. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  345. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  346. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  347. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  348. package/dist/src/lib/sync-dir-selector.js +30 -0
  349. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  350. package/dist/src/lib/sync-paths.d.ts +111 -0
  351. package/dist/src/lib/sync-paths.js +198 -0
  352. package/dist/src/lib/sync-paths.js.map +1 -0
  353. package/dist/src/lib/sync-resource-types.d.ts +544 -0
  354. package/dist/src/lib/sync-resource-types.js +975 -0
  355. package/dist/src/lib/sync-resource-types.js.map +1 -0
  356. package/dist/src/lib/sync-selectors.d.ts +95 -0
  357. package/dist/src/lib/sync-selectors.js +228 -0
  358. package/dist/src/lib/sync-selectors.js.map +1 -0
  359. package/dist/src/lib/template.d.ts +170 -0
  360. package/dist/src/lib/template.js +484 -68
  361. package/dist/src/lib/template.js.map +1 -1
  362. package/dist/src/lib/test-case-keys.d.ts +29 -0
  363. package/dist/src/lib/test-case-keys.js +55 -0
  364. package/dist/src/lib/test-case-keys.js.map +1 -0
  365. package/dist/src/lib/test-case-variables.d.ts +15 -0
  366. package/dist/src/lib/test-case-variables.js +29 -0
  367. package/dist/src/lib/test-case-variables.js.map +1 -0
  368. package/dist/src/lib/token-inject.d.ts +56 -0
  369. package/dist/src/lib/token-inject.js +204 -0
  370. package/dist/src/lib/token-inject.js.map +1 -0
  371. package/dist/src/lib/toml-database-config.d.ts +123 -0
  372. package/dist/src/lib/toml-database-config.js +527 -0
  373. package/dist/src/lib/toml-database-config.js.map +1 -0
  374. package/dist/src/lib/toml-metadata-config.d.ts +151 -0
  375. package/dist/src/lib/toml-metadata-config.js +476 -0
  376. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  377. package/dist/src/lib/toml-native-form.d.ts +46 -0
  378. package/dist/src/lib/toml-native-form.js +78 -0
  379. package/dist/src/lib/toml-native-form.js.map +1 -0
  380. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  381. package/dist/src/lib/toml-params-validator.js +298 -0
  382. package/dist/src/lib/toml-params-validator.js.map +1 -0
  383. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  384. package/dist/src/lib/toml-scalar-edit.js +283 -0
  385. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  386. package/dist/src/lib/user-selector.d.ts +24 -0
  387. package/dist/src/lib/user-selector.js +33 -0
  388. package/dist/src/lib/user-selector.js.map +1 -0
  389. package/dist/src/lib/version-check.d.ts +35 -0
  390. package/dist/src/lib/version-check.js +241 -0
  391. package/dist/src/lib/version-check.js.map +1 -0
  392. package/dist/src/lib/watch.d.ts +121 -0
  393. package/dist/src/lib/watch.js +169 -0
  394. package/dist/src/lib/watch.js.map +1 -0
  395. package/dist/src/lib/workflow-apply.d.ts +110 -0
  396. package/dist/src/lib/workflow-apply.js +164 -0
  397. package/dist/src/lib/workflow-apply.js.map +1 -0
  398. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
  399. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
  400. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  401. package/dist/src/lib/workflow-codegen/generator.d.ts +96 -0
  402. package/dist/src/lib/workflow-codegen/generator.js +361 -0
  403. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  404. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +94 -0
  405. package/dist/src/lib/workflow-codegen/invokerIR.js +76 -0
  406. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  407. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  408. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  409. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  410. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +80 -0
  411. package/dist/src/lib/workflow-codegen/schemaToTs.js +303 -0
  412. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  413. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  414. package/dist/src/lib/workflow-config-apply.js +137 -0
  415. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  416. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  417. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  418. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  419. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  420. package/dist/src/lib/workflow-defaults.js +41 -0
  421. package/dist/src/lib/workflow-defaults.js.map +1 -0
  422. package/dist/src/lib/workflow-fragments.d.ts +64 -0
  423. package/dist/src/lib/workflow-fragments.js +342 -0
  424. package/dist/src/lib/workflow-fragments.js.map +1 -0
  425. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  426. package/dist/src/lib/workflow-include-preserve.js +286 -0
  427. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  428. package/dist/src/lib/workflow-payload.d.ts +98 -0
  429. package/dist/src/lib/workflow-payload.js +178 -0
  430. package/dist/src/lib/workflow-payload.js.map +1 -0
  431. package/dist/src/lib/workflow-toml-validator.d.ts +202 -0
  432. package/dist/src/lib/workflow-toml-validator.js +757 -0
  433. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  434. package/dist/src/types/index.d.ts +581 -0
  435. package/dist/src/validators.d.ts +65 -0
  436. package/dist/src/validators.js +64 -0
  437. package/dist/src/validators.js.map +1 -0
  438. package/package.json +32 -8
@@ -1,8 +1,50 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, renameSync, rmSync, statSync, } from "fs";
1
+ import { cpSync, existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "fs";
2
+ import { execFileSync } from "child_process";
2
3
  import { join } from "path";
4
+ import { tmpdir } from "os";
3
5
  import * as tar from "tar";
4
- const TEMPLATE_URL = "https://github.com/Primitive-Labs/primitive-app-template/archive/refs/heads/main.tar.gz";
6
+ import { PRODUCTION_SERVER_URL } from "./constants.js";
7
+ import { installArgv, PRIMITIVE_CLI_PACKAGE } from "./package-manager.js";
8
+ import { resolveChannelBranch, DEFAULT_CHANNEL_BRANCH } from "./channel.js";
9
+ // Mirror repos pushed from this monorepo at publish time:
10
+ // templates/primitive-vue-template via scripts/sync-vue-template.mjs, and
11
+ // templates/primitive-swift-template via scripts/publish-swift-packages.sh.
12
+ // The branch is the channel (issue #1934): `main` = production, `alpha` =
13
+ // the alpha environment (its Primitive deps are pinned to the alpha
14
+ // prerelease npm versions / mirror branches).
15
+ export function vueTemplateUrl(branch = DEFAULT_CHANNEL_BRANCH) {
16
+ return `https://github.com/Primitive-Labs/primitive-vue-template/archive/refs/heads/${branch}.tar.gz`;
17
+ }
18
+ export function iosTemplateUrl(branch = DEFAULT_CHANNEL_BRANCH) {
19
+ return `https://api.github.com/repos/Primitive-Labs/primitive-swift-template/tarball/${branch}`;
20
+ }
21
+ const TEMPLATE_URL = vueTemplateUrl();
22
+ const IOS_TEMPLATE_URL = iosTemplateUrl();
23
+ /**
24
+ * Resolve which template branch `primitive init` scaffolds from — same
25
+ * precedence as `primitive guides` (see resolveChannelBranch): the
26
+ * undocumented `PRIMITIVE_TEMPLATE_BRANCH` override (validated), then alpha
27
+ * server-URL detection, then `main`.
28
+ */
29
+ export function resolveTemplateBranch(serverUrl, override = process.env.PRIMITIVE_TEMPLATE_BRANCH) {
30
+ return resolveChannelBranch(serverUrl, override, "PRIMITIVE_TEMPLATE_BRANCH");
31
+ }
5
32
  const DOWNLOAD_TIMEOUT_MS = 30000; // 30 seconds
33
+ /**
34
+ * Tries to get a GitHub token from the gh CLI for authenticated downloads.
35
+ * Returns null if gh is not installed or not authenticated.
36
+ */
37
+ async function getGitHubToken() {
38
+ const { execSync } = await import("child_process");
39
+ try {
40
+ return execSync("gh auth token", { stdio: ["ignore", "pipe", "ignore"] })
41
+ .toString()
42
+ .trim();
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
6
48
  /**
7
49
  * Check if a directory is empty.
8
50
  */
@@ -13,21 +55,21 @@ export function isDirectoryEmpty(dir) {
13
55
  const files = readdirSync(dir);
14
56
  return files.length === 0;
15
57
  }
16
- /**
17
- * Downloads and extracts the Primitive app template.
18
- * The tarball extracts to a subfolder, so we strip that prefix by moving contents up.
19
- */
20
- export async function downloadAndExtractTemplate(options) {
21
- const { targetDir, onProgress } = options;
22
- // Ensure target directory exists
23
- mkdirSync(targetDir, { recursive: true });
24
- onProgress?.("Downloading template...");
58
+ async function fetchTemplateTarball(url) {
25
59
  // Fetch the tarball with timeout
26
60
  const controller = new AbortController();
27
61
  const timeout = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS);
28
62
  let response;
29
63
  try {
30
- response = await fetch(TEMPLATE_URL, { signal: controller.signal });
64
+ const headers = {
65
+ "User-Agent": "primitive-cli",
66
+ };
67
+ // For private repos, use GitHub token if available (from gh CLI)
68
+ const ghToken = await getGitHubToken();
69
+ if (ghToken) {
70
+ headers["Authorization"] = `token ${ghToken}`;
71
+ }
72
+ response = await fetch(url, { signal: controller.signal, headers });
31
73
  }
32
74
  catch (err) {
33
75
  clearTimeout(timeout);
@@ -43,50 +85,118 @@ export async function downloadAndExtractTemplate(options) {
43
85
  throw new Error(`Failed to download template: HTTP ${response.status}`);
44
86
  }
45
87
  const arrayBuffer = await response.arrayBuffer();
46
- const buffer = Buffer.from(arrayBuffer);
47
- onProgress?.("Extracting template...");
48
- // Create a temporary directory for extraction
49
- const tempDir = join(targetDir, ".primitive-temp-" + Date.now());
50
- mkdirSync(tempDir, { recursive: true });
51
- // Write buffer to temp file and extract
52
- const tempTarPath = join(tempDir, "template.tar.gz");
53
- writeFileSync(tempTarPath, buffer);
54
- // Extract tarball using tar
55
- await tar.extract({
56
- file: tempTarPath,
57
- cwd: tempDir,
58
- });
59
- // Remove the temp tarball
60
- rmSync(tempTarPath);
61
- // Find the extracted directory (e.g., "primitive-app-template-main")
62
- const extractedItems = readdirSync(tempDir);
63
- if (extractedItems.length !== 1) {
64
- throw new Error(`Unexpected template structure: expected 1 directory, found ${extractedItems.length}`);
65
- }
66
- const extractedDir = join(tempDir, extractedItems[0]);
67
- // Verify it's a directory
68
- if (!statSync(extractedDir).isDirectory()) {
69
- throw new Error("Unexpected template structure: expected a directory");
70
- }
71
- // Move contents to target directory
72
- for (const item of readdirSync(extractedDir)) {
73
- const src = join(extractedDir, item);
74
- const dest = join(targetDir, item);
75
- // Remove existing item if it exists (for overwrite scenarios)
76
- if (existsSync(dest)) {
77
- rmSync(dest, { recursive: true, force: true });
88
+ return Buffer.from(arrayBuffer);
89
+ }
90
+ async function downloadTemplateBuffer(options) {
91
+ const { onProgress, onFallback, fallbackTemplateUrl } = options;
92
+ onProgress?.("Downloading template...");
93
+ try {
94
+ return await fetchTemplateTarball(options.templateUrl || TEMPLATE_URL);
95
+ }
96
+ catch (err) {
97
+ if (!fallbackTemplateUrl)
98
+ throw err;
99
+ // A channel branch that hasn't been pushed yet 404s — fall back to the
100
+ // default branch rather than failing the scaffold.
101
+ onFallback?.(err.message);
102
+ return await fetchTemplateTarball(fallbackTemplateUrl);
103
+ }
104
+ }
105
+ /**
106
+ * Downloads and validates the Primitive app template in a temporary staging
107
+ * directory. Nothing is written to the final target directory until install()
108
+ * is called.
109
+ */
110
+ export async function prepareTemplate(options = {}) {
111
+ const tempDir = mkdtempSync(join(tmpdir(), "primitive-template-"));
112
+ try {
113
+ const buffer = await downloadTemplateBuffer(options);
114
+ options.onProgress?.("Extracting template...");
115
+ const extractRoot = join(tempDir, "extract");
116
+ mkdirSync(extractRoot, { recursive: true });
117
+ const tempTarPath = join(tempDir, "template.tar.gz");
118
+ writeFileSync(tempTarPath, buffer);
119
+ await tar.extract({
120
+ file: tempTarPath,
121
+ cwd: extractRoot,
122
+ });
123
+ rmSync(tempTarPath);
124
+ // Find the extracted directory (e.g., "primitive-vue-template-main")
125
+ const extractedItems = readdirSync(extractRoot);
126
+ if (extractedItems.length !== 1) {
127
+ throw new Error(`Unexpected template structure: expected 1 directory, found ${extractedItems.length}`);
128
+ }
129
+ const extractedDir = join(extractRoot, extractedItems[0]);
130
+ // Verify it's a directory
131
+ if (!statSync(extractedDir).isDirectory()) {
132
+ throw new Error("Unexpected template structure: expected a directory");
78
133
  }
79
- renameSync(src, dest);
134
+ options.onProgress?.("Template downloaded and validated.");
135
+ return {
136
+ install(targetDir) {
137
+ // Ensure target directory exists
138
+ mkdirSync(targetDir, { recursive: true });
139
+ // Move contents to target directory
140
+ for (const item of readdirSync(extractedDir)) {
141
+ const src = join(extractedDir, item);
142
+ const dest = join(targetDir, item);
143
+ // Remove existing item if it exists (for overwrite scenarios)
144
+ if (existsSync(dest)) {
145
+ rmSync(dest, { recursive: true, force: true });
146
+ }
147
+ cpSync(src, dest, { recursive: true, force: true });
148
+ }
149
+ },
150
+ cleanup() {
151
+ rmSync(tempDir, { recursive: true, force: true });
152
+ },
153
+ };
154
+ }
155
+ catch (err) {
156
+ rmSync(tempDir, { recursive: true, force: true });
157
+ throw err;
158
+ }
159
+ }
160
+ /**
161
+ * Derives VITE_API_URL and VITE_WS_URL from a server URL.
162
+ * https:// → wss://, http:// → ws://
163
+ */
164
+ function deriveEnvUrls(serverUrl) {
165
+ const apiUrl = serverUrl.replace(/\/+$/, "");
166
+ if (!/^https?:\/\//.test(apiUrl)) {
167
+ throw new Error(`Invalid server URL (must start with http:// or https://): ${apiUrl}`);
168
+ }
169
+ const wsUrl = apiUrl
170
+ .replace(/^https:\/\//, "wss://")
171
+ .replace(/^http:\/\//, "ws://");
172
+ return { apiUrl, wsUrl };
173
+ }
174
+ /**
175
+ * Replaces a key=value pair in env file content IF the key is already there.
176
+ *
177
+ * Replace-only, deliberately (#2873): the Vue template no longer authors the
178
+ * identity keys — `primitiveEnv()` fills them from `.primitive/config.json` —
179
+ * so appending one would re-create the second source of truth this change
180
+ * removed, and `cf-deploy` treats an identity key in a `.env` file as a hard
181
+ * error. An OLD template still carries the keys, and those must keep being
182
+ * filled in, which is exactly what "replace if present" does.
183
+ */
184
+ function setEnvVar(content, key, value) {
185
+ const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
186
+ const pattern = new RegExp(`^${escapedKey}=.*`, "m");
187
+ // Quote values that contain characters dotenv would misparse (# starts
188
+ // a comment, leading/trailing whitespace is stripped, etc.)
189
+ const formatted = /[#\n]/.test(value) ? `"${value.replace(/"/g, '\\"')}"` : value;
190
+ if (pattern.test(content)) {
191
+ return content.replace(pattern, `${key}=${formatted}`);
80
192
  }
81
- // Clean up temp directory
82
- rmSync(tempDir, { recursive: true, force: true });
83
- onProgress?.("Template extracted successfully.");
193
+ return content;
84
194
  }
85
195
  /**
86
- * Updates a single env file with the app ID.
196
+ * Updates a single env file with the app ID and server URLs.
87
197
  * Returns true if the file was updated, false if it didn't exist.
88
198
  */
89
- function updateSingleEnvFile(envPath, appId, fallbackPath) {
199
+ function updateSingleEnvFile(envPath, appId, serverUrl, appName, fallbackPath) {
90
200
  let envContent = "";
91
201
  // If file doesn't exist but fallback does, copy from fallback
92
202
  if (!existsSync(envPath) && fallbackPath && existsSync(fallbackPath)) {
@@ -98,29 +208,34 @@ function updateSingleEnvFile(envPath, appId, fallbackPath) {
98
208
  else {
99
209
  return false;
100
210
  }
101
- // Update or add VITE_APP_ID
102
- if (envContent.includes("VITE_APP_ID=")) {
103
- envContent = envContent.replace(/VITE_APP_ID=.*/, `VITE_APP_ID=${appId}`);
104
- }
105
- else {
106
- envContent = envContent.trimEnd() + `\nVITE_APP_ID=${appId}\n`;
211
+ envContent = setEnvVar(envContent, "VITE_APP_ID", appId);
212
+ if (appName) {
213
+ envContent = setEnvVar(envContent, "VITE_APP_NAME", appName);
107
214
  }
215
+ const { apiUrl, wsUrl } = deriveEnvUrls(serverUrl);
216
+ envContent = setEnvVar(envContent, "VITE_API_URL", apiUrl);
217
+ envContent = setEnvVar(envContent, "VITE_WS_URL", wsUrl);
108
218
  writeFileSync(envPath, envContent.trimEnd() + "\n");
109
219
  return true;
110
220
  }
111
221
  /**
112
- * Updates .env and .env.production files with the app ID.
222
+ * Updates .env and .env.production files with the app ID and server URLs.
113
223
  * For .env, if it doesn't exist but .env.example does, copies from example first.
114
224
  * Returns information about which files were updated.
225
+ *
226
+ * `production` names the backend/app pair a production build should talk to.
227
+ * Omit it and `.env.production` points at the hosted production server with
228
+ * this app id — the historical behavior, which is correct for an app created
229
+ * there and wrong for one created anywhere else, so composed runs derive the
230
+ * pair from the project's own environments and pass it in (#2890).
115
231
  */
116
- export function updateEnvFile(targetDir, appId) {
232
+ export function updateEnvFile(targetDir, appId, serverUrl, appName, production) {
117
233
  const envPath = join(targetDir, ".env");
118
234
  const envExamplePath = join(targetDir, ".env.example");
119
235
  const envProductionPath = join(targetDir, ".env.production");
120
236
  // Update .env (create from .env.example if needed)
121
- const envUpdated = updateSingleEnvFile(envPath, appId, envExamplePath);
122
- // Update .env.production if it exists
123
- const envProductionUpdated = updateSingleEnvFile(envProductionPath, appId);
237
+ const envUpdated = updateSingleEnvFile(envPath, appId, serverUrl, appName, envExamplePath);
238
+ const envProductionUpdated = updateSingleEnvFile(envProductionPath, production?.appId ?? appId, production?.serverUrl ?? PRODUCTION_SERVER_URL, production?.appName ?? appName);
124
239
  return { envUpdated, envProductionUpdated };
125
240
  }
126
241
  /**
@@ -183,14 +298,14 @@ export async function installPnpmGlobally() {
183
298
  });
184
299
  }
185
300
  /**
186
- * Checks if the primitive CLI (primitive-admin) is installed globally.
187
- * Uses npm list -g to check for actual global installation, not just
188
- * temporary availability via npx.
301
+ * Checks if the primitive CLI is installed and available in PATH.
302
+ * Checks for the `primitive` command directly, which covers installs via
303
+ * npm, pnpm, yarn, or any other package manager.
189
304
  */
190
305
  export async function isPrimitiveCliInstalled() {
191
306
  const { execSync } = await import("child_process");
192
307
  try {
193
- execSync("npm list -g primitive-admin", { stdio: "ignore" });
308
+ execSync("primitive --version", { stdio: "ignore" });
194
309
  return true;
195
310
  }
196
311
  catch {
@@ -198,12 +313,313 @@ export async function isPrimitiveCliInstalled() {
198
313
  }
199
314
  }
200
315
  /**
201
- * Installs the primitive CLI (primitive-admin) globally using npm.
316
+ * Initializes a git repository in the target directory.
317
+ */
318
+ async function spawnGit(args, cwd) {
319
+ const { spawn } = await import("child_process");
320
+ return new Promise((resolve, reject) => {
321
+ const proc = spawn("git", args, {
322
+ cwd,
323
+ stdio: "ignore",
324
+ shell: process.platform === "win32",
325
+ });
326
+ proc.on("close", (code) => {
327
+ if (code === 0) {
328
+ resolve();
329
+ }
330
+ else {
331
+ reject(new Error(`git ${args[0]} exited with code ${code}`));
332
+ }
333
+ });
334
+ proc.on("error", reject);
335
+ });
336
+ }
337
+ export async function gitInitRepo(targetDir) {
338
+ await spawnGit(["init"], targetDir);
339
+ }
340
+ export async function gitInitialCommit(targetDir) {
341
+ await spawnGit(["add", "-A"], targetDir);
342
+ await spawnGit(["commit", "--allow-empty", "-m", "Initial Commit"], targetDir);
343
+ }
344
+ /**
345
+ * Tries to connect to `host:port`. Returns true if something answered
346
+ * (port occupied), false if the connection was refused (port free).
347
+ */
348
+ function canConnect(port, host) {
349
+ return new Promise((resolve) => {
350
+ import("net").then(({ createConnection }) => {
351
+ const socket = createConnection({ port, host });
352
+ socket.once("connect", () => {
353
+ socket.destroy();
354
+ resolve(true);
355
+ });
356
+ socket.once("error", () => resolve(false));
357
+ });
358
+ });
359
+ }
360
+ /**
361
+ * Checks whether a TCP port is currently in use on localhost.
362
+ * Tries both IPv4 (127.0.0.1) and IPv6 (::1) since a server may only
363
+ * bind to one address family.
364
+ */
365
+ export async function isPortFree(port) {
366
+ const [v4, v6] = await Promise.all([
367
+ canConnect(port, "127.0.0.1"),
368
+ canConnect(port, "::1"),
369
+ ]);
370
+ return !v4 && !v6;
371
+ }
372
+ /**
373
+ * Locates the `{` that opens the configuration object literal of a vite
374
+ * config, so a `server` block can be inserted into it. Returns null when the
375
+ * shape isn't one we can patch safely.
376
+ *
377
+ * The shipped template exports `defineConfig(({ mode }) => { ... return {...} })`,
378
+ * so matching only `defineConfig({` — as this used to — silently patched
379
+ * nothing (#2720).
380
+ */
381
+ function findConfigObjectStart(content) {
382
+ const call = /defineConfig\s*\(\s*/.exec(content);
383
+ if (call) {
384
+ const afterCall = call.index + call[0].length;
385
+ // `defineConfig({ ... })` — a direct object literal.
386
+ if (content[afterCall] === "{")
387
+ return afterCall;
388
+ // `defineConfig((env) => ...)` — an arrow function, with either a concise
389
+ // object body or a block body that returns the config.
390
+ const arrow = /^(?:async\s+)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>\s*/.exec(content.slice(afterCall));
391
+ if (arrow) {
392
+ const body = afterCall + arrow[0].length;
393
+ // Concise body: `=> ({ ... })`.
394
+ const concise = /^\(\s*\{/.exec(content.slice(body));
395
+ if (concise)
396
+ return body + concise[0].length - 1;
397
+ // Block body: the config is whatever the function returns.
398
+ if (content[body] === "{") {
399
+ const ret = /\breturn\s*\{/.exec(content.slice(body));
400
+ if (ret)
401
+ return body + ret.index + ret[0].length - 1;
402
+ }
403
+ }
404
+ }
405
+ // `export default { ... }` — a plain object config, no `defineConfig`.
406
+ const plain = /export\s+default\s*\{/.exec(content);
407
+ if (plain)
408
+ return plain.index + plain[0].length - 1;
409
+ return null;
410
+ }
411
+ /** Indentation of the line the given offset sits on. */
412
+ function indentOfLineAt(content, index) {
413
+ const lineStart = content.lastIndexOf("\n", index) + 1;
414
+ return /^[ \t]*/.exec(content.slice(lineStart, index))?.[0] ?? "";
415
+ }
416
+ /**
417
+ * Pins `server.port` in the source of a vite config. Returns the patched
418
+ * source, or null when the config's shape is one we can't patch — the caller
419
+ * must not claim success in that case.
420
+ *
421
+ * Exported for tests, which pin this against the real shipped template.
422
+ */
423
+ export function patchViteConfigPort(content, port) {
424
+ // An existing numeric `server.port`: retarget it.
425
+ if (/server\s*:\s*\{[^}]*port\s*:\s*\d+/.test(content)) {
426
+ return content.replace(/(server\s*:\s*\{[^}]*port\s*:\s*)\d+/, `$1${port}`);
427
+ }
428
+ // A `server.port` set to something other than a literal (`env.PORT`, say).
429
+ // Rewriting it would either be a no-op or clobber the author's intent.
430
+ if (/server\s*:\s*\{[^}]*port\s*:/.test(content))
431
+ return null;
432
+ // A `server` block with no port: add one.
433
+ if (/server\s*:\s*\{/.test(content)) {
434
+ const match = /server\s*:\s*\{/.exec(content);
435
+ const indent = indentOfLineAt(content, match.index);
436
+ return content.replace(/(server\s*:\s*\{)/, `$1\n${indent} port: ${port},`);
437
+ }
438
+ // No `server` block at all: insert one at the head of the config object.
439
+ const objectStart = findConfigObjectStart(content);
440
+ if (objectStart === null)
441
+ return null;
442
+ const indent = indentOfLineAt(content, objectStart) + " ";
443
+ return (content.slice(0, objectStart + 1) +
444
+ `\n${indent}server: {\n${indent} port: ${port},\n${indent}},` +
445
+ content.slice(objectStart + 1));
446
+ }
447
+ /**
448
+ * Pins the dev server port in vite.config.{ts,js,mts,mjs} by injecting or
449
+ * updating the `server.port` field. Returns true only if a config file was
450
+ * found *and* actually rewritten.
451
+ */
452
+ export function updateViteConfig(targetDir, port) {
453
+ const candidates = [
454
+ "vite.config.ts",
455
+ "vite.config.js",
456
+ "vite.config.mts",
457
+ "vite.config.mjs",
458
+ ];
459
+ let configPath = null;
460
+ for (const name of candidates) {
461
+ const p = join(targetDir, name);
462
+ if (existsSync(p)) {
463
+ configPath = p;
464
+ break;
465
+ }
466
+ }
467
+ if (!configPath)
468
+ return false;
469
+ const content = readFileSync(configPath, "utf-8");
470
+ const patched = patchViteConfigPort(content, port);
471
+ if (patched === null)
472
+ return false;
473
+ writeFileSync(configPath, patched);
474
+ return true;
475
+ }
476
+ /**
477
+ * Updates port-sensitive env vars (VITE_OAUTH_REDIRECT_URI, VITE_BASE_URL)
478
+ * in the project's .env file to point at the given localhost port.
479
+ */
480
+ export function updateEnvPort(targetDir, port) {
481
+ const envPath = join(targetDir, ".env");
482
+ if (!existsSync(envPath))
483
+ return;
484
+ const origin = `http://localhost:${port}`;
485
+ let content = readFileSync(envPath, "utf-8");
486
+ if (content.includes("VITE_OAUTH_REDIRECT_URI=")) {
487
+ content = content.replace(/VITE_OAUTH_REDIRECT_URI=.*/, `VITE_OAUTH_REDIRECT_URI=${origin}/oauth/callback`);
488
+ }
489
+ else {
490
+ content =
491
+ content.trimEnd() +
492
+ `\nVITE_OAUTH_REDIRECT_URI=${origin}/oauth/callback\n`;
493
+ }
494
+ if (content.includes("VITE_BASE_URL=")) {
495
+ content = content.replace(/VITE_BASE_URL=.*/, `VITE_BASE_URL=${origin}`);
496
+ }
497
+ else {
498
+ content = content.trimEnd() + `\nVITE_BASE_URL=${origin}\n`;
499
+ }
500
+ writeFileSync(envPath, content.trimEnd() + "\n");
501
+ }
502
+ /**
503
+ * Starting from `startPort` (default 5173), finds the first free port and
504
+ * returns which ports were already occupied and which port vite will bind to.
505
+ * `exhausted` is true when all checked ports were occupied and the returned
506
+ * port is a best-guess beyond the checked range.
507
+ */
508
+ export async function findDevPort(startPort = 5173, maxChecks = 10) {
509
+ const takenPorts = [];
510
+ for (let port = startPort; port < startPort + maxChecks; port++) {
511
+ if (await isPortFree(port)) {
512
+ return { availablePort: port, takenPorts, exhausted: false };
513
+ }
514
+ takenPorts.push(port);
515
+ }
516
+ // All checked ports were occupied — best guess is the next one
517
+ return { availablePort: startPort + maxChecks, takenPorts, exhausted: true };
518
+ }
519
+ // ── iOS template helpers ──────────────────────────────────────────────
520
+ export { IOS_TEMPLATE_URL };
521
+ /**
522
+ * Updates primitive.json in the iOS template with app ID, server URL, and app name.
523
+ * Replaces __PRIMITIVE_*__ placeholder values.
524
+ * Returns true if the file was found and updated.
525
+ */
526
+ export function updatePrimitiveJson(targetDir, appId, serverUrl, appName) {
527
+ const jsonPath = join(targetDir, "primitive.json");
528
+ if (!existsSync(jsonPath))
529
+ return false;
530
+ let content = readFileSync(jsonPath, "utf-8");
531
+ content = content.replace(/__PRIMITIVE_APP_ID__/g, appId);
532
+ content = content.replace(/__PRIMITIVE_SERVER_URL__/g, serverUrl.replace(/\/+$/, ""));
533
+ if (appName) {
534
+ content = content.replace(/__PRIMITIVE_APP_NAME__/g, appName);
535
+ }
536
+ writeFileSync(jsonPath, content);
537
+ return true;
538
+ }
539
+ /**
540
+ * Gives an Apple scaffold a working `primitive.json`.
541
+ *
542
+ * In a current template that file is a BUILD PRODUCT generated from the
543
+ * Primitive environment in `.primitive/config.json` (#2873) — the one place
544
+ * the app ID and server URL are typed. `init` has just scaffolded that config,
545
+ * so running the template's own resolve script here means the scaffold has a
546
+ * `primitive.json` immediately rather than only after its first build, and
547
+ * there is exactly one implementation of the resolution.
548
+ *
549
+ * A template that predates the change has no such script and ships a tracked
550
+ * file with `__PRIMITIVE_*__` placeholders instead; filling those in keeps a
551
+ * new CLI working against an old template.
552
+ */
553
+ export function configurePrimitiveJson(targetDir, appId, serverUrl, appName, options = {}) {
554
+ const script = join(targetDir, "scripts", "resolve-primitive-config.sh");
555
+ if (existsSync(script)) {
556
+ try {
557
+ execFileSync("bash", [
558
+ "scripts/resolve-primitive-config.sh",
559
+ ...(options.environmentName
560
+ ? ["--primitive-env", options.environmentName]
561
+ : []),
562
+ ], {
563
+ cwd: targetDir,
564
+ stdio: "pipe",
565
+ });
566
+ return { outcome: "generated" };
567
+ }
568
+ catch (err) {
569
+ const detail = [err?.stderr?.toString(), err?.stdout?.toString(), err?.message]
570
+ .filter(Boolean)
571
+ .join("\n")
572
+ .trim();
573
+ return { outcome: "failed", detail };
574
+ }
575
+ }
576
+ return updatePrimitiveJson(targetDir, appId, serverUrl, appName)
577
+ ? { outcome: "filled" }
578
+ : { outcome: "missing" };
579
+ }
580
+ /**
581
+ * Checks if Xcode command-line tools are installed.
582
+ */
583
+ export async function isXcodeInstalled() {
584
+ const { execSync } = await import("child_process");
585
+ try {
586
+ execSync("xcodebuild -version", { stdio: "ignore" });
587
+ return true;
588
+ }
589
+ catch {
590
+ return false;
591
+ }
592
+ }
593
+ /**
594
+ * Runs `swift package resolve` in the target directory to download SPM dependencies.
595
+ */
596
+ export async function runSwiftPackageResolve(targetDir) {
597
+ const { spawn } = await import("child_process");
598
+ return new Promise((resolve, reject) => {
599
+ const proc = spawn("swift", ["package", "resolve"], {
600
+ cwd: targetDir,
601
+ stdio: "inherit",
602
+ });
603
+ proc.on("close", (code) => {
604
+ if (code === 0) {
605
+ resolve();
606
+ }
607
+ else {
608
+ reject(new Error(`swift package resolve exited with code ${code}`));
609
+ }
610
+ });
611
+ proc.on("error", reject);
612
+ });
613
+ }
614
+ /**
615
+ * Installs the primitive CLI (primitive-admin) globally, using whichever
616
+ * package manager already owns a global copy — pnpm by default.
202
617
  */
203
618
  export async function installPrimitiveCli() {
204
619
  const { spawn } = await import("child_process");
620
+ const { command, args } = installArgv(PRIMITIVE_CLI_PACKAGE);
205
621
  return new Promise((resolve, reject) => {
206
- const proc = spawn("npm", ["install", "-g", "primitive-admin"], {
622
+ const proc = spawn(command, args, {
207
623
  stdio: "inherit",
208
624
  shell: process.platform === "win32",
209
625
  });
@@ -212,7 +628,7 @@ export async function installPrimitiveCli() {
212
628
  resolve();
213
629
  }
214
630
  else {
215
- reject(new Error(`npm install -g primitive-admin exited with code ${code}`));
631
+ reject(new Error(`${[command, ...args].join(" ")} exited with code ${code}`));
216
632
  }
217
633
  });
218
634
  proc.on("error", reject);