primitive-admin 1.1.0-alpha.8 → 1.1.0-alpha.80

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 (522) hide show
  1. package/README.md +444 -106
  2. package/assets/skill/skills/primitive-platform/SKILL.md +811 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +373 -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 +128 -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 +700 -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 +54 -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 +196 -105
  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 +84 -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 +465 -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 +163 -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 +171 -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 +1859 -238
  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 +2062 -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 +385 -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/functions.d.ts +20 -0
  64. package/dist/src/commands/functions.js +672 -0
  65. package/dist/src/commands/functions.js.map +1 -0
  66. package/dist/src/commands/group-type-configs.d.ts +2 -0
  67. package/dist/src/commands/group-type-configs.js +86 -0
  68. package/dist/src/commands/group-type-configs.js.map +1 -0
  69. package/dist/src/commands/groups.d.ts +2 -0
  70. package/dist/src/commands/groups.js +39 -108
  71. package/dist/src/commands/groups.js.map +1 -1
  72. package/dist/src/commands/guides.d.ts +223 -0
  73. package/dist/src/commands/guides.js +617 -65
  74. package/dist/src/commands/guides.js.map +1 -1
  75. package/dist/src/commands/init.d.ts +37 -0
  76. package/dist/src/commands/init.js +1693 -208
  77. package/dist/src/commands/init.js.map +1 -1
  78. package/dist/src/commands/integrations.d.ts +2 -0
  79. package/dist/src/commands/integrations.js +402 -182
  80. package/dist/src/commands/integrations.js.map +1 -1
  81. package/dist/src/commands/llm.d.ts +2 -0
  82. package/dist/src/commands/llm.js +13 -8
  83. package/dist/src/commands/llm.js.map +1 -1
  84. package/dist/src/commands/locks.d.ts +8 -0
  85. package/dist/src/commands/locks.js +160 -0
  86. package/dist/src/commands/locks.js.map +1 -0
  87. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  88. package/dist/src/commands/metadata-category-configs.js +112 -0
  89. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  90. package/dist/src/commands/metadata.d.ts +2 -0
  91. package/dist/src/commands/metadata.js +281 -0
  92. package/dist/src/commands/metadata.js.map +1 -0
  93. package/dist/src/commands/prompts.d.ts +2 -0
  94. package/dist/src/commands/prompts.js +275 -621
  95. package/dist/src/commands/prompts.js.map +1 -1
  96. package/dist/src/commands/rule-sets.d.ts +3 -0
  97. package/dist/src/commands/rule-sets.js +137 -147
  98. package/dist/src/commands/rule-sets.js.map +1 -1
  99. package/dist/src/commands/scripts.d.ts +30 -0
  100. package/dist/src/commands/scripts.js +679 -0
  101. package/dist/src/commands/scripts.js.map +1 -0
  102. package/dist/src/commands/secrets.d.ts +2 -0
  103. package/dist/src/commands/secrets.js +108 -0
  104. package/dist/src/commands/secrets.js.map +1 -0
  105. package/dist/src/commands/sessions.d.ts +2 -0
  106. package/dist/src/commands/sessions.js +75 -0
  107. package/dist/src/commands/sessions.js.map +1 -0
  108. package/dist/src/commands/settings.d.ts +18 -0
  109. package/dist/src/commands/settings.js +54 -0
  110. package/dist/src/commands/settings.js.map +1 -0
  111. package/dist/src/commands/skill.d.ts +2 -0
  112. package/dist/src/commands/skill.js +29 -0
  113. package/dist/src/commands/skill.js.map +1 -0
  114. package/dist/src/commands/sync-app-settings.d.ts +158 -0
  115. package/dist/src/commands/sync-app-settings.js +328 -0
  116. package/dist/src/commands/sync-app-settings.js.map +1 -0
  117. package/dist/src/commands/sync.d.ts +2514 -0
  118. package/dist/src/commands/sync.js +16106 -848
  119. package/dist/src/commands/sync.js.map +1 -1
  120. package/dist/src/commands/tokens.d.ts +2 -0
  121. package/dist/src/commands/tokens.js +130 -21
  122. package/dist/src/commands/tokens.js.map +1 -1
  123. package/dist/src/commands/users.d.ts +2 -0
  124. package/dist/src/commands/users.js +532 -23
  125. package/dist/src/commands/users.js.map +1 -1
  126. package/dist/src/commands/vars.d.ts +8 -0
  127. package/dist/src/commands/vars.js +96 -0
  128. package/dist/src/commands/vars.js.map +1 -0
  129. package/dist/src/commands/waitlist.d.ts +2 -0
  130. package/dist/src/commands/waitlist.js +10 -10
  131. package/dist/src/commands/waitlist.js.map +1 -1
  132. package/dist/src/commands/webhooks.d.ts +2 -0
  133. package/dist/src/commands/webhooks.js +562 -0
  134. package/dist/src/commands/webhooks.js.map +1 -0
  135. package/dist/src/commands/workflows.d.ts +116 -0
  136. package/dist/src/commands/workflows.js +1638 -729
  137. package/dist/src/commands/workflows.js.map +1 -1
  138. package/dist/src/lib/access-rule-display.d.ts +21 -0
  139. package/dist/src/lib/access-rule-display.js +34 -0
  140. package/dist/src/lib/access-rule-display.js.map +1 -0
  141. package/dist/src/lib/api-client.d.ts +2147 -0
  142. package/dist/src/lib/api-client.js +2042 -160
  143. package/dist/src/lib/api-client.js.map +1 -1
  144. package/dist/src/lib/app-match-guard.d.ts +44 -0
  145. package/dist/src/lib/app-match-guard.js +72 -0
  146. package/dist/src/lib/app-match-guard.js.map +1 -0
  147. package/dist/src/lib/app-settings-descriptor.d.ts +263 -0
  148. package/dist/src/lib/app-settings-descriptor.js +584 -0
  149. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  150. package/dist/src/lib/auth-flow.d.ts +8 -0
  151. package/dist/src/lib/batch.d.ts +26 -0
  152. package/dist/src/lib/batch.js +32 -0
  153. package/dist/src/lib/batch.js.map +1 -0
  154. package/dist/src/lib/block-layout.d.ts +160 -0
  155. package/dist/src/lib/block-layout.js +451 -0
  156. package/dist/src/lib/block-layout.js.map +1 -0
  157. package/dist/src/lib/block-selector.d.ts +58 -0
  158. package/dist/src/lib/block-selector.js +92 -0
  159. package/dist/src/lib/block-selector.js.map +1 -0
  160. package/dist/src/lib/canonical-json.d.ts +12 -0
  161. package/dist/src/lib/canonical-json.js +35 -0
  162. package/dist/src/lib/canonical-json.js.map +1 -0
  163. package/dist/src/lib/channel.d.ts +30 -0
  164. package/dist/src/lib/channel.js +68 -0
  165. package/dist/src/lib/channel.js.map +1 -0
  166. package/dist/src/lib/cli-manifest.d.ts +68 -0
  167. package/dist/src/lib/cli-manifest.js +71 -0
  168. package/dist/src/lib/cli-manifest.js.map +1 -0
  169. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +101 -0
  170. package/dist/src/lib/codegen-shared/generatedFiles.js +191 -0
  171. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  172. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  173. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  174. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  175. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +38 -0
  176. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +46 -0
  177. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  178. package/dist/src/lib/config-json-field.d.ts +28 -0
  179. package/dist/src/lib/config-json-field.js +56 -0
  180. package/dist/src/lib/config-json-field.js.map +1 -0
  181. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  182. package/dist/src/lib/config-object-descriptor.js +696 -0
  183. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  184. package/dist/src/lib/config-payload.d.ts +85 -0
  185. package/dist/src/lib/config-payload.js +116 -0
  186. package/dist/src/lib/config-payload.js.map +1 -0
  187. package/dist/src/lib/config-surface.d.ts +140 -0
  188. package/dist/src/lib/config-surface.js +317 -0
  189. package/dist/src/lib/config-surface.js.map +1 -0
  190. package/dist/src/lib/config-toml.d.ts +10 -0
  191. package/dist/src/lib/config-toml.js +42 -0
  192. package/dist/src/lib/config-toml.js.map +1 -0
  193. package/dist/src/lib/config.d.ts +71 -0
  194. package/dist/src/lib/config.js +71 -68
  195. package/dist/src/lib/config.js.map +1 -1
  196. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  197. package/dist/src/lib/confirm-prompt.js +110 -0
  198. package/dist/src/lib/confirm-prompt.js.map +1 -0
  199. package/dist/src/lib/constants.d.ts +11 -0
  200. package/dist/src/lib/constants.js +12 -0
  201. package/dist/src/lib/constants.js.map +1 -0
  202. package/dist/src/lib/crash-handlers.d.ts +20 -0
  203. package/dist/src/lib/crash-handlers.js +49 -0
  204. package/dist/src/lib/crash-handlers.js.map +1 -0
  205. package/dist/src/lib/credentials-store.d.ts +104 -0
  206. package/dist/src/lib/credentials-store.js +336 -0
  207. package/dist/src/lib/credentials-store.js.map +1 -0
  208. package/dist/src/lib/csv.d.ts +47 -0
  209. package/dist/src/lib/csv.js +172 -0
  210. package/dist/src/lib/csv.js.map +1 -0
  211. package/dist/src/lib/data-input.d.ts +23 -0
  212. package/dist/src/lib/data-input.js +50 -0
  213. package/dist/src/lib/data-input.js.map +1 -0
  214. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  215. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  216. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  217. package/dist/src/lib/db-codegen/dbGenerator.d.ts +67 -0
  218. package/dist/src/lib/db-codegen/dbGenerator.js +170 -0
  219. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  220. package/dist/src/lib/db-codegen/dbNaming.d.ts +87 -0
  221. package/dist/src/lib/db-codegen/dbNaming.js +180 -0
  222. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  223. package/dist/src/lib/db-codegen/dbTemplates.d.ts +272 -0
  224. package/dist/src/lib/db-codegen/dbTemplates.js +480 -0
  225. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  226. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +73 -0
  227. package/dist/src/lib/db-codegen/dbTsTypes.js +139 -0
  228. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  229. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  230. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  231. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  232. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  233. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  234. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  235. package/dist/src/lib/document-export-permissions.d.ts +30 -0
  236. package/dist/src/lib/document-export-permissions.js +54 -0
  237. package/dist/src/lib/document-export-permissions.js.map +1 -0
  238. package/dist/src/lib/env-resolver-core.d.ts +253 -0
  239. package/dist/src/lib/env-resolver-core.js +459 -0
  240. package/dist/src/lib/env-resolver-core.js.map +1 -0
  241. package/dist/src/lib/env-resolver.d.ts +99 -0
  242. package/dist/src/lib/env-resolver.js +153 -0
  243. package/dist/src/lib/env-resolver.js.map +1 -0
  244. package/dist/src/lib/fetch.d.ts +5 -0
  245. package/dist/src/lib/function-bundle.d.ts +141 -0
  246. package/dist/src/lib/function-bundle.js +333 -0
  247. package/dist/src/lib/function-bundle.js.map +1 -0
  248. package/dist/src/lib/function-collect.d.ts +123 -0
  249. package/dist/src/lib/function-collect.js +594 -0
  250. package/dist/src/lib/function-collect.js.map +1 -0
  251. package/dist/src/lib/function-db-types.d.ts +187 -0
  252. package/dist/src/lib/function-db-types.js +782 -0
  253. package/dist/src/lib/function-db-types.js.map +1 -0
  254. package/dist/src/lib/function-document-types.d.ts +50 -0
  255. package/dist/src/lib/function-document-types.js +163 -0
  256. package/dist/src/lib/function-document-types.js.map +1 -0
  257. package/dist/src/lib/function-grants-preflight.d.ts +64 -0
  258. package/dist/src/lib/function-grants-preflight.js +100 -0
  259. package/dist/src/lib/function-grants-preflight.js.map +1 -0
  260. package/dist/src/lib/function-log-tail.d.ts +83 -0
  261. package/dist/src/lib/function-log-tail.js +115 -0
  262. package/dist/src/lib/function-log-tail.js.map +1 -0
  263. package/dist/src/lib/function-schema-codegen.d.ts +118 -0
  264. package/dist/src/lib/function-schema-codegen.js +402 -0
  265. package/dist/src/lib/function-schema-codegen.js.map +1 -0
  266. package/dist/src/lib/function-sync.d.ts +263 -0
  267. package/dist/src/lib/function-sync.js +604 -0
  268. package/dist/src/lib/function-sync.js.map +1 -0
  269. package/dist/src/lib/function-triggers.d.ts +66 -0
  270. package/dist/src/lib/function-triggers.js +285 -0
  271. package/dist/src/lib/function-triggers.js.map +1 -0
  272. package/dist/src/lib/function-typecheck.d.ts +86 -0
  273. package/dist/src/lib/function-typecheck.js +370 -0
  274. package/dist/src/lib/function-typecheck.js.map +1 -0
  275. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  276. package/dist/src/lib/generated-allowlist.js +281 -0
  277. package/dist/src/lib/generated-allowlist.js.map +1 -0
  278. package/dist/src/lib/generated-config-surfaces.d.ts +1445 -0
  279. package/dist/src/lib/generated-config-surfaces.js +5836 -0
  280. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  281. package/dist/src/lib/generated-sdk-types.d.ts +12 -0
  282. package/dist/src/lib/generated-sdk-types.js +13 -0
  283. package/dist/src/lib/generated-sdk-types.js.map +1 -0
  284. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  285. package/dist/src/lib/generated-template-lint.js +624 -0
  286. package/dist/src/lib/generated-template-lint.js.map +1 -0
  287. package/dist/src/lib/generated-workflow-model-fields.d.ts +20 -0
  288. package/dist/src/lib/generated-workflow-model-fields.js +53 -0
  289. package/dist/src/lib/generated-workflow-model-fields.js.map +1 -0
  290. package/dist/src/lib/google-client-secret-status.d.ts +35 -0
  291. package/dist/src/lib/google-client-secret-status.js +56 -0
  292. package/dist/src/lib/google-client-secret-status.js.map +1 -0
  293. package/dist/src/lib/init-adopt.d.ts +16 -0
  294. package/dist/src/lib/init-adopt.js +34 -0
  295. package/dist/src/lib/init-adopt.js.map +1 -0
  296. package/dist/src/lib/init-assets.d.ts +39 -0
  297. package/dist/src/lib/init-assets.js +97 -0
  298. package/dist/src/lib/init-assets.js.map +1 -0
  299. package/dist/src/lib/init-client-platforms.d.ts +14 -0
  300. package/dist/src/lib/init-client-platforms.js +71 -0
  301. package/dist/src/lib/init-client-platforms.js.map +1 -0
  302. package/dist/src/lib/init-config.d.ts +98 -0
  303. package/dist/src/lib/init-config.js +186 -0
  304. package/dist/src/lib/init-config.js.map +1 -0
  305. package/dist/src/lib/init-email-redirect-uris.d.ts +37 -0
  306. package/dist/src/lib/init-email-redirect-uris.js +46 -0
  307. package/dist/src/lib/init-email-redirect-uris.js.map +1 -0
  308. package/dist/src/lib/init-ios-links.d.ts +91 -0
  309. package/dist/src/lib/init-ios-links.js +219 -0
  310. package/dist/src/lib/init-ios-links.js.map +1 -0
  311. package/dist/src/lib/init-plan.d.ts +80 -0
  312. package/dist/src/lib/init-plan.js +95 -0
  313. package/dist/src/lib/init-plan.js.map +1 -0
  314. package/dist/src/lib/init-production-env.d.ts +48 -0
  315. package/dist/src/lib/init-production-env.js +59 -0
  316. package/dist/src/lib/init-production-env.js.map +1 -0
  317. package/dist/src/lib/init-schema.d.ts +74 -0
  318. package/dist/src/lib/init-schema.js +358 -0
  319. package/dist/src/lib/init-schema.js.map +1 -0
  320. package/dist/src/lib/init-xcode.d.ts +34 -0
  321. package/dist/src/lib/init-xcode.js +138 -0
  322. package/dist/src/lib/init-xcode.js.map +1 -0
  323. package/dist/src/lib/integration-request-config.d.ts +30 -0
  324. package/dist/src/lib/integration-request-config.js +145 -0
  325. package/dist/src/lib/integration-request-config.js.map +1 -0
  326. package/dist/src/lib/integration-selector.d.ts +42 -0
  327. package/dist/src/lib/integration-selector.js +46 -0
  328. package/dist/src/lib/integration-selector.js.map +1 -0
  329. package/dist/src/lib/ios-app-id.d.ts +34 -0
  330. package/dist/src/lib/ios-app-id.js +69 -0
  331. package/dist/src/lib/ios-app-id.js.map +1 -0
  332. package/dist/src/lib/local-state.d.ts +55 -0
  333. package/dist/src/lib/local-state.js +167 -0
  334. package/dist/src/lib/local-state.js.map +1 -0
  335. package/dist/src/lib/local-test-cases.d.ts +63 -0
  336. package/dist/src/lib/local-test-cases.js +136 -0
  337. package/dist/src/lib/local-test-cases.js.map +1 -0
  338. package/dist/src/lib/log-inspection.d.ts +680 -0
  339. package/dist/src/lib/log-inspection.js +784 -0
  340. package/dist/src/lib/log-inspection.js.map +1 -0
  341. package/dist/src/lib/migration-nag.d.ts +49 -0
  342. package/dist/src/lib/migration-nag.js +164 -0
  343. package/dist/src/lib/migration-nag.js.map +1 -0
  344. package/dist/src/lib/object-status-filter.d.ts +22 -0
  345. package/dist/src/lib/object-status-filter.js +45 -0
  346. package/dist/src/lib/object-status-filter.js.map +1 -0
  347. package/dist/src/lib/output.d.ts +109 -0
  348. package/dist/src/lib/output.js +191 -8
  349. package/dist/src/lib/output.js.map +1 -1
  350. package/dist/src/lib/package-manager.d.ts +140 -0
  351. package/dist/src/lib/package-manager.js +305 -0
  352. package/dist/src/lib/package-manager.js.map +1 -0
  353. package/dist/src/lib/paginate.d.ts +83 -0
  354. package/dist/src/lib/paginate.js +95 -0
  355. package/dist/src/lib/paginate.js.map +1 -0
  356. package/dist/src/lib/platform-owned.d.ts +63 -0
  357. package/dist/src/lib/platform-owned.js +85 -0
  358. package/dist/src/lib/platform-owned.js.map +1 -0
  359. package/dist/src/lib/project-config.d.ts +122 -0
  360. package/dist/src/lib/project-config.js +244 -0
  361. package/dist/src/lib/project-config.js.map +1 -0
  362. package/dist/src/lib/query-operators.d.ts +43 -0
  363. package/dist/src/lib/query-operators.js +80 -0
  364. package/dist/src/lib/query-operators.js.map +1 -0
  365. package/dist/src/lib/record-filter.d.ts +18 -0
  366. package/dist/src/lib/record-filter.js +55 -0
  367. package/dist/src/lib/record-filter.js.map +1 -0
  368. package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
  369. package/dist/src/lib/refresh-admin-credentials.js +103 -0
  370. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  371. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  372. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  373. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  374. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  375. package/dist/src/lib/resolve-init-server.js +77 -0
  376. package/dist/src/lib/resolve-init-server.js.map +1 -0
  377. package/dist/src/lib/resolve-platform.d.ts +74 -0
  378. package/dist/src/lib/resolve-platform.js +105 -0
  379. package/dist/src/lib/resolve-platform.js.map +1 -0
  380. package/dist/src/lib/run-status.d.ts +19 -0
  381. package/dist/src/lib/run-status.generated.d.ts +39 -0
  382. package/dist/src/lib/run-status.generated.js +66 -0
  383. package/dist/src/lib/run-status.generated.js.map +1 -0
  384. package/dist/src/lib/run-status.js +19 -0
  385. package/dist/src/lib/run-status.js.map +1 -0
  386. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  387. package/dist/src/lib/server-text-normalization.js +90 -0
  388. package/dist/src/lib/server-text-normalization.js.map +1 -0
  389. package/dist/src/lib/server-url.d.ts +22 -0
  390. package/dist/src/lib/server-url.js +33 -0
  391. package/dist/src/lib/server-url.js.map +1 -0
  392. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  393. package/dist/src/lib/signing-secret-status.js +116 -0
  394. package/dist/src/lib/signing-secret-status.js.map +1 -0
  395. package/dist/src/lib/skill-installer.d.ts +25 -0
  396. package/dist/src/lib/skill-installer.js +266 -0
  397. package/dist/src/lib/skill-installer.js.map +1 -0
  398. package/dist/src/lib/snapshots.d.ts +98 -0
  399. package/dist/src/lib/snapshots.js +294 -0
  400. package/dist/src/lib/snapshots.js.map +1 -0
  401. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +113 -0
  402. package/dist/src/lib/swift-codegen/dbGenerator.js +914 -0
  403. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  404. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  405. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  406. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  407. package/dist/src/lib/swift-codegen/generator.d.ts +94 -0
  408. package/dist/src/lib/swift-codegen/generator.js +440 -0
  409. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  410. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  411. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  412. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  413. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +94 -0
  414. package/dist/src/lib/swift-codegen/siblingSymbols.js +155 -0
  415. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  416. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  417. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  418. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  419. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  420. package/dist/src/lib/sync-dir-selector.js +30 -0
  421. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  422. package/dist/src/lib/sync-paths.d.ts +123 -0
  423. package/dist/src/lib/sync-paths.js +193 -0
  424. package/dist/src/lib/sync-paths.js.map +1 -0
  425. package/dist/src/lib/sync-resource-types.d.ts +563 -0
  426. package/dist/src/lib/sync-resource-types.js +1073 -0
  427. package/dist/src/lib/sync-resource-types.js.map +1 -0
  428. package/dist/src/lib/sync-selectors.d.ts +95 -0
  429. package/dist/src/lib/sync-selectors.js +228 -0
  430. package/dist/src/lib/sync-selectors.js.map +1 -0
  431. package/dist/src/lib/template.d.ts +170 -0
  432. package/dist/src/lib/template.js +484 -68
  433. package/dist/src/lib/template.js.map +1 -1
  434. package/dist/src/lib/test-case-file-names.d.ts +40 -0
  435. package/dist/src/lib/test-case-file-names.js +91 -0
  436. package/dist/src/lib/test-case-file-names.js.map +1 -0
  437. package/dist/src/lib/test-case-keys.d.ts +29 -0
  438. package/dist/src/lib/test-case-keys.js +55 -0
  439. package/dist/src/lib/test-case-keys.js.map +1 -0
  440. package/dist/src/lib/test-case-variables.d.ts +29 -0
  441. package/dist/src/lib/test-case-variables.js +71 -0
  442. package/dist/src/lib/test-case-variables.js.map +1 -0
  443. package/dist/src/lib/token-inject.d.ts +56 -0
  444. package/dist/src/lib/token-inject.js +204 -0
  445. package/dist/src/lib/token-inject.js.map +1 -0
  446. package/dist/src/lib/toml-database-config.d.ts +123 -0
  447. package/dist/src/lib/toml-database-config.js +544 -0
  448. package/dist/src/lib/toml-database-config.js.map +1 -0
  449. package/dist/src/lib/toml-metadata-config.d.ts +151 -0
  450. package/dist/src/lib/toml-metadata-config.js +476 -0
  451. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  452. package/dist/src/lib/toml-native-form.d.ts +46 -0
  453. package/dist/src/lib/toml-native-form.js +78 -0
  454. package/dist/src/lib/toml-native-form.js.map +1 -0
  455. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  456. package/dist/src/lib/toml-params-validator.js +298 -0
  457. package/dist/src/lib/toml-params-validator.js.map +1 -0
  458. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  459. package/dist/src/lib/toml-scalar-edit.js +283 -0
  460. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  461. package/dist/src/lib/user-selector.d.ts +24 -0
  462. package/dist/src/lib/user-selector.js +33 -0
  463. package/dist/src/lib/user-selector.js.map +1 -0
  464. package/dist/src/lib/version-check.d.ts +35 -0
  465. package/dist/src/lib/version-check.js +241 -0
  466. package/dist/src/lib/version-check.js.map +1 -0
  467. package/dist/src/lib/watch.d.ts +121 -0
  468. package/dist/src/lib/watch.js +169 -0
  469. package/dist/src/lib/watch.js.map +1 -0
  470. package/dist/src/lib/web-url.d.ts +40 -0
  471. package/dist/src/lib/web-url.js +76 -0
  472. package/dist/src/lib/web-url.js.map +1 -0
  473. package/dist/src/lib/workflow-apply.d.ts +110 -0
  474. package/dist/src/lib/workflow-apply.js +164 -0
  475. package/dist/src/lib/workflow-apply.js.map +1 -0
  476. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
  477. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
  478. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  479. package/dist/src/lib/workflow-codegen/generator.d.ts +96 -0
  480. package/dist/src/lib/workflow-codegen/generator.js +361 -0
  481. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  482. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +94 -0
  483. package/dist/src/lib/workflow-codegen/invokerIR.js +76 -0
  484. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  485. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  486. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  487. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  488. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +80 -0
  489. package/dist/src/lib/workflow-codegen/schemaToTs.js +303 -0
  490. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  491. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  492. package/dist/src/lib/workflow-config-apply.js +137 -0
  493. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  494. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  495. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  496. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  497. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  498. package/dist/src/lib/workflow-defaults.js +41 -0
  499. package/dist/src/lib/workflow-defaults.js.map +1 -0
  500. package/dist/src/lib/workflow-field-descriptor.d.ts +91 -0
  501. package/dist/src/lib/workflow-field-descriptor.js +153 -0
  502. package/dist/src/lib/workflow-field-descriptor.js.map +1 -0
  503. package/dist/src/lib/workflow-fragments.d.ts +64 -0
  504. package/dist/src/lib/workflow-fragments.js +342 -0
  505. package/dist/src/lib/workflow-fragments.js.map +1 -0
  506. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  507. package/dist/src/lib/workflow-include-preserve.js +286 -0
  508. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  509. package/dist/src/lib/workflow-payload.d.ts +98 -0
  510. package/dist/src/lib/workflow-payload.js +178 -0
  511. package/dist/src/lib/workflow-payload.js.map +1 -0
  512. package/dist/src/lib/workflow-toml-validator.d.ts +207 -0
  513. package/dist/src/lib/workflow-toml-validator.js +762 -0
  514. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  515. package/dist/src/lib/workflow-usage.d.ts +198 -0
  516. package/dist/src/lib/workflow-usage.js +312 -0
  517. package/dist/src/lib/workflow-usage.js.map +1 -0
  518. package/dist/src/types/index.d.ts +591 -0
  519. package/dist/src/validators.d.ts +65 -0
  520. package/dist/src/validators.js +64 -0
  521. package/dist/src/validators.js.map +1 -0
  522. package/package.json +34 -9
