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