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,57 +1,219 @@
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
+ /** Format a value that is already a percentage (e.g. 33.3 → "33.3%") */
6
+ function formatPctRaw(value) {
7
+ if (value === undefined || value === null)
8
+ return "-";
9
+ return `${value.toFixed(1)}%`;
10
+ }
4
11
  export function registerAnalyticsCommands(program) {
5
12
  const analytics = program
6
13
  .command("analytics")
7
14
  .description("View usage analytics, user activity, and integration metrics")
15
+ // Subcommands are listed once, by commander, from what is registered
16
+ // below — a second hand-written list drifts (#2860: `errors-groups`
17
+ // shipped and never reached the copy). Examples illustrate; they do not
18
+ // re-list the group.
8
19
  .addHelpText("after", `
9
20
  Examples:
10
21
  $ primitive analytics overview
11
- $ primitive analytics top-users --window-days 7 --limit 20
12
- $ primitive analytics integrations
22
+ $ primitive analytics daily-active --window-days 14
23
+ $ primitive analytics top-users --limit 20
24
+ $ primitive analytics user-search --query user@example.com
25
+ $ primitive analytics user-detail <user-ulid>
26
+ $ primitive analytics events --window-days 7 --page 0
27
+ $ primitive analytics events-grouped --group-by feature
28
+ $ primitive analytics errors-groups --window-days 14 --limit 100
29
+ $ primitive analytics cohort-retention
30
+ $ primitive analytics workflows --limit 5
31
+ $ primitive analytics prompts --window-days 14
13
32
  `);
14
- // Overview
33
+ // ── Overview (DAU / WAU / MAU / Growth) ──────────────────────────
15
34
  analytics
16
35
  .command("overview")
17
- .description("Get analytics overview for an app")
36
+ .description("Show DAU, WAU, MAU, and growth accounting")
18
37
  .argument("[app-id]", "App ID (uses current app if not specified)")
19
38
  .option("--app <app-id>", "App ID")
20
- .option("--window-days <n>", "Time window in days", "30")
39
+ .option("--window-days <n>", "Growth window in days", "28")
21
40
  .option("--json", "Output as JSON")
22
41
  .action(async (appId, options) => {
23
42
  const resolvedAppId = resolveAppId(appId, options);
24
43
  const client = new ApiClient();
25
44
  try {
26
- const result = await client.getAnalyticsOverview(resolvedAppId, {
45
+ const [dau, wau, mau, growth] = await Promise.all([
46
+ client.getAnalyticsOverviewDau(resolvedAppId),
47
+ client.getAnalyticsOverviewWau(resolvedAppId),
48
+ client.getAnalyticsOverviewMau(resolvedAppId),
49
+ client.getAnalyticsOverviewGrowth(resolvedAppId, {
50
+ windowDays: parseInt(options.windowDays),
51
+ }),
52
+ ]);
53
+ if (options.json) {
54
+ json({ dau, wau, mau, growth });
55
+ return;
56
+ }
57
+ heading("Active Users");
58
+ console.log();
59
+ const formatDelta = (d) => d > 0 ? `+${(d * 100).toFixed(1)}%` : d === 0 ? "0%" : `${(d * 100).toFixed(1)}%`;
60
+ console.log(formatTable([
61
+ { metric: "DAU", value: dau.value, previous: dau.previous, delta: formatDelta(dau.deltaPct) },
62
+ { metric: "WAU", value: wau.value, previous: wau.previous, delta: formatDelta(wau.deltaPct) },
63
+ { metric: "MAU", value: mau.value, previous: mau.previous, delta: formatDelta(mau.deltaPct) },
64
+ ], [
65
+ { header: "METRIC", key: "metric" },
66
+ { header: "CURRENT", key: "value", align: "right", format: formatNumber },
67
+ { header: "PREVIOUS", key: "previous", align: "right", format: formatNumber },
68
+ { header: "CHANGE", key: "delta", align: "right" },
69
+ ]));
70
+ console.log();
71
+ heading(`Growth Accounting (${growth.window_days} days)`);
72
+ console.log();
73
+ printResult("Current active", String(growth.current_active));
74
+ printResult("Previous active", String(growth.previous_active));
75
+ printResult("New users", String(growth.new_users));
76
+ printResult("Retained", String(growth.retained_users));
77
+ printResult("Reactivated", String(growth.reactivated_users));
78
+ printResult("Churned", String(growth.churned_users));
79
+ printResult("Delta", formatDelta(growth.deltaPct));
80
+ }
81
+ catch (err) {
82
+ error(err.message);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ // ── Daily Active ─────────────────────────────────────────────────
87
+ analytics
88
+ .command("daily-active")
89
+ .description("Daily active users time series")
90
+ .argument("[app-id]", "App ID (uses current app if not specified)")
91
+ .option("--app <app-id>", "App ID")
92
+ .option("--window-days <n>", "Time window in days (7-90)", "28")
93
+ .option("--json", "Output as JSON")
94
+ .action(async (appId, options) => {
95
+ const resolvedAppId = resolveAppId(appId, options);
96
+ const client = new ApiClient();
97
+ try {
98
+ const result = await client.getAnalyticsDailyActive(resolvedAppId, {
27
99
  windowDays: parseInt(options.windowDays),
28
100
  });
29
101
  if (options.json) {
30
102
  json(result);
31
103
  return;
32
104
  }
33
- heading(`Analytics Overview (${result.windowDays} days)`);
105
+ heading(`Daily Active Users (${result.window_days} days)`);
34
106
  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
- ]));
107
+ if (!result.rows || result.rows.length === 0) {
108
+ info("No data found.");
109
+ return;
47
110
  }
111
+ console.log(formatTable(result.rows, [
112
+ { header: "DATE", key: "day_label" },
113
+ { header: "ACTIVE USERS", key: "active_users", align: "right", format: formatNumber },
114
+ ]));
48
115
  }
49
116
  catch (err) {
50
117
  error(err.message);
51
118
  process.exit(1);
52
119
  }
53
120
  });
54
- // Top users
121
+ // ── Rolling Active ───────────────────────────────────────────────
122
+ analytics
123
+ .command("rolling-active")
124
+ .description("Rolling active users (28 data points)")
125
+ .argument("[app-id]", "App ID (uses current app if not specified)")
126
+ .option("--app <app-id>", "App ID")
127
+ .option("--window-days <n>", "Rolling window size in days (1-28)", "7")
128
+ .option("--json", "Output as JSON")
129
+ .action(async (appId, options) => {
130
+ const resolvedAppId = resolveAppId(appId, options);
131
+ const client = new ApiClient();
132
+ try {
133
+ const result = await client.getAnalyticsRollingActive(resolvedAppId, {
134
+ windowDays: parseInt(options.windowDays),
135
+ });
136
+ if (options.json) {
137
+ json(result);
138
+ return;
139
+ }
140
+ heading(`Rolling Active Users (${result.window_days}-day window)`);
141
+ console.log();
142
+ if (!result.rows || result.rows.length === 0) {
143
+ info("No data found.");
144
+ return;
145
+ }
146
+ console.log(formatTable(result.rows, [
147
+ { header: "DATE", key: "day_label" },
148
+ { header: "ACTIVE USERS", key: "active_users", align: "right", format: formatNumber },
149
+ ]));
150
+ }
151
+ catch (err) {
152
+ error(err.message);
153
+ process.exit(1);
154
+ }
155
+ });
156
+ // ── Cohort Retention ─────────────────────────────────────────────
157
+ analytics
158
+ .command("cohort-retention")
159
+ .description("Weekly cohort retention matrix")
160
+ .argument("[app-id]", "App ID (uses current app if not specified)")
161
+ .option("--app <app-id>", "App ID")
162
+ .option("--json", "Output as JSON")
163
+ .action(async (appId, options) => {
164
+ const resolvedAppId = resolveAppId(appId, options);
165
+ const client = new ApiClient();
166
+ try {
167
+ const result = await client.getAnalyticsCohortRetention(resolvedAppId);
168
+ if (options.json) {
169
+ json(result);
170
+ return;
171
+ }
172
+ heading("Cohort Retention");
173
+ console.log();
174
+ if (!result.rows || result.rows.length === 0) {
175
+ info("No cohort data found.");
176
+ return;
177
+ }
178
+ // Build week headers
179
+ const weekHeaders = result.weeks.map((w) => `W${w}`);
180
+ // Build table rows with retention percentages
181
+ const tableRows = result.rows.map((row) => {
182
+ const entry = {
183
+ cohort: row.signup_week_label,
184
+ size: row.cohort_size,
185
+ };
186
+ row.retention.forEach((r, i) => {
187
+ entry[`w${result.weeks[i]}`] =
188
+ r !== null ? `${r.toFixed(0)}%` : "-";
189
+ });
190
+ return entry;
191
+ });
192
+ const columns = [
193
+ { header: "COHORT", key: "cohort" },
194
+ { header: "SIZE", key: "size", align: "right", format: formatNumber },
195
+ ...weekHeaders.map((h, i) => ({
196
+ header: h,
197
+ key: `w${result.weeks[i]}`,
198
+ align: "right",
199
+ })),
200
+ ];
201
+ console.log(formatTable(tableRows, columns));
202
+ // Print averages row
203
+ if (result.averages) {
204
+ const avgStr = result.averages
205
+ .map((a) => a !== null ? `${a.toFixed(0)}%` : "-")
206
+ .join(" ");
207
+ console.log();
208
+ dim(`Averages: ${avgStr}`);
209
+ }
210
+ }
211
+ catch (err) {
212
+ error(err.message);
213
+ process.exit(1);
214
+ }
215
+ });
216
+ // ── Top Users ────────────────────────────────────────────────────
55
217
  analytics
56
218
  .command("top-users")
57
219
  .description("Get top users by activity")
@@ -80,6 +242,7 @@ Examples:
80
242
  }
81
243
  console.log(formatTable(result.results, [
82
244
  { header: "USER", key: "userUlid", format: formatId },
245
+ { header: "EMAIL", key: "email" },
83
246
  { header: "EVENTS", key: "eventCount", align: "right" },
84
247
  { header: "FIRST SEEN", key: "firstSeen", format: formatDate },
85
248
  { header: "LAST SEEN", key: "lastSeen", format: formatDate },
@@ -90,53 +253,93 @@ Examples:
90
253
  process.exit(1);
91
254
  }
92
255
  });
93
- // User details
256
+ // ── User Search ──────────────────────────────────────────────────
94
257
  analytics
95
- .command("user")
96
- .description("Get analytics for a specific user")
258
+ .command("user-search")
259
+ .description("Search users by email or ULID")
97
260
  .argument("[app-id]", "App ID (uses current app if not specified)")
98
- .argument("<user-ulid>", "User ULID")
99
261
  .option("--app <app-id>", "App ID")
100
- .option("--window-days <n>", "Time window in days", "30")
262
+ .requiredOption("--query <q>", "Email or ULID to search for")
263
+ .option("--limit <n>", "Max results", "25")
101
264
  .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;
265
+ .action(async (appId, options) => {
266
+ const resolvedAppId = resolveAppId(appId, options);
267
+ const client = new ApiClient();
268
+ try {
269
+ const result = await client.getAnalyticsUserSearch(resolvedAppId, {
270
+ q: options.query,
271
+ limit: parseInt(options.limit),
272
+ });
273
+ if (options.json) {
274
+ json(result);
275
+ return;
276
+ }
277
+ heading(`User Search: "${result.query}"`);
278
+ console.log();
279
+ if (!result.results || result.results.length === 0) {
280
+ info("No users found.");
281
+ return;
282
+ }
283
+ console.log(formatTable(result.results, [
284
+ { header: "USER", key: "userUlid", format: formatId },
285
+ { header: "EMAIL", key: "email" },
286
+ { header: "NAME", key: "name" },
287
+ { header: "EVENTS", key: "eventCount", align: "right" },
288
+ { header: "LAST SEEN", key: "lastSeen", format: formatDate },
289
+ ]));
108
290
  }
109
- else {
110
- resolvedAppId = resolveAppId(undefined, options);
111
- userUlid = appIdOrUserUlid;
291
+ catch (err) {
292
+ error(err.message);
293
+ process.exit(1);
112
294
  }
295
+ });
296
+ // ── User Detail ──────────────────────────────────────────────────
297
+ analytics
298
+ .command("user-detail")
299
+ .description("Detailed activity for a single user")
300
+ .argument("<user-ulid>", "User ULID")
301
+ .argument("[app-id]", "App ID (uses current app if not specified)")
302
+ .option("--app <app-id>", "App ID")
303
+ .option("--json", "Output as JSON")
304
+ .action(async (userUlid, appId, options) => {
305
+ const resolvedAppId = resolveAppId(appId, options);
113
306
  const client = new ApiClient();
114
307
  try {
115
- const result = await client.getAnalyticsUserTimeline(resolvedAppId, userUlid, {
116
- windowDays: parseInt(options.windowDays),
117
- });
308
+ const result = await client.getAnalyticsUserDetail(resolvedAppId, userUlid);
118
309
  if (options.json) {
119
310
  json(result);
120
311
  return;
121
312
  }
122
- heading(`User Activity (${result.windowDays} days)`);
123
- keyValue("User", userUlid);
313
+ heading("User Detail");
314
+ console.log();
315
+ printResult("ULID", result.user.user_ulid);
316
+ if (result.user.email)
317
+ printResult("Email", result.user.email);
318
+ if (result.user.name)
319
+ printResult("Name", result.user.name);
124
320
  console.log();
125
- if (result.breakdown && result.breakdown.length > 0) {
126
- info("Activity Breakdown:");
127
- console.log(formatTable(result.breakdown.slice(0, 15), [
321
+ printResult("First seen", result.stats.first_seen ? formatDate(result.stats.first_seen) : "-");
322
+ printResult("Last active", result.stats.last_active ? formatDate(result.stats.last_active) : "-");
323
+ printResult("Total events", String(result.stats.total_events));
324
+ printResult("Days active", String(result.stats.days_active));
325
+ if (result.events_by_action?.length > 0) {
326
+ console.log();
327
+ heading("Events by Action");
328
+ console.log();
329
+ console.log(formatTable(result.events_by_action, [
128
330
  { header: "ACTION", key: "action" },
129
- { header: "FEATURE", key: "feature" },
130
- { header: "ROUTE", key: "route" },
131
- { header: "EVENTS", key: "events", align: "right" },
331
+ { header: "COUNT", key: "event_count", align: "right", format: formatNumber },
332
+ { header: "LAST OCCURRED", key: "last_occurred", format: formatDate },
132
333
  ]));
133
334
  }
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" },
335
+ if (result.events_by_feature?.length > 0) {
336
+ console.log();
337
+ heading("Events by Feature");
338
+ console.log();
339
+ console.log(formatTable(result.events_by_feature, [
340
+ { header: "FEATURE", key: "feature" },
341
+ { header: "COUNT", key: "event_count", align: "right", format: formatNumber },
342
+ { header: "PCT", key: "pct", align: "right", format: formatPctRaw },
140
343
  ]));
141
344
  }
142
345
  }
@@ -145,7 +348,212 @@ Examples:
145
348
  process.exit(1);
146
349
  }
147
350
  });
148
- // Integration metrics
351
+ // ── User Snapshot ────────────────────────────────────────────────
352
+ analytics
353
+ .command("user-snapshot")
354
+ .description("Latest context snapshot for a user")
355
+ .argument("<user-ulid>", "User ULID")
356
+ .argument("[app-id]", "App ID (uses current app if not specified)")
357
+ .option("--app <app-id>", "App ID")
358
+ .option("--json", "Output as JSON")
359
+ .action(async (userUlid, appId, options) => {
360
+ const resolvedAppId = resolveAppId(appId, options);
361
+ const client = new ApiClient();
362
+ try {
363
+ const result = await client.getAnalyticsUserSnapshot(resolvedAppId, userUlid);
364
+ if (options.json) {
365
+ json(result);
366
+ return;
367
+ }
368
+ heading("User Snapshot");
369
+ console.log();
370
+ if (!result.snapshot) {
371
+ info("No snapshot found for this user.");
372
+ return;
373
+ }
374
+ printResult("Timestamp", formatDate(result.snapshot.timestamp));
375
+ console.log();
376
+ console.log(JSON.stringify(result.snapshot.values, null, 2));
377
+ }
378
+ catch (err) {
379
+ error(err.message);
380
+ process.exit(1);
381
+ }
382
+ });
383
+ // ── Events Feed ──────────────────────────────────────────────────
384
+ analytics
385
+ .command("events")
386
+ .description("Paginated event feed")
387
+ .argument("[app-id]", "App ID (uses current app if not specified)")
388
+ .option("--app <app-id>", "App ID")
389
+ .option("--window-days <n>", "Time window in days", "7")
390
+ .option("--page <n>", "Page number (0-based)", "0")
391
+ .option("--user-id <id>", "Filter to a single user's events")
392
+ .option("--json", "Output as JSON")
393
+ .action(async (appId, options) => {
394
+ const resolvedAppId = resolveAppId(appId, options);
395
+ const client = new ApiClient();
396
+ try {
397
+ const result = await client.getAnalyticsEvents(resolvedAppId, {
398
+ windowDays: parseInt(options.windowDays),
399
+ page: parseInt(options.page),
400
+ // The events feed filters by user via the bracketed
401
+ // `filter[user][is]` syntax the analytics route already parses — not
402
+ // a raw query param (behavior 11).
403
+ ...(options.userId ? { "filter[user][is]": options.userId } : {}),
404
+ });
405
+ if (options.json) {
406
+ // Normalize the offset-paged response to the shared activity
407
+ // envelope: `{page_size, rows}` → `{pageSize, items}` with the
408
+ // activity allowlist dropping infra fields such as `colo`
409
+ // (behaviors 7, 9).
410
+ json(buildActivityEnvelope(result));
411
+ return;
412
+ }
413
+ heading(`Events (page ${result.page}, ${result.total_rows} total)`);
414
+ console.log();
415
+ if (!result.rows || result.rows.length === 0) {
416
+ info("No events found.");
417
+ return;
418
+ }
419
+ console.log(formatTable(result.rows, [
420
+ { header: "TIME", key: "timestamp", format: formatDate },
421
+ { header: "USER", key: "user_ulid", format: formatId },
422
+ { header: "ACTION", key: "action" },
423
+ { header: "FEATURE", key: "feature" },
424
+ { header: "ROUTE", key: "route" },
425
+ { header: "COUNTRY", key: "country" },
426
+ ]));
427
+ const totalPages = Math.ceil(result.total_rows / result.page_size);
428
+ if (result.page + 1 < totalPages) {
429
+ console.log();
430
+ dim(`Page ${result.page + 1} of ${totalPages}. Use --page ${result.page + 1} for the next page.`);
431
+ }
432
+ }
433
+ catch (err) {
434
+ error(err.message);
435
+ process.exit(1);
436
+ }
437
+ });
438
+ // ── Events Grouped ───────────────────────────────────────────────
439
+ analytics
440
+ .command("events-grouped")
441
+ .description("Events grouped by a dimension")
442
+ .argument("[app-id]", "App ID (uses current app if not specified)")
443
+ .option("--app <app-id>", "App ID")
444
+ .option("--group-by <dim>", "Dimension: action, feature, route, country, deviceType, plan, day", "action")
445
+ .option("--window-days <n>", "Time window in days", "7")
446
+ .option("--json", "Output as JSON")
447
+ .action(async (appId, options) => {
448
+ const resolvedAppId = resolveAppId(appId, options);
449
+ const client = new ApiClient();
450
+ try {
451
+ const result = await client.getAnalyticsEventsGrouped(resolvedAppId, {
452
+ groupBy: options.groupBy,
453
+ windowDays: parseInt(options.windowDays),
454
+ });
455
+ if (options.json) {
456
+ json(result);
457
+ return;
458
+ }
459
+ heading(`Events by ${result.group_by}`);
460
+ console.log();
461
+ if (!result.rows || result.rows.length === 0) {
462
+ info("No events found.");
463
+ return;
464
+ }
465
+ console.log(formatTable(result.rows, [
466
+ { header: result.group_by.toUpperCase(), key: "group_value" },
467
+ { header: "EVENTS", key: "events", align: "right", format: formatNumber },
468
+ { header: "UNIQUE USERS", key: "unique_users", align: "right", format: formatNumber },
469
+ ]));
470
+ }
471
+ catch (err) {
472
+ error(err.message);
473
+ process.exit(1);
474
+ }
475
+ });
476
+ // ── Errors Grouped ───────────────────────────────────────────────
477
+ analytics
478
+ .command("errors-groups")
479
+ .description("Group failure events by fingerprint with per-day count buckets")
480
+ .argument("[app-id]", "App ID (uses current app if not specified)")
481
+ .option("--app <app-id>", "App ID")
482
+ .option("--window-days <n>", "Time window in days", "7")
483
+ .option("--limit <n>", "Max error groups to return", "50")
484
+ .option("--status-class <class>", "Filter by status class: 4xx, 5xx, transport")
485
+ .option("--source <source>", "Filter by source: workflow_run, workflow_step, integration")
486
+ .option("--verbose", "Also print each group's exemplar (a raw sample of the failure) and where it came from")
487
+ .option("--json", "Output as JSON")
488
+ .action(async (appId, options) => {
489
+ const resolvedAppId = resolveAppId(appId, options);
490
+ const client = new ApiClient();
491
+ try {
492
+ const params = {
493
+ windowDays: parseInt(options.windowDays),
494
+ limit: parseInt(options.limit),
495
+ };
496
+ if (options.statusClass) {
497
+ params["filter[statusClass][is]"] = options.statusClass;
498
+ }
499
+ if (options.source) {
500
+ params["filter[source][is]"] = options.source;
501
+ }
502
+ const result = await client.getAnalyticsErrorsGroups(resolvedAppId, params);
503
+ if (options.json) {
504
+ json(result);
505
+ return;
506
+ }
507
+ heading(`Error groups (last ${result.window_days} days)`);
508
+ console.log();
509
+ if (!result.rows || result.rows.length === 0) {
510
+ info("No error groups found.");
511
+ return;
512
+ }
513
+ console.log(formatTable(result.rows, [
514
+ { header: "TITLE", key: "normalized_title" },
515
+ { header: "SOURCE", key: "source" },
516
+ { header: "STATUS", key: "status_class" },
517
+ {
518
+ header: "TOTAL",
519
+ key: "total",
520
+ align: "right",
521
+ format: formatNumber,
522
+ },
523
+ {
524
+ header: "DAYS",
525
+ key: "daily",
526
+ align: "right",
527
+ format: (d) => formatNumber(Array.isArray(d) ? d.length : 0),
528
+ },
529
+ { header: "LAST SEEN", key: "last_seen", format: formatDate },
530
+ { header: "FINGERPRINT", key: "fingerprint", format: formatId },
531
+ ]));
532
+ // The normalized title is a grouping key, not an explanation — the
533
+ // exemplar is the raw sample plus the run/step it came from, which is
534
+ // what makes a group actionable without paging `analytics events`.
535
+ if (options.verbose) {
536
+ for (const row of result.rows) {
537
+ console.log();
538
+ heading(row.normalized_title || row.fingerprint);
539
+ printResult("Seen", `${row.first_seen ? formatDate(row.first_seen) : "-"} → ${row.last_seen ? formatDate(row.last_seen) : "-"}`);
540
+ if (!row.exemplar) {
541
+ info("No exemplar available for this group.");
542
+ continue;
543
+ }
544
+ printResult("Example", row.exemplar.message);
545
+ printResult("Scope", row.exemplar.scope_key || "-");
546
+ printResult("Step", row.exemplar.step_id || "-");
547
+ printResult("Run", row.exemplar.run_id || "-");
548
+ }
549
+ }
550
+ }
551
+ catch (err) {
552
+ error(err.message);
553
+ process.exit(1);
554
+ }
555
+ });
556
+ // ── Integration Metrics ──────────────────────────────────────────
149
557
  analytics
150
558
  .command("integrations")
151
559
  .description("Get integration usage metrics")
@@ -174,8 +582,89 @@ Examples:
174
582
  { header: "INTEGRATION", key: "integrationKey" },
175
583
  { header: "CALLS", key: "invocations", align: "right", format: formatNumber },
176
584
  { 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 },
585
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
586
+ { header: "P95", key: "p95DurationMs", align: "right", format: formatDuration },
587
+ ]));
588
+ }
589
+ catch (err) {
590
+ error(err.message);
591
+ process.exit(1);
592
+ }
593
+ });
594
+ // ── Top Workflows ────────────────────────────────────────────────
595
+ analytics
596
+ .command("workflows")
597
+ .description("Top workflows by runs")
598
+ .argument("[app-id]", "App ID (uses current app if not specified)")
599
+ .option("--app <app-id>", "App ID")
600
+ .option("--window-days <n>", "Time window in days", "30")
601
+ .option("--limit <n>", "Number of workflows to show", "10")
602
+ .option("--json", "Output as JSON")
603
+ .action(async (appId, options) => {
604
+ const resolvedAppId = resolveAppId(appId, options);
605
+ const client = new ApiClient();
606
+ try {
607
+ const result = await client.getAnalyticsTopWorkflows(resolvedAppId, {
608
+ windowDays: parseInt(options.windowDays),
609
+ limit: parseInt(options.limit),
610
+ });
611
+ if (options.json) {
612
+ json(result);
613
+ return;
614
+ }
615
+ heading(`Top Workflows (${result.windowDays} days)`);
616
+ console.log();
617
+ if (!result.workflows || result.workflows.length === 0) {
618
+ info("No workflow data found.");
619
+ return;
620
+ }
621
+ console.log(formatTable(result.workflows, [
622
+ { header: "WORKFLOW", key: "workflowKey" },
623
+ { header: "RUNS", key: "runs", align: "right", format: formatNumber },
624
+ { header: "SUCCESS", key: "successRate", align: "right", format: formatPercent },
625
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
626
+ { header: "P95", key: "p95", align: "right", format: formatDuration },
627
+ { header: "TOKENS", key: "totalTokens", align: "right", format: formatNumber },
628
+ ]));
629
+ }
630
+ catch (err) {
631
+ error(err.message);
632
+ process.exit(1);
633
+ }
634
+ });
635
+ // ── Top Prompts ──────────────────────────────────────────────────
636
+ analytics
637
+ .command("prompts")
638
+ .description("Top prompts by executions")
639
+ .argument("[app-id]", "App ID (uses current app if not specified)")
640
+ .option("--app <app-id>", "App ID")
641
+ .option("--window-days <n>", "Time window in days", "30")
642
+ .option("--limit <n>", "Number of prompts to show", "10")
643
+ .option("--json", "Output as JSON")
644
+ .action(async (appId, options) => {
645
+ const resolvedAppId = resolveAppId(appId, options);
646
+ const client = new ApiClient();
647
+ try {
648
+ const result = await client.getAnalyticsTopPrompts(resolvedAppId, {
649
+ windowDays: parseInt(options.windowDays),
650
+ limit: parseInt(options.limit),
651
+ });
652
+ if (options.json) {
653
+ json(result);
654
+ return;
655
+ }
656
+ heading(`Top Prompts (${result.windowDays} days)`);
657
+ console.log();
658
+ if (!result.prompts || result.prompts.length === 0) {
659
+ info("No prompt data found.");
660
+ return;
661
+ }
662
+ console.log(formatTable(result.prompts, [
663
+ { header: "PROMPT", key: "promptKey" },
664
+ { header: "RUNS", key: "executions", align: "right", format: formatNumber },
665
+ { header: "MEDIAN", key: "medianDurationMs", align: "right", format: formatDuration },
666
+ { header: "P95", key: "p95DurationMs", align: "right", format: formatDuration },
667
+ { header: "TOKENS", key: "totalTokens", align: "right", format: formatNumber },
179
668
  ]));
180
669
  }
181
670
  catch (err) {