@@ -1,57 +1,221 @@
1
1
  import { ApiClient } from "../lib/api-client.js";
2
2
  import { resolveAppId } from "../lib/config.js";
3
- import { error, info, keyValue, formatTable, formatId, formatDate, formatNumber, formatPercent, formatDuration, json, divider, heading, } from "../lib/output.js";
3
+ import { error, info, formatTable, formatId, formatDate, formatNumber, formatPercent, formatDuration, json, heading, result as printResult, dim, } from "../lib/output.js";
4
+ import { buildActivityEnvelope } from "../lib/log-inspection.js";
5
+ import { ALL_APPS_CONFLICT_ERROR, ALL_APPS_SUPER_ADMIN_ERROR, isAbortStatus, isSuperAdminRole, mergeUsageReports, parseWindowDaysFlag, renderMergedUsageReport, renderUsageReport, usageExitCode, USAGE_CLI_DEFAULT_WINDOW_DAYS, USAGE_CLI_MAX_WINDOW_DAYS, USAGE_CLI_MIN_WINDOW_DAYS, } from "../lib/workflow-usage.js";
6
+ /** Format a value that is already a percentage (e.g. 33.3 → "33.3%") */
7
+ function formatPctRaw(value) {
8
+ if (value === undefined || value === null)
9
+ return "-";
10
+ return `${value.toFixed(1)}%`;
11
+ }
4
12
  export function registerAnalyticsCommands(program) {
5
13
  const analytics = program
6
14
  .command("analytics")
7
15
  .description("View usage analytics, user activity, and integration metrics")
16
+ // Subcommands are listed once, by commander, from what is registered
17
+ // below — a second hand-written list drifts (#2860: `errors-groups`
18
+ // shipped and never reached the copy). Examples illustrate; they do not
19
+ // re-list the group.
8
20
  .addHelpText("after", `
9
21
  Examples:
10
22
  $ primitive analytics overview
11
- $ primitive analytics top-users --window-days 7 --limit 20
12
- $ primitive analytics integrations
23
+ $ primitive analytics daily-active --window-days 14
24
+ $ primitive analytics top-users --limit 20
25
+ $ primitive analytics user-search --query user@example.com
26
+ $ primitive analytics user-detail <user-ulid>
27
+ $ primitive analytics events --window-days 7 --page 0
28
+ $ primitive analytics events-grouped --group-by feature
29
+ $ primitive analytics errors-groups --window-days 14 --limit 100
30
+ $ primitive analytics cohort-retention
31
+ $ primitive analytics workflows --limit 5
32
+ $ primitive analytics prompts --window-days 14
33
+ $ primitive analytics workflow-usage --window-days 30 --all-apps --json
13
34
  `);
14
- // Overview
35
+ // ── Overview (DAU / WAU / MAU / Growth) ──────────────────────────
15
36
  analytics
16
37
  .command("overview")
17
- .description("Get analytics overview for an app")
38
+ .description("Show DAU, WAU, MAU, and growth accounting")
18
39
  .argument("[app-id]", "App ID (uses current app if not specified)")
19
40
  .option("--app <app-id>", "App ID")
20
- .option("--window-days <n>", "Time window in days", "30")
41
+ .option("--window-days <n>", "Growth window in days", "28")
42
+ .option("--json", "Output as JSON")
43
+ .action(async (appId, options) => {
44
+ const resolvedAppId = resolveAppId(appId, options);
45
+ const client = new ApiClient();
46
+ try {
47
+ const [dau, wau, mau, growth] = await Promise.all([
48
+ client.getAnalyticsOverviewDau(resolvedAppId),
49
+ client.getAnalyticsOverviewWau(resolvedAppId),
50
+ client.getAnalyticsOverviewMau(resolvedAppId),
51
+ client.getAnalyticsOverviewGrowth(resolvedAppId, {
52
+ windowDays: parseInt(options.windowDays),
53
+ }),
54
+ ]);
55
+ if (options.json) {
56
+ json({ dau, wau, mau, growth });
57
+ return;
58
+ }
59
+ heading("Active Users");
60
+ console.log();
61
+ const formatDelta = (d) => d > 0 ? `+${(d * 100).toFixed(1)}%` : d === 0 ? "0%" : `${(d * 100).toFixed(1)}%`;
62
+ console.log(formatTable([
63
+ { metric: "DAU", value: dau.value, previous: dau.previous, delta: formatDelta(dau.deltaPct) },
64
+ { metric: "WAU", value: wau.value, previous: wau.previous, delta: formatDelta(wau.deltaPct) },
65
+ { metric: "MAU", value: mau.value, previous: mau.previous, delta: formatDelta(mau.deltaPct) },
66
+ ], [
67
+ { header: "METRIC", key: "metric" },
68
+ { header: "CURRENT", key: "value", align: "right", format: formatNumber },
69
+ { header: "PREVIOUS", key: "previous", align: "right", format: formatNumber },
70
+ { header: "CHANGE", key: "delta", align: "right" },
71
+ ]));
72
+ console.log();
73
+ heading(`Growth Accounting (${growth.window_days} days)`);
74
+ console.log();
75
+ printResult("Current active", String(growth.current_active));
76
+ printResult("Previous active", String(growth.previous_active));
77
+ printResult("New users", String(growth.new_users));
78
+ printResult("Retained", String(growth.retained_users));
79
+ printResult("Reactivated", String(growth.reactivated_users));
80
+ printResult("Churned", String(growth.churned_users));
81
+ printResult("Delta", formatDelta(growth.deltaPct));
82
+ }
83
+ catch (err) {
84
+ error(err.message);
85
+ process.exit(1);
86
+ }
87
+ });
88
+ // ── Daily Active ─────────────────────────────────────────────────
89
+ analytics
90
+ .command("daily-active")
91
+ .description("Daily active users time series")
92
+ .argument("[app-id]", "App ID (uses current app if not specified)")
93
+ .option("--app <app-id>", "App ID")
94
+ .option("--window-days <n>", "Time window in days (7-90)", "28")
21
95
  .option("--json", "Output as JSON")
22
96
  .action(async (appId, options) => {
23
97
  const resolvedAppId = resolveAppId(appId, options);
24
98
  const client = new ApiClient();
25
99
  try {
26
- const result = await client.getAnalyticsOverview(resolvedAppId, {
100
+ const result = await client.getAnalyticsDailyActive(resolvedAppId, {
27
101
  windowDays: parseInt(options.windowDays),
28
102
  });
29
103
  if (options.json) {
30
104
  json(result);
31
105
  return;
32
106
  }
33
- heading(`Analytics Overview (${result.windowDays} days)`);
107
+ heading(`Daily Active Users (${result.window_days} days)`);
34
108
  console.log();
35
- keyValue("Daily Active Users (DAU)", formatNumber(result.totals.dau));
36
- keyValue("Weekly Active Users (WAU)", formatNumber(result.totals.wau));
37
- keyValue("Monthly Active Users (MAU)", formatNumber(result.totals.mau));
38
- keyValue("Total Events", formatNumber(result.totals.totalEvents));
39
- if (result.series && result.series.length > 0) {
40
- divider();
41
- info("Activity Series:");
42
- console.log(formatTable(result.series.slice(-10), [
43
- { header: "DATE", key: "bucketStart", format: (v) => v.slice(0, 10) },
44
- { header: "USERS", key: "activeUsers", align: "right" },
45
- { header: "EVENTS", key: "totalEvents", align: "right" },
46
- ]));
109
+ if (!result.rows || result.rows.length === 0) {
110
+ info("No data found.");
111
+ return;
112
+ }
113
+ console.log(formatTable(result.rows, [
114
+ { header: "DATE", key: "day_label" },
115
+ { header: "ACTIVE USERS", key: "active_users", align: "right", format: formatNumber },
116
+ ]));
117
+ }
118
+ catch (err) {
119
+ error(err.message);
120
+ process.exit(1);
121
+ }
122
+ });
123
+ // ── Rolling Active ───────────────────────────────────────────────
124
+ analytics
125
+ .command("rolling-active")
126
+ .description("Rolling active users (28 data points)")
127
+ .argument("[app-id]", "App ID (uses current app if not specified)")
128
+ .option("--app <app-id>", "App ID")
129
+ .option("--window-days <n>", "Rolling window size in days (1-28)", "7")
130
+ .option("--json", "Output as JSON")
131
+ .action(async (appId, options) => {
132
+ const resolvedAppId = resolveAppId(appId, options);
133
+ const client = new ApiClient();
134
+ try {
135
+ const result = await client.getAnalyticsRollingActive(resolvedAppId, {
136
+ windowDays: parseInt(options.windowDays),
137
+ });
138
+ if (options.json) {
139
+ json(result);
140
+ return;
47
141
  }
142
+ heading(`Rolling Active Users (${result.window_days}-day window)`);
143
+ console.log();
144
+ if (!result.rows || result.rows.length === 0) {
145
+ info("No data found.");
146
+ return;
147
+ }
148
+ console.log(formatTable(result.rows, [
149
+ { header: "DATE", key: "day_label" },
150
+ { header: "ACTIVE USERS", key: "active_users", align: "right", format: formatNumber },
151
+ ]));
48
152
  }
49
153
  catch (err) {
50
154
  error(err.message);
51
155
  process.exit(1);
52
156
  }
53
157
  });
54
- // Top users
158
+ // ── Cohort Retention ─────────────────────────────────────────────
159
+ analytics
160
+ .command("cohort-retention")
161
+ .description("Weekly cohort retention matrix")
162
+ .argument("[app-id]", "App ID (uses current app if not specified)")
163
+ .option("--app <app-id>", "App ID")
164
+ .option("--json", "Output as JSON")
165
+ .action(async (appId, options) => {
166
+ const resolvedAppId = resolveAppId(appId, options);
167
+ const client = new ApiClient();
168
+ try {
169
+ const result = await client.getAnalyticsCohortRetention(resolvedAppId);
170
+ if (options.json) {
171
+ json(result);
172
+ return;
173
+ }
174
+ heading("Cohort Retention");
175
+ console.log();
176
+ if (!result.rows || result.rows.length === 0) {
177
+ info("No cohort data found.");
178
+ return;
179
+ }
180
+ // Build week headers
181
+ const weekHeaders = result.weeks.map((w) => `W${w}`);
182
+ // Build table rows with retention percentages
183
+ const tableRows = result.rows.map((row) => {
184
+ const entry = {
185
+ cohort: row.signup_week_label,
186
+ size: row.cohort_size,
187
+ };
188
+ row.retention.forEach((r, i) => {
189
+ entry[`w${result.weeks[i]}`] =
190
+ r !== null ? `${r.toFixed(0)}%` : "-";
191
+ });
192
+ return entry;
193
+ });
194
+ const columns = [
195
+ { header: "COHORT", key: "cohort" },
196
+ { header: "SIZE", key: "size", align: "right", format: formatNumber },
197
+ ...weekHeaders.map((h, i) => ({
198
+ header: h,
199
+ key: `w${result.weeks[i]}`,
200
+ align: "right",
201
+ })),
202
+ ];
203
+ console.log(formatTable(tableRows, columns));
204
+ // Print averages row
205
+ if (result.averages) {
206
+ const avgStr = result.averages
207
+ .map((a) => a !== null ? `${a.toFixed(0)}%` : "-")
208
+ .join(" ");
209
+ console.log();
210
+ dim(`Averages: ${avgStr}`);
211
+ }
212
+ }
213
+ catch (err) {
214
+ error(err.message);
215
+ process.exit(1);
216
+ }
217
+ });
218
+ // ── Top Users ────────────────────────────────────────────────────
55
219
  analytics
56
220
  .command("top-users")
57
221
  .description("Get top users by activity")
@@ -80,6 +244,7 @@ Examples:
80
244
  }
81
245
  console.log(formatTable(result.results, [
82
246
  { header: "USER", key: "userUlid", format: formatId },
247
+ { header: "EMAIL", key: "email" },
83
248
  { header: "EVENTS", key: "eventCount", align: "right" },
84
249
  { header: "FIRST SEEN", key: "firstSeen", format: formatDate },
85
250
  { header: "LAST SEEN", key: "lastSeen", format: formatDate },
@@ -90,53 +255,134 @@ Examples:
90
255
  process.exit(1);
91
256
  }
92
257
  });
93
- // User details
258
+ // ── User Search ──────────────────────────────────────────────────
94
259
  analytics
95
- .command("user")
96
- .description("Get analytics for a specific user")
260
+ .command("user-search")
261
+ .description("Search users by email or ULID, or list who signed up on a given day")
97
262
  .argument("[app-id]", "App ID (uses current app if not specified)")
98
- .argument("<user-ulid>", "User ULID")
99
263
  .option("--app <app-id>", "App ID")
100
- .option("--window-days <n>", "Time window in days", "30")
264
+ // #3127 — no longer required: "who signed up on day D" names no user, so a
265
+ // signup filter is the second way to say what is being asked for.
266
+ .option("--query <q>", "Email or ULID to search for")
267
+ .option("--signup-day <day>", "Users who joined on this UTC day (YYYY-MM-DD)")
268
+ .option("--signup-start-day <day>", "Start of an inclusive signup range (YYYY-MM-DD, at most 90 days)")
269
+ .option("--signup-end-day <day>", "End of an inclusive signup range (YYYY-MM-DD)")
270
+ .option("--offset <n>", "Row offset; page a busy day until the result is not truncated")
271
+ .option("--limit <n>", "Max results", "25")
101
272
  .option("--json", "Output as JSON")
102
- .action(async (appIdOrUserUlid, userUlidOrUndefined, options) => {
103
- let resolvedAppId;
104
- let userUlid;
105
- if (userUlidOrUndefined) {
106
- resolvedAppId = resolveAppId(appIdOrUserUlid, options);
107
- userUlid = userUlidOrUndefined;
273
+ .action(async (appId, options) => {
274
+ const resolvedAppId = resolveAppId(appId, options);
275
+ const client = new ApiClient();
276
+ const hasSignupFilter = Boolean(options.signupDay || options.signupStartDay || options.signupEndDay);
277
+ if (!options.query && !hasSignupFilter) {
278
+ error("Give --query, or a signup filter (--signup-day, or " +
279
+ "--signup-start-day with --signup-end-day).");
280
+ process.exit(1);
281
+ return;
282
+ }
283
+ try {
284
+ const limit = parseInt(options.limit);
285
+ const result = await client.getAnalyticsUserSearch(resolvedAppId, {
286
+ ...(options.query ? { q: options.query } : {}),
287
+ limit,
288
+ ...(options.signupDay ? { signupDay: options.signupDay } : {}),
289
+ ...(options.signupStartDay
290
+ ? { signupStartDay: options.signupStartDay }
291
+ : {}),
292
+ ...(options.signupEndDay ? { signupEndDay: options.signupEndDay } : {}),
293
+ ...(options.offset !== undefined
294
+ ? { offset: parseInt(options.offset) }
295
+ : {}),
296
+ });
297
+ if (options.json) {
298
+ json(result);
299
+ return;
300
+ }
301
+ heading(hasSignupFilter
302
+ ? `Signups: ${result.signupStartDay ?? ""} to ${result.signupEndDay ?? ""}`
303
+ : `User Search: "${result.query}"`);
304
+ console.log();
305
+ if (!result.results || result.results.length === 0) {
306
+ info("No users found.");
307
+ return;
308
+ }
309
+ console.log(formatTable(result.results, [
310
+ { header: "USER", key: "userUlid", format: formatId },
311
+ { header: "EMAIL", key: "email" },
312
+ { header: "NAME", key: "name" },
313
+ { header: "SIGNED UP", key: "signedUpAt", format: formatDate },
314
+ { header: "EVENTS", key: "eventCount", align: "right" },
315
+ { header: "LAST SEEN", key: "lastSeen", format: formatDate },
316
+ ]));
317
+ // #3127 — a busy day has more matches than one page. Say so, and say
318
+ // exactly what to run next: silence here is how a digest undercounts.
319
+ //
320
+ // The step is the limit the SERVER used, not the one asked for: it
321
+ // clamps to 100, so advancing by a larger `--limit` would step straight
322
+ // over the users this page could not hold (CR3127-002).
323
+ if (result.truncated) {
324
+ const pageSize = typeof result.limit === "number" && result.limit > 0
325
+ ? result.limit
326
+ : limit;
327
+ const nextOffset = (result.offset ?? 0) + pageSize;
328
+ console.log();
329
+ // stdout, with the table it continues — a hint printed to stderr is
330
+ // the one a piped digest never sees.
331
+ console.log(`more results: rerun with --offset ${nextOffset}`);
332
+ }
108
333
  }
109
- else {
110
- resolvedAppId = resolveAppId(undefined, options);
111
- userUlid = appIdOrUserUlid;
334
+ catch (err) {
335
+ error(err.message);
336
+ process.exit(1);
112
337
  }
338
+ });
339
+ // ── User Detail ──────────────────────────────────────────────────
340
+ analytics
341
+ .command("user-detail")
342
+ .description("Detailed activity for a single user")
343
+ .argument("<user-ulid>", "User ULID")
344
+ .argument("[app-id]", "App ID (uses current app if not specified)")
345
+ .option("--app <app-id>", "App ID")
346
+ .option("--json", "Output as JSON")
347
+ .action(async (userUlid, appId, options) => {
348
+ const resolvedAppId = resolveAppId(appId, options);
113
349
  const client = new ApiClient();
114
350
  try {
115
- const result = await client.getAnalyticsUserTimeline(resolvedAppId, userUlid, {
116
- windowDays: parseInt(options.windowDays),
117
- });
351
+ const result = await client.getAnalyticsUserDetail(resolvedAppId, userUlid);
118
352
  if (options.json) {
119
353
  json(result);
120
354
  return;
121
355
  }
122
- heading(`User Activity (${result.windowDays} days)`);
123
- keyValue("User", userUlid);
356
+ heading("User Detail");
124
357
  console.log();
125
- if (result.breakdown && result.breakdown.length > 0) {
126
- info("Activity Breakdown:");
127
- console.log(formatTable(result.breakdown.slice(0, 15), [
358
+ printResult("ULID", result.user.user_ulid);
359
+ if (result.user.email)
360
+ printResult("Email", result.user.email);
361
+ if (result.user.name)
362
+ printResult("Name", result.user.name);
363
+ console.log();
364
+ printResult("First seen", result.stats.first_seen ? formatDate(result.stats.first_seen) : "-");
365
+ printResult("Last active", result.stats.last_active ? formatDate(result.stats.last_active) : "-");
366
+ printResult("Total events", String(result.stats.total_events));
367
+ printResult("Days active", String(result.stats.days_active));
368
+ if (result.events_by_action?.length > 0) {
369
+ console.log();
370
+ heading("Events by Action");
371
+ console.log();
372
+ console.log(formatTable(result.events_by_action, [
128
373
  { header: "ACTION", key: "action" },
129
- { header: "FEATURE", key: "feature" },
130
- { header: "ROUTE", key: "route" },
131
- { header: "EVENTS", key: "events", align: "right" },
374
+ { header: "COUNT", key: "event_count", align: "right", format: formatNumber },
375
+ { header: "LAST OCCURRED", key: "last_occurred", format: formatDate },
132
376
  ]));
133
377
  }
134
- if (result.timeline && result.timeline.length > 0) {
135
- divider();
136
- info("Recent Timeline:");
137
- console.log(formatTable(result.timeline.slice(-10), [
138
- { header: "TIME", key: "bucketStart", format: formatDate },
139
- { header: "EVENTS", key: "events", align: "right" },
378
+ if (result.events_by_feature?.length > 0) {
379
+ console.log();
380
+ heading("Events by Feature");
381
+ console.log();
382
+ console.log(formatTable(result.events_by_feature, [
383
+ { header: "FEATURE", key: "feature" },
384
+ { header: "COUNT", key: "event_count", align: "right", format: formatNumber },
385
+ { header: "PCT", key: "pct", align: "right", format: formatPctRaw },
140
386
  ]));
141
387
  }
142
388
  }
@@ -145,7 +391,220 @@ Examples:
145
391
  process.exit(1);
146
392
  }
147
393
  });
148
- // Integration metrics
394
+ // ── User Snapshot ────────────────────────────────────────────────
395
+ analytics
396
+ .command("user-snapshot")
397
+ .description("Latest context snapshot for a user")
398
+ .argument("<user-ulid>", "User ULID")
399
+ .argument("[app-id]", "App ID (uses current app if not specified)")
400
+ .option("--app <app-id>", "App ID")
401
+ .option("--json", "Output as JSON")
402
+ .action(async (userUlid, appId, options) => {
403
+ const resolvedAppId = resolveAppId(appId, options);
404
+ const client = new ApiClient();
405
+ try {
406
+ const result = await client.getAnalyticsUserSnapshot(resolvedAppId, userUlid);
407
+ if (options.json) {
408
+ json(result);
409
+ return;
410
+ }
411
+ heading("User Snapshot");
412
+ console.log();
413
+ if (!result.snapshot) {
414
+ info("No snapshot found for this user.");
415
+ return;
416
+ }
417
+ printResult("Timestamp", formatDate(result.snapshot.timestamp));
418
+ console.log();
419
+ console.log(JSON.stringify(result.snapshot.values, null, 2));
420
+ }
421
+ catch (err) {
422
+ error(err.message);
423
+ process.exit(1);
424
+ }
425
+ });
426
+ // ── Events Feed ──────────────────────────────────────────────────
427
+ analytics
428
+ .command("events")
429
+ .description("Paginated event feed")
430
+ .argument("[app-id]", "App ID (uses current app if not specified)")
431
+ .option("--app <app-id>", "App ID")
432
+ .option("--window-days <n>", "Time window in days", "7")
433
+ .option("--page <n>", "Page number (0-based)", "0")
434
+ .option("--user-id <id>", "Filter to a single user's events")
435
+ .option("--json", "Output as JSON")
436
+ .action(async (appId, options) => {
437
+ const resolvedAppId = resolveAppId(appId, options);
438
+ const client = new ApiClient();
439
+ try {
440
+ const result = await client.getAnalyticsEvents(resolvedAppId, {
441
+ windowDays: parseInt(options.windowDays),
442
+ page: parseInt(options.page),
443
+ // The events feed filters by user via the bracketed
444
+ // `filter[user][is]` syntax the analytics route already parses — not
445
+ // a raw query param (behavior 11).
446
+ ...(options.userId ? { "filter[user][is]": options.userId } : {}),
447
+ });
448
+ if (options.json) {
449
+ // Normalize the offset-paged response to the shared activity
450
+ // envelope: `{page_size, rows}` → `{pageSize, items}` with the
451
+ // activity allowlist dropping infra fields such as `colo`
452
+ // (behaviors 7, 9).
453
+ json(buildActivityEnvelope(result));
454
+ return;
455
+ }
456
+ heading(`Events (page ${result.page}, ${result.total_rows} total)`);
457
+ console.log();
458
+ if (!result.rows || result.rows.length === 0) {
459
+ info("No events found.");
460
+ return;
461
+ }
462
+ // The USER cell prefers the feed's display name (#3168): only the
463
+ // system principal `sys:<appId>` has one, and its id is 30 characters
464
+ // — `formatId` truncated it at 26, mid-ULID. A column `format` sees
465
+ // only its own cell, so the fallback is folded in here.
466
+ const eventRows = result.rows.map((row) => ({
467
+ ...row,
468
+ user_display: row.user_name ?? formatId(row.user_ulid ?? ""),
469
+ }));
470
+ console.log(formatTable(eventRows, [
471
+ { header: "TIME", key: "timestamp", format: formatDate },
472
+ { header: "USER", key: "user_display" },
473
+ { header: "ACTION", key: "action" },
474
+ { header: "FEATURE", key: "feature" },
475
+ { header: "ROUTE", key: "route" },
476
+ { header: "COUNTRY", key: "country" },
477
+ ]));
478
+ const totalPages = Math.ceil(result.total_rows / result.page_size);
479
+ if (result.page + 1 < totalPages) {
480
+ console.log();
481
+ dim(`Page ${result.page + 1} of ${totalPages}. Use --page ${result.page + 1} for the next page.`);
482
+ }
483
+ }
484
+ catch (err) {
485
+ error(err.message);
486
+ process.exit(1);
487
+ }
488
+ });
489
+ // ── Events Grouped ───────────────────────────────────────────────
490
+ analytics
491
+ .command("events-grouped")
492
+ .description("Events grouped by a dimension")
493
+ .argument("[app-id]", "App ID (uses current app if not specified)")
494
+ .option("--app <app-id>", "App ID")
495
+ .option("--group-by <dim>", "Dimension: action, feature, route, country, deviceType, plan, day", "action")
496
+ .option("--window-days <n>", "Time window in days", "7")
497
+ .option("--json", "Output as JSON")
498
+ .action(async (appId, options) => {
499
+ const resolvedAppId = resolveAppId(appId, options);
500
+ const client = new ApiClient();
501
+ try {
502
+ const result = await client.getAnalyticsEventsGrouped(resolvedAppId, {
503
+ groupBy: options.groupBy,
504
+ windowDays: parseInt(options.windowDays),
505
+ });
506
+ if (options.json) {
507
+ json(result);
508
+ return;
509
+ }
510
+ heading(`Events by ${result.group_by}`);
511
+ console.log();
512
+ if (!result.rows || result.rows.length === 0) {
513
+ info("No events found.");
514
+ return;
515
+ }
516
+ console.log(formatTable(result.rows, [
517
+ { header: result.group_by.toUpperCase(), key: "group_value" },
518
+ { header: "EVENTS", key: "events", align: "right", format: formatNumber },
519
+ { header: "UNIQUE USERS", key: "unique_users", align: "right", format: formatNumber },
520
+ ]));
521
+ }
522
+ catch (err) {
523
+ error(err.message);
524
+ process.exit(1);
525
+ }
526
+ });
527
+ // ── Errors Grouped ───────────────────────────────────────────────
528
+ analytics
529
+ .command("errors-groups")
530
+ .description("Group failure events by fingerprint with per-day count buckets")
531
+ .argument("[app-id]", "App ID (uses current app if not specified)")
532
+ .option("--app <app-id>", "App ID")
533
+ .option("--window-days <n>", "Time window in days", "7")
534
+ .option("--limit <n>", "Max error groups to return", "50")
535
+ .option("--status-class <class>", "Filter by status class: 4xx, 5xx, transport")
536
+ .option("--source <source>", "Filter by source: workflow_run, workflow_step, integration")
537
+ .option("--verbose", "Also print each group's exemplar (a raw sample of the failure) and where it came from")
538
+ .option("--json", "Output as JSON")
539
+ .action(async (appId, options) => {
540
+ const resolvedAppId = resolveAppId(appId, options);
541
+ const client = new ApiClient();
542
+ try {
543
+ const params = {
544
+ windowDays: parseInt(options.windowDays),
545
+ limit: parseInt(options.limit),
546
+ };
547
+ if (options.statusClass) {
548
+ params["filter[statusClass][is]"] = options.statusClass;
549
+ }
550
+ if (options.source) {
551
+ params["filter[source][is]"] = options.source;
552
+ }
553
+ const result = await client.getAnalyticsErrorsGroups(resolvedAppId, params);
554
+ if (options.json) {
555
+ json(result);
556
+ return;
557
+ }
558
+ heading(`Error groups (last ${result.window_days} days)`);
559
+ console.log();
560
+ if (!result.rows || result.rows.length === 0) {
561
+ info("No error groups found.");
562
+ return;
563
+ }
564
+ console.log(formatTable(result.rows, [
565
+ { header: "TITLE", key: "normalized_title" },
566
+ { header: "SOURCE", key: "source" },
567
+ { header: "STATUS", key: "status_class" },
568
+ {
569
+ header: "TOTAL",
570
+ key: "total",
571
+ align: "right",
572
+ format: formatNumber,
573
+ },
574
+ {
575
+ header: "DAYS",
576
+ key: "daily",
577
+ align: "right",
578
+ format: (d) => formatNumber(Array.isArray(d) ? d.length : 0),
579
+ },
580
+ { header: "LAST SEEN", key: "last_seen", format: formatDate },
581
+ { header: "FINGERPRINT", key: "fingerprint", format: formatId },
582
+ ]));
583
+ // The normalized title is a grouping key, not an explanation — the
584
+ // exemplar is the raw sample plus the run/step it came from, which is
585
+ // what makes a group actionable without paging `analytics events`.
586
+ if (options.verbose) {
587
+ for (const row of result.rows) {
588
+ console.log();
589
+ heading(row.normalized_title || row.fingerprint);
590
+ printResult("Seen", `${row.first_seen ? formatDate(row.first_seen) : "-"} → ${row.last_seen ? formatDate(row.last_seen) : "-"}`);
591
+ if (!row.exemplar) {
592
+ info("No exemplar available for this group.");
593
+ continue;
594
+ }
595
+ printResult("Example", row.exemplar.message);
596
+ printResult("Scope", row.exemplar.scope_key || "-");
597
+ printResult("Step", row.exemplar.step_id || "-");
598
+ printResult("Run", row.exemplar.run_id || "-");
599
+ }
600
+ }
601
+ }
602
+ catch (err) {
603
+ error(err.message);
604
+ process.exit(1);
605
+ }
606
+ });
607
+ // ── Integration Metrics ──────────────────────────────────────────
149
608
  analytics
150
609
  .command("integrations")
151
610
  .description("Get integration usage metrics")
@@ -174,8 +633,8 @@ Examples:
174
633
  { header: "INTEGRATION", key: "integrationKey" },
175
634
  { header: "CALLS", key: "invocations", align: "right", format: formatNumber },
176
635
  { header: "ERROR RATE", key: "errorRate", align: "right", format: formatPercent },
177
- { header: "AVG LATENCY", key: "avgDurationMs", align: "right", format: formatDuration },
178
- { header: "P95 LATENCY", key: "p95DurationMs", align: "right", format: formatDuration },
636
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
637
+ { header: "P95", key: "p95DurationMs", align: "right", format: formatDuration },
179
638
  ]));
180
639
  }
181
640
  catch (err) {
@@ -183,5 +642,191 @@ Examples:
183
642
  process.exit(1);
184
643
  }
185
644
  });
645
+ // ── Top Workflows ────────────────────────────────────────────────
646
+ analytics
647
+ .command("workflows")
648
+ .description("Top workflows by runs")
649
+ .argument("[app-id]", "App ID (uses current app if not specified)")
650
+ .option("--app <app-id>", "App ID")
651
+ .option("--window-days <n>", "Time window in days", "30")
652
+ .option("--limit <n>", "Number of workflows to show", "10")
653
+ .option("--json", "Output as JSON")
654
+ .action(async (appId, options) => {
655
+ const resolvedAppId = resolveAppId(appId, options);
656
+ const client = new ApiClient();
657
+ try {
658
+ const result = await client.getAnalyticsTopWorkflows(resolvedAppId, {
659
+ windowDays: parseInt(options.windowDays),
660
+ limit: parseInt(options.limit),
661
+ });
662
+ if (options.json) {
663
+ json(result);
664
+ return;
665
+ }
666
+ heading(`Top Workflows (${result.windowDays} days)`);
667
+ console.log();
668
+ if (!result.workflows || result.workflows.length === 0) {
669
+ info("No workflow data found.");
670
+ return;
671
+ }
672
+ console.log(formatTable(result.workflows, [
673
+ { header: "WORKFLOW", key: "workflowKey" },
674
+ { header: "RUNS", key: "runs", align: "right", format: formatNumber },
675
+ { header: "SUCCESS", key: "successRate", align: "right", format: formatPercent },
676
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
677
+ { header: "P95", key: "p95", align: "right", format: formatDuration },
678
+ { header: "TOKENS", key: "totalTokens", align: "right", format: formatNumber },
679
+ ]));
680
+ }
681
+ catch (err) {
682
+ error(err.message);
683
+ process.exit(1);
684
+ }
685
+ });
686
+ // ── Top Prompts ──────────────────────────────────────────────────
687
+ analytics
688
+ .command("prompts")
689
+ .description("Top prompts by executions")
690
+ .argument("[app-id]", "App ID (uses current app if not specified)")
691
+ .option("--app <app-id>", "App ID")
692
+ .option("--window-days <n>", "Time window in days", "30")
693
+ .option("--limit <n>", "Number of prompts to show", "10")
694
+ .option("--json", "Output as JSON")
695
+ .action(async (appId, options) => {
696
+ const resolvedAppId = resolveAppId(appId, options);
697
+ const client = new ApiClient();
698
+ try {
699
+ const result = await client.getAnalyticsTopPrompts(resolvedAppId, {
700
+ windowDays: parseInt(options.windowDays),
701
+ limit: parseInt(options.limit),
702
+ });
703
+ if (options.json) {
704
+ json(result);
705
+ return;
706
+ }
707
+ heading(`Top Prompts (${result.windowDays} days)`);
708
+ console.log();
709
+ if (!result.prompts || result.prompts.length === 0) {
710
+ info("No prompt data found.");
711
+ return;
712
+ }
713
+ console.log(formatTable(result.prompts, [
714
+ { header: "PROMPT", key: "promptKey" },
715
+ { header: "RUNS", key: "executions", align: "right", format: formatNumber },
716
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
717
+ { header: "P95", key: "p95DurationMs", align: "right", format: formatDuration },
718
+ { header: "TOKENS", key: "totalTokens", align: "right", format: formatNumber },
719
+ ]));
720
+ }
721
+ catch (err) {
722
+ error(err.message);
723
+ process.exit(1);
724
+ }
725
+ });
726
+ // ── Workflow step usage ──────────────────────────────────────────
727
+ /** Print one report's blocks: headings to stderr, bodies to stdout. */
728
+ function printUsageBlocks(blocks) {
729
+ for (const block of blocks) {
730
+ if (block.heading) {
731
+ console.log();
732
+ heading(block.heading);
733
+ }
734
+ console.log(block.body);
735
+ }
736
+ }
737
+ analytics
738
+ .command("workflow-usage")
739
+ .description("Step kinds this app's workflows configure, their runs in the window, and the sync-callable and idle workflows")
740
+ .argument("[app-id]", "App ID (uses current app if not specified)")
741
+ .option("--app <app-id>", "App ID")
742
+ .option("--window-days <n>", `Run window in days (${USAGE_CLI_MIN_WINDOW_DAYS}-${USAGE_CLI_MAX_WINDOW_DAYS}, default ${USAGE_CLI_DEFAULT_WINDOW_DAYS})`)
743
+ .option("--all-apps", "Merge the report across every app (super-admin only)")
744
+ .option("--json", "Output as JSON")
745
+ .action(async (appId, options) => {
746
+ // Both boundary checks run before the client is constructed, so an
747
+ // invalid invocation never reaches the network (principle 6).
748
+ if (options.allApps && (appId || options.app)) {
749
+ error(ALL_APPS_CONFLICT_ERROR);
750
+ process.exit(1);
751
+ }
752
+ const window = parseWindowDaysFlag(options.windowDays);
753
+ if ("error" in window) {
754
+ error(window.error);
755
+ process.exit(1);
756
+ return;
757
+ }
758
+ // Omitted means omitted on the wire: the server applies its own default
759
+ // and the CLI reports the same number for a merge that has no request.
760
+ const params = window.omitted
761
+ ? undefined
762
+ : { windowDays: window.effective };
763
+ const client = new ApiClient();
764
+ if (options.allApps) {
765
+ try {
766
+ // The role gate comes first and is server-side: GET /admin/api/apps
767
+ // has no role filter, and the per-app endpoint admits any admin
768
+ // assigned to the app, so an app admin assigned to every app would
769
+ // otherwise receive the aggregate (D3130-002).
770
+ const me = await client.getMe();
771
+ if (!isSuperAdminRole(me.role)) {
772
+ error(ALL_APPS_SUPER_ADMIN_ERROR);
773
+ process.exit(1);
774
+ }
775
+ // There is no cross-app endpoint by design (intent): the CLI calls
776
+ // the per-app one once per app, over the GLOBAL apps list.
777
+ const apps = await client.listAllAppsGlobal();
778
+ const results = [];
779
+ for (const app of apps) {
780
+ try {
781
+ results.push({
782
+ appId: app.appId,
783
+ report: await client.getWorkflowUsage(app.appId, params),
784
+ });
785
+ }
786
+ catch (err) {
787
+ // A merged report over a silently chosen subset would answer a
788
+ // different question, so a refusal ends the walk.
789
+ if (isAbortStatus(err?.statusCode))
790
+ throw err;
791
+ results.push({
792
+ appId: app.appId,
793
+ error: err?.message ?? String(err),
794
+ });
795
+ }
796
+ }
797
+ const merged = mergeUsageReports(window.effective, results);
798
+ if (options.json) {
799
+ json(merged);
800
+ }
801
+ else {
802
+ printUsageBlocks(renderMergedUsageReport(merged));
803
+ }
804
+ // An incomplete report still prints, and still fails (intent).
805
+ // `exitCode` rather than `exit()`: the report is already on stdout
806
+ // and `process.exit` truncates a pipe's pending writes (#1004).
807
+ process.exitCode = usageExitCode(merged);
808
+ }
809
+ catch (err) {
810
+ error(err.message);
811
+ process.exit(1);
812
+ }
813
+ return;
814
+ }
815
+ const resolvedAppId = resolveAppId(appId, options);
816
+ try {
817
+ const report = await client.getWorkflowUsage(resolvedAppId, params);
818
+ if (options.json) {
819
+ json(report);
820
+ }
821
+ else {
822
+ printUsageBlocks(renderUsageReport(report));
823
+ }
824
+ process.exitCode = usageExitCode(report);
825
+ }
826
+ catch (err) {
827
+ error(err.message);
828
+ process.exit(1);
829
+ }
830
+ });
186
831
  }
187
832
  //# sourceMappingURL=analytics.js.map