primitive-admin 1.1.0-alpha.9 → 1.1.0

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