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,11 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { basename } from "path";
|
|
3
|
-
import * as TOML from "@iarna/toml";
|
|
4
|
-
import { lookup as mimeLookup } from "mime-types";
|
|
1
|
+
import { writeFileSync } from "fs";
|
|
5
2
|
import { ApiClient } from "../lib/api-client.js";
|
|
6
3
|
import { resolveAppId } from "../lib/config.js";
|
|
7
4
|
import chalk from "chalk";
|
|
8
|
-
import { success, error, info, warn, keyValue, formatTable, formatId, formatDate, formatStatus, formatDuration, json, divider, } from "../lib/output.js";
|
|
5
|
+
import { success, error, info, warn, keyValue, result as printResult, formatTable, formatId, formatDate, formatStatus, formatDuration, json, divider, progress, progressEnd, } from "../lib/output.js";
|
|
6
|
+
import { pollUntil } from "../lib/watch.js";
|
|
7
|
+
import { confirmPrompt } from "../lib/confirm-prompt.js";
|
|
8
|
+
import { parseStatusFilter } from "../lib/object-status-filter.js";
|
|
9
|
+
import { formatAccessRuleForDisplay } from "../lib/access-rule-display.js";
|
|
10
|
+
import { requireTestCaseInputVariables } from "../lib/test-case-variables.js";
|
|
11
|
+
import { resolvePromptSelector } from "../lib/block-selector.js";
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a prompt reference — its server id, or the author-chosen key its
|
|
14
|
+
* TOML file is named for.
|
|
15
|
+
*
|
|
16
|
+
* Under TOML-only authoring the key is what an operator has: `prompts/<key>.toml`
|
|
17
|
+
* is the object, and the id is a server detail they never wrote down. Mirrors
|
|
18
|
+
* `resolveScriptId` in `scripts.ts`. The resolution itself lives in
|
|
19
|
+
* `block-selector.ts` (#3249) so the `tests` verbs and `configs get` agree on
|
|
20
|
+
* it — and drain every page of the list, where this used to read one.
|
|
21
|
+
*/
|
|
22
|
+
async function resolvePromptId(client, appId, ref) {
|
|
23
|
+
return (await resolvePromptSelector(client, appId, ref)).blockId;
|
|
24
|
+
}
|
|
9
25
|
export function registerPromptsCommands(program) {
|
|
10
26
|
const prompts = program
|
|
11
27
|
.command("prompts")
|
|
@@ -13,9 +29,19 @@ export function registerPromptsCommands(program) {
|
|
|
13
29
|
.addHelpText("after", `
|
|
14
30
|
Examples:
|
|
15
31
|
$ primitive prompts list
|
|
16
|
-
$ primitive
|
|
32
|
+
$ primitive config create prompt summarizer # scaffold prompts/summarizer.toml
|
|
33
|
+
$ primitive config push --only prompt/summarizer # apply it
|
|
17
34
|
$ primitive prompts execute 01HXY... --vars '{"text":"Hello world"}'
|
|
18
|
-
$ primitive prompts configs
|
|
35
|
+
$ primitive prompts configs list summarizer # what the server runs
|
|
36
|
+
`);
|
|
37
|
+
// Server-side configuration is authored in TOML and applied with `config push`
|
|
38
|
+
// (issue #2645) — this group no longer carries config-setting flags.
|
|
39
|
+
prompts.addHelpText("after", `
|
|
40
|
+
Configuration lives in prompts/<key>.toml:
|
|
41
|
+
$ primitive config fields prompt # the file's keys, types and defaults
|
|
42
|
+
$ primitive config create prompt <key> # scaffold one locally
|
|
43
|
+
$ primitive config set prompt/<key> <path>=<value>
|
|
44
|
+
$ primitive config push --only prompt/<key>
|
|
19
45
|
`);
|
|
20
46
|
// List prompts
|
|
21
47
|
prompts
|
|
@@ -23,14 +49,22 @@ Examples:
|
|
|
23
49
|
.description("List prompts")
|
|
24
50
|
.argument("[app-id]", "App ID (uses current app if not specified)")
|
|
25
51
|
.option("--app <app-id>", "App ID")
|
|
26
|
-
.option("--status <status>", "Filter by status:
|
|
52
|
+
.option("--status <status>", "Filter by status: active, inactive, archived")
|
|
27
53
|
.option("--json", "Output as JSON")
|
|
28
54
|
.action(async (appId, options) => {
|
|
29
55
|
const resolvedAppId = resolveAppId(appId, options);
|
|
30
56
|
const client = new ApiClient();
|
|
31
57
|
try {
|
|
58
|
+
// #2803 — `draft` is gone; refuse it by name rather than returning the
|
|
59
|
+
// empty list a canonical filter would produce. #2887 added `archived`:
|
|
60
|
+
// the delete flow writes one now, so asking for the retired rows is a
|
|
61
|
+
// question with an answer rather than a 400.
|
|
32
62
|
const { items } = await client.listPrompts(resolvedAppId, {
|
|
33
|
-
status: options.status,
|
|
63
|
+
status: parseStatusFilter("prompts", options.status, [
|
|
64
|
+
"active",
|
|
65
|
+
"inactive",
|
|
66
|
+
"archived",
|
|
67
|
+
]),
|
|
34
68
|
});
|
|
35
69
|
if (options.json) {
|
|
36
70
|
json(items);
|
|
@@ -53,209 +87,154 @@ Examples:
|
|
|
53
87
|
process.exit(1);
|
|
54
88
|
}
|
|
55
89
|
});
|
|
56
|
-
//
|
|
90
|
+
// #2645 criterion 9 / #2803 — the operational verbs. They are the only
|
|
91
|
+
// writers of `status`, which is server-owned and no longer a TOML key.
|
|
57
92
|
prompts
|
|
58
|
-
.command("
|
|
59
|
-
.description("
|
|
60
|
-
.argument("
|
|
61
|
-
.option("--app <app-id>", "App ID")
|
|
62
|
-
.option("--key <key>", "Prompt key (unique identifier)")
|
|
63
|
-
.option("--name <name>", "Display name")
|
|
64
|
-
.option("--description <desc>", "Description")
|
|
65
|
-
.option("--provider <provider>", "LLM provider: openrouter, gemini", "openrouter")
|
|
66
|
-
.option("--model <model>", "Model name")
|
|
67
|
-
.option("--system-prompt <prompt>", "System prompt")
|
|
68
|
-
.option("--user-template <template>", "User prompt template")
|
|
69
|
-
.option("--temperature <temp>", "Temperature (0-1)")
|
|
70
|
-
.option("--max-tokens <n>", "Max output tokens")
|
|
71
|
-
.option("--output-format <format>", "Output format: text, json")
|
|
72
|
-
.option("--input-schema <json>", "Input schema as JSON")
|
|
73
|
-
.option("--output-schema <json>", "Output schema as JSON")
|
|
74
|
-
.option("--from-file <path>", "Load prompt from TOML file")
|
|
93
|
+
.command("disable")
|
|
94
|
+
.description("Take prompt out of service now. Operational, not configuration: `status` is server-owned and 'config push' can neither set nor clear it.")
|
|
95
|
+
.argument("<prompt-id>", "Prompt ID")
|
|
96
|
+
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
75
97
|
.option("--json", "Output as JSON")
|
|
76
|
-
.action(async (
|
|
77
|
-
const resolvedAppId = resolveAppId(
|
|
98
|
+
.action(async (id, options) => {
|
|
99
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
78
100
|
const client = new ApiClient();
|
|
79
|
-
let payload;
|
|
80
|
-
if (options.fromFile) {
|
|
81
|
-
try {
|
|
82
|
-
const content = readFileSync(options.fromFile, "utf-8");
|
|
83
|
-
const tomlData = TOML.parse(content);
|
|
84
|
-
const prompt = tomlData.prompt || tomlData;
|
|
85
|
-
const config = tomlData.configs?.[0] || {};
|
|
86
|
-
payload = {
|
|
87
|
-
promptKey: prompt.key || prompt.promptKey,
|
|
88
|
-
displayName: prompt.displayName || prompt.name,
|
|
89
|
-
description: prompt.description,
|
|
90
|
-
provider: config.provider || prompt.provider || "openrouter",
|
|
91
|
-
model: config.model || prompt.model,
|
|
92
|
-
systemPrompt: config.systemPrompt || prompt.systemPrompt,
|
|
93
|
-
userPromptTemplate: config.userPromptTemplate || prompt.userPromptTemplate,
|
|
94
|
-
temperature: config.temperature || prompt.temperature,
|
|
95
|
-
maxTokens: config.maxTokens || prompt.maxTokens,
|
|
96
|
-
outputFormat: config.outputFormat || prompt.outputFormat,
|
|
97
|
-
inputSchema: prompt.inputSchema,
|
|
98
|
-
outputSchema: prompt.outputSchema,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
error(`Failed to read TOML file: ${err.message}`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
if (!options.key || !options.name || !options.model || !options.userTemplate) {
|
|
108
|
-
error("Required: --key, --name, --model, --user-template (or use --from-file)");
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
111
|
-
payload = {
|
|
112
|
-
promptKey: options.key,
|
|
113
|
-
displayName: options.name,
|
|
114
|
-
description: options.description,
|
|
115
|
-
provider: options.provider,
|
|
116
|
-
model: options.model,
|
|
117
|
-
systemPrompt: options.systemPrompt,
|
|
118
|
-
userPromptTemplate: options.userTemplate,
|
|
119
|
-
temperature: options.temperature,
|
|
120
|
-
maxTokens: options.maxTokens ? parseInt(options.maxTokens) : undefined,
|
|
121
|
-
outputFormat: options.outputFormat,
|
|
122
|
-
inputSchema: options.inputSchema,
|
|
123
|
-
outputSchema: options.outputSchema,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
101
|
try {
|
|
127
|
-
const result = await client.
|
|
102
|
+
const result = await client.setPromptAvailability(resolvedAppId, id, "disable");
|
|
128
103
|
if (options.json) {
|
|
129
104
|
json(result);
|
|
130
105
|
return;
|
|
131
106
|
}
|
|
132
|
-
success(`Prompt
|
|
133
|
-
keyValue("Prompt ID", result.promptId);
|
|
134
|
-
keyValue("Key", result.promptKey);
|
|
107
|
+
success(`Prompt disabled: ${result.promptKey || id}`);
|
|
135
108
|
}
|
|
136
109
|
catch (err) {
|
|
137
110
|
error(err.message);
|
|
138
111
|
process.exit(1);
|
|
139
112
|
}
|
|
140
113
|
});
|
|
141
|
-
// Get prompt
|
|
142
114
|
prompts
|
|
143
|
-
.command("
|
|
144
|
-
.description("
|
|
115
|
+
.command("enable")
|
|
116
|
+
.description("Put prompt back in service.")
|
|
145
117
|
.argument("<prompt-id>", "Prompt ID")
|
|
146
118
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
147
119
|
.option("--json", "Output as JSON")
|
|
148
|
-
.action(async (
|
|
120
|
+
.action(async (id, options) => {
|
|
149
121
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
150
122
|
const client = new ApiClient();
|
|
151
123
|
try {
|
|
152
|
-
const result = await client.
|
|
124
|
+
const result = await client.setPromptAvailability(resolvedAppId, id, "enable");
|
|
153
125
|
if (options.json) {
|
|
154
126
|
json(result);
|
|
155
127
|
return;
|
|
156
128
|
}
|
|
157
|
-
|
|
158
|
-
keyValue("Key", result.promptKey);
|
|
159
|
-
keyValue("Name", result.displayName);
|
|
160
|
-
keyValue("Description", result.description);
|
|
161
|
-
keyValue("Status", formatStatus(result.status));
|
|
162
|
-
keyValue("Active Config", result.activeConfigId || "-");
|
|
163
|
-
if (result.configs && result.configs.length > 0) {
|
|
164
|
-
divider();
|
|
165
|
-
info(`Configs (${result.configs.length}):`);
|
|
166
|
-
console.log(formatTable(result.configs, [
|
|
167
|
-
{ header: "ID", key: "configId", format: formatId },
|
|
168
|
-
{ header: "NAME", key: "configName" },
|
|
169
|
-
{ header: "MODEL", key: "model" },
|
|
170
|
-
{ header: "STATUS", key: "status", format: formatStatus },
|
|
171
|
-
]));
|
|
172
|
-
}
|
|
129
|
+
success(`Prompt enabled: ${result.promptKey || id}`);
|
|
173
130
|
}
|
|
174
131
|
catch (err) {
|
|
175
132
|
error(err.message);
|
|
176
133
|
process.exit(1);
|
|
177
134
|
}
|
|
178
135
|
});
|
|
179
|
-
//
|
|
136
|
+
// #2907 — the delete flow's CLI spelling. Not a second writer of `status`:
|
|
137
|
+
// this is the plain `DELETE` #2887 made retire-with-history, which until now
|
|
138
|
+
// only the admin API and the console could reach. Named `archive`, not
|
|
139
|
+
// `delete`, because a configuration noun gets no `delete` verb
|
|
140
|
+
// (docs/cli-design.md) and prune-by-push stays the only CLI hard-delete path.
|
|
180
141
|
prompts
|
|
181
|
-
.command("
|
|
182
|
-
.description("
|
|
142
|
+
.command("archive")
|
|
143
|
+
.description("Retire a prompt (soft delete). Delete-lifecycle, not `disable`: the row and its configs are kept so executions still resolve, it goes on holding its key, and there is no un-archive.")
|
|
183
144
|
.argument("<prompt-id>", "Prompt ID")
|
|
184
145
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
185
|
-
.option("--
|
|
186
|
-
.option("--description <desc>", "Description")
|
|
187
|
-
.option("--status <status>", "Status: draft, active, archived")
|
|
188
|
-
.option("--input-schema <json>", "Input schema as JSON")
|
|
189
|
-
.option("--output-schema <json>", "Output schema as JSON")
|
|
146
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
190
147
|
.option("--json", "Output as JSON")
|
|
191
|
-
.
|
|
148
|
+
.addHelpText("after", `
|
|
149
|
+
What archiving a prompt costs (retire-with-history):
|
|
150
|
+
The member endpoint refuses it, and so does admin execution — the diagnostic
|
|
151
|
+
runs an INACTIVE prompt on purpose, but not an archived one.
|
|
152
|
+
Its configs, executions and analytics keep resolving what they point at.
|
|
153
|
+
The archived row still holds its promptKey.
|
|
154
|
+
\`primitive prompts enable\` refuses an archived prompt; there is no
|
|
155
|
+
un-archive.
|
|
156
|
+
The per-version \`[[configs]] status\` is a different key and is untouched.
|
|
157
|
+
|
|
158
|
+
Reclaiming the key means hard-deleting the row:
|
|
159
|
+
$ rm prompts/<key>.toml
|
|
160
|
+
$ primitive config push --prune # confirmed; hard-deletes the row
|
|
161
|
+
# or hard-delete it in the console, then re-add the file and push.
|
|
162
|
+
`)
|
|
163
|
+
.action(async (id, options) => {
|
|
192
164
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
165
|
+
if (!options.yes) {
|
|
166
|
+
let confirmed;
|
|
167
|
+
try {
|
|
168
|
+
confirmed = await confirmPrompt(`Archive prompt ${id}? It is retired, its configs and executions are ` +
|
|
169
|
+
`kept, it goes on holding its key, and there is no un-archive.`);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
error(err.message);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
if (!confirmed) {
|
|
176
|
+
info("Cancelled.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
207
179
|
}
|
|
208
180
|
const client = new ApiClient();
|
|
209
181
|
try {
|
|
210
|
-
|
|
182
|
+
// The soft delete: no `hard`, so the configs and stored prompt bodies
|
|
183
|
+
// survive and every execution row keeps resolving.
|
|
184
|
+
const result = await client.deletePrompt(resolvedAppId, id);
|
|
211
185
|
if (options.json) {
|
|
212
186
|
json(result);
|
|
213
187
|
return;
|
|
214
188
|
}
|
|
215
|
-
success(
|
|
189
|
+
success(`Prompt archived: ${id}`);
|
|
190
|
+
info("Its configs and executions keep resolving. The row still holds its key — reclaim it by removing its file and running a confirmed `primitive config push --prune`.");
|
|
216
191
|
}
|
|
217
192
|
catch (err) {
|
|
218
193
|
error(err.message);
|
|
219
194
|
process.exit(1);
|
|
220
195
|
}
|
|
221
196
|
});
|
|
222
|
-
// Delete prompt
|
|
223
197
|
prompts
|
|
224
|
-
.command("
|
|
225
|
-
.description("
|
|
198
|
+
.command("get")
|
|
199
|
+
.description("Get prompt details")
|
|
226
200
|
.argument("<prompt-id>", "Prompt ID")
|
|
227
201
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
228
|
-
.option("--
|
|
229
|
-
.option("-y, --yes", "Skip confirmation prompt")
|
|
202
|
+
.option("--json", "Output as JSON")
|
|
230
203
|
.action(async (promptId, options) => {
|
|
231
204
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
232
|
-
if (!options.yes) {
|
|
233
|
-
const action = options.hard ? "permanently delete" : "archive";
|
|
234
|
-
const inquirer = await import("inquirer");
|
|
235
|
-
const { confirm } = await inquirer.default.prompt([
|
|
236
|
-
{
|
|
237
|
-
type: "confirm",
|
|
238
|
-
name: "confirm",
|
|
239
|
-
message: `Are you sure you want to ${action} prompt ${promptId}?`,
|
|
240
|
-
default: false,
|
|
241
|
-
},
|
|
242
|
-
]);
|
|
243
|
-
if (!confirm) {
|
|
244
|
-
info("Cancelled.");
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
205
|
const client = new ApiClient();
|
|
249
206
|
try {
|
|
250
|
-
await client.
|
|
251
|
-
|
|
207
|
+
const result = await client.getPrompt(resolvedAppId, promptId);
|
|
208
|
+
if (options.json) {
|
|
209
|
+
json(result);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
printResult("Prompt ID", result.promptId);
|
|
213
|
+
printResult("Key", result.promptKey);
|
|
214
|
+
printResult("Name", result.displayName);
|
|
215
|
+
printResult("Description", result.description);
|
|
216
|
+
printResult("Status", formatStatus(result.status));
|
|
217
|
+
// #2652: no rule means every non-admin execution is denied. Print that
|
|
218
|
+
// in words — a blank or "-" would read as "unrestricted" and hide a
|
|
219
|
+
// prompt that was never given a rule.
|
|
220
|
+
printResult("Access Rule", formatAccessRuleForDisplay(result.accessRule, "prompt"));
|
|
221
|
+
printResult("Active Config", result.activeConfigId || "-");
|
|
222
|
+
if (result.configs && result.configs.length > 0) {
|
|
223
|
+
divider();
|
|
224
|
+
info(`Configs (${result.configs.length}):`);
|
|
225
|
+
console.log(formatTable(result.configs, [
|
|
226
|
+
{ header: "ID", key: "configId", format: formatId },
|
|
227
|
+
{ header: "NAME", key: "configName" },
|
|
228
|
+
{ header: "MODEL", key: "model" },
|
|
229
|
+
{ header: "STATUS", key: "status", format: formatStatus },
|
|
230
|
+
]));
|
|
231
|
+
}
|
|
252
232
|
}
|
|
253
233
|
catch (err) {
|
|
254
234
|
error(err.message);
|
|
255
235
|
process.exit(1);
|
|
256
236
|
}
|
|
257
237
|
});
|
|
258
|
-
// Execute prompt
|
|
259
238
|
prompts
|
|
260
239
|
.command("execute")
|
|
261
240
|
.description("Execute a prompt with variables")
|
|
@@ -397,8 +376,25 @@ Examples:
|
|
|
397
376
|
process.exit(1);
|
|
398
377
|
}
|
|
399
378
|
});
|
|
400
|
-
// Configs subcommand
|
|
401
|
-
|
|
379
|
+
// Configs subcommand — reads only. A prompt's configs are `[[configs]]`
|
|
380
|
+
// entries in its own TOML file (#2645), so the verbs that used to write them
|
|
381
|
+
// were a second writer for state the file already owns.
|
|
382
|
+
const configs = prompts
|
|
383
|
+
.command("configs")
|
|
384
|
+
.description("Inspect a prompt's configs (authored in prompts/<key>.toml)")
|
|
385
|
+
.addHelpText("after", `
|
|
386
|
+
A prompt's configs are the \`[[configs]]\` entries of prompts/<key>.toml. Add,
|
|
387
|
+
edit, retire (\`status = "archived"\`) or mark one live (\`active = true\`) in that
|
|
388
|
+
file, then apply it:
|
|
389
|
+
|
|
390
|
+
$ primitive config push --only prompt/<key>
|
|
391
|
+
|
|
392
|
+
That per-config \`status\` says which VERSION is retired and is yours to author.
|
|
393
|
+
The PROMPT's own availability is server-owned and has no TOML key: use
|
|
394
|
+
'primitive prompts disable' / 'enable'.
|
|
395
|
+
|
|
396
|
+
Duplicating a config is copying its \`[[configs]]\` block and renaming it.
|
|
397
|
+
`);
|
|
402
398
|
// List configs
|
|
403
399
|
configs
|
|
404
400
|
.command("list")
|
|
@@ -432,154 +428,51 @@ Examples:
|
|
|
432
428
|
process.exit(1);
|
|
433
429
|
}
|
|
434
430
|
});
|
|
435
|
-
//
|
|
431
|
+
// Get one config. `list` says which configs exist; this says what one of
|
|
432
|
+
// them actually runs — the body, provider and model the server would use.
|
|
433
|
+
// With `prompts configs create/update` gone, this is where that content is
|
|
434
|
+
// read back from.
|
|
436
435
|
configs
|
|
437
|
-
.command("
|
|
438
|
-
.description("
|
|
439
|
-
.argument("<prompt
|
|
436
|
+
.command("get")
|
|
437
|
+
.description("Show one config of a prompt as the server has it")
|
|
438
|
+
.argument("<prompt>", "Prompt ID or key")
|
|
439
|
+
.argument("<config>", "Config ID or name")
|
|
440
440
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
441
|
-
.option("--name <name>", "Config name")
|
|
442
|
-
.option("--description <desc>", "Description")
|
|
443
|
-
.option("--provider <provider>", "LLM provider: openrouter, gemini", "openrouter")
|
|
444
|
-
.option("--model <model>", "Model name")
|
|
445
|
-
.option("--system-prompt <prompt>", "System prompt")
|
|
446
|
-
.option("--user-template <template>", "User prompt template")
|
|
447
|
-
.option("--temperature <temp>", "Temperature (0-1)")
|
|
448
|
-
.option("--max-tokens <n>", "Max output tokens")
|
|
449
|
-
.option("--output-format <format>", "Output format: text, json")
|
|
450
441
|
.option("--json", "Output as JSON")
|
|
451
|
-
.action(async (
|
|
442
|
+
.action(async (prompt, config, options) => {
|
|
452
443
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
453
|
-
if (!options.name || !options.model || !options.userTemplate) {
|
|
454
|
-
error("Required: --name, --model, --user-template");
|
|
455
|
-
process.exit(1);
|
|
456
|
-
}
|
|
457
|
-
const payload = {
|
|
458
|
-
configName: options.name,
|
|
459
|
-
description: options.description,
|
|
460
|
-
provider: options.provider,
|
|
461
|
-
model: options.model,
|
|
462
|
-
systemPrompt: options.systemPrompt,
|
|
463
|
-
userPromptTemplate: options.userTemplate,
|
|
464
|
-
temperature: options.temperature,
|
|
465
|
-
maxTokens: options.maxTokens ? parseInt(options.maxTokens) : undefined,
|
|
466
|
-
outputFormat: options.outputFormat,
|
|
467
|
-
};
|
|
468
444
|
const client = new ApiClient();
|
|
469
445
|
try {
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
446
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
447
|
+
const { items } = await client.listPromptConfigs(resolvedAppId, promptId);
|
|
448
|
+
const summary = (items ?? []).find((c) => c.configId === config || c.configName === config);
|
|
449
|
+
if (!summary) {
|
|
450
|
+
error(`Prompt '${prompt}' has no config '${config}'. Run 'primitive prompts configs list ${prompt}' to see them.`);
|
|
451
|
+
process.exit(1);
|
|
474
452
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
catch (err) {
|
|
479
|
-
error(err.message);
|
|
480
|
-
process.exit(1);
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
// Activate config
|
|
484
|
-
configs
|
|
485
|
-
.command("activate")
|
|
486
|
-
.description("Set a config as the active config for a prompt")
|
|
487
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
488
|
-
.argument("<config-id>", "Config ID")
|
|
489
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
490
|
-
.action(async (promptId, configId, options) => {
|
|
491
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
492
|
-
const client = new ApiClient();
|
|
493
|
-
try {
|
|
494
|
-
await client.activatePromptConfig(resolvedAppId, promptId, configId);
|
|
495
|
-
success(`Config ${configId} activated.`);
|
|
496
|
-
}
|
|
497
|
-
catch (err) {
|
|
498
|
-
error(err.message);
|
|
499
|
-
process.exit(1);
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
// Duplicate config
|
|
503
|
-
configs
|
|
504
|
-
.command("duplicate")
|
|
505
|
-
.description("Duplicate a config")
|
|
506
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
507
|
-
.argument("<config-id>", "Config ID to duplicate")
|
|
508
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
509
|
-
.option("--name <name>", "New config name")
|
|
510
|
-
.option("--json", "Output as JSON")
|
|
511
|
-
.action(async (promptId, configId, options) => {
|
|
512
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
513
|
-
const client = new ApiClient();
|
|
514
|
-
try {
|
|
515
|
-
const result = await client.duplicatePromptConfig(resolvedAppId, promptId, configId, {
|
|
516
|
-
configName: options.name,
|
|
517
|
-
});
|
|
453
|
+
const full = (await client.getPromptConfig(resolvedAppId, promptId, summary.configId)) ??
|
|
454
|
+
summary;
|
|
518
455
|
if (options.json) {
|
|
519
|
-
json(
|
|
456
|
+
json(full);
|
|
520
457
|
return;
|
|
521
458
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
.option("--description <desc>", "Description")
|
|
539
|
-
.option("--provider <provider>", "LLM provider: openrouter, gemini")
|
|
540
|
-
.option("--model <model>", "Model name")
|
|
541
|
-
.option("--system-prompt <prompt>", "System prompt")
|
|
542
|
-
.option("--user-template <template>", "User prompt template")
|
|
543
|
-
.option("--temperature <temp>", "Temperature (0-1)")
|
|
544
|
-
.option("--max-tokens <n>", "Max output tokens")
|
|
545
|
-
.option("--output-format <format>", "Output format: text, json")
|
|
546
|
-
.option("--status <status>", "Status: active, archived")
|
|
547
|
-
.option("--json", "Output as JSON")
|
|
548
|
-
.action(async (promptId, configId, options) => {
|
|
549
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
550
|
-
const payload = {};
|
|
551
|
-
if (options.name)
|
|
552
|
-
payload.configName = options.name;
|
|
553
|
-
if (options.description)
|
|
554
|
-
payload.description = options.description;
|
|
555
|
-
if (options.provider)
|
|
556
|
-
payload.provider = options.provider;
|
|
557
|
-
if (options.model)
|
|
558
|
-
payload.model = options.model;
|
|
559
|
-
if (options.systemPrompt)
|
|
560
|
-
payload.systemPrompt = options.systemPrompt;
|
|
561
|
-
if (options.userTemplate)
|
|
562
|
-
payload.userPromptTemplate = options.userTemplate;
|
|
563
|
-
if (options.temperature)
|
|
564
|
-
payload.temperature = options.temperature;
|
|
565
|
-
if (options.maxTokens)
|
|
566
|
-
payload.maxTokens = parseInt(options.maxTokens);
|
|
567
|
-
if (options.outputFormat)
|
|
568
|
-
payload.outputFormat = options.outputFormat;
|
|
569
|
-
if (options.status)
|
|
570
|
-
payload.status = options.status;
|
|
571
|
-
if (Object.keys(payload).length === 0) {
|
|
572
|
-
error("No update options specified.");
|
|
573
|
-
process.exit(1);
|
|
574
|
-
}
|
|
575
|
-
const client = new ApiClient();
|
|
576
|
-
try {
|
|
577
|
-
const result = await client.updatePromptConfig(resolvedAppId, promptId, configId, payload);
|
|
578
|
-
if (options.json) {
|
|
579
|
-
json(result);
|
|
580
|
-
return;
|
|
459
|
+
printResult("Config ID", full.configId);
|
|
460
|
+
printResult("Name", full.configName);
|
|
461
|
+
printResult("Status", formatStatus(full.status));
|
|
462
|
+
printResult("Provider", full.provider || "-");
|
|
463
|
+
printResult("Model", full.model || "-");
|
|
464
|
+
if (full.description)
|
|
465
|
+
printResult("Description", full.description);
|
|
466
|
+
if (full.systemPrompt) {
|
|
467
|
+
divider();
|
|
468
|
+
info("System prompt:");
|
|
469
|
+
console.log(full.systemPrompt);
|
|
470
|
+
}
|
|
471
|
+
if (full.userPrompt) {
|
|
472
|
+
divider();
|
|
473
|
+
info("User prompt:");
|
|
474
|
+
console.log(full.userPrompt);
|
|
581
475
|
}
|
|
582
|
-
success("Config updated.");
|
|
583
476
|
}
|
|
584
477
|
catch (err) {
|
|
585
478
|
error(err.message);
|
|
@@ -591,26 +484,37 @@ Examples:
|
|
|
591
484
|
// ============================================
|
|
592
485
|
const tests = prompts
|
|
593
486
|
.command("tests")
|
|
594
|
-
.description("
|
|
487
|
+
.description("Run and inspect prompt test cases")
|
|
595
488
|
.addHelpText("after", `
|
|
489
|
+
Test cases are authored in TOML at prompts/<key>.tests/<name>.toml and applied
|
|
490
|
+
with \`primitive config push\` (issue #2769); \`config fields prompt\` lists the
|
|
491
|
+
fields. Deleting a case is removing its file and running \`config push --prune\`.
|
|
492
|
+
|
|
493
|
+
Every verb here takes the prompt's KEY or its ID (#3249). An identifier that
|
|
494
|
+
names no prompt in the app fails; "No test cases found." only ever means the
|
|
495
|
+
prompt exists and has no cases.
|
|
496
|
+
|
|
596
497
|
Examples:
|
|
597
|
-
$ primitive prompts tests list <prompt
|
|
598
|
-
$ primitive prompts tests
|
|
599
|
-
$ primitive prompts tests run <prompt
|
|
600
|
-
$ primitive prompts tests run-all <prompt-
|
|
601
|
-
$ primitive prompts tests run-all <prompt-id> --test-cases 01ABC,01DEF,01GHI
|
|
498
|
+
$ primitive prompts tests list <prompt>
|
|
499
|
+
$ primitive prompts tests run <prompt> <test-case-id>
|
|
500
|
+
$ primitive prompts tests run-all <prompt>
|
|
501
|
+
$ primitive prompts tests run-all <prompt> --test-cases 01ABC,01DEF,01GHI
|
|
602
502
|
`);
|
|
603
503
|
// List test cases
|
|
604
504
|
tests
|
|
605
505
|
.command("list")
|
|
606
506
|
.description("List test cases for a prompt")
|
|
607
|
-
.argument("<prompt
|
|
507
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
608
508
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
609
509
|
.option("--json", "Output as JSON")
|
|
610
|
-
.action(async (
|
|
510
|
+
.action(async (prompt, options) => {
|
|
611
511
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
612
512
|
const client = new ApiClient();
|
|
613
513
|
try {
|
|
514
|
+
// #3249 — resolve BEFORE listing: the test-case endpoint answers an
|
|
515
|
+
// unknown block with an empty page, so an unresolved identifier would
|
|
516
|
+
// print "No test cases found." and exit 0.
|
|
517
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
614
518
|
const { items } = await client.listTestCases(resolvedAppId, "prompt", promptId);
|
|
615
519
|
if (options.json) {
|
|
616
520
|
json(items);
|
|
@@ -632,100 +536,28 @@ Examples:
|
|
|
632
536
|
process.exit(1);
|
|
633
537
|
}
|
|
634
538
|
});
|
|
635
|
-
// Create test case
|
|
636
|
-
tests
|
|
637
|
-
.command("create")
|
|
638
|
-
.description("Create a test case for a prompt")
|
|
639
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
640
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
641
|
-
.option("--name <name>", "Test case name (required)")
|
|
642
|
-
.option("--vars <json>", "Input variables as JSON (required)")
|
|
643
|
-
.option("--pattern <regex>", "Expected output pattern (regex)")
|
|
644
|
-
.option("--contains <json>", "Expected strings to contain (JSON array)")
|
|
645
|
-
.option("--json-subset <json>", "Expected JSON subset to match")
|
|
646
|
-
.option("--config <config-id>", "Config ID to use for this test")
|
|
647
|
-
.option("--evaluator-prompt <prompt-id>", "Evaluator prompt ID")
|
|
648
|
-
.option("--evaluator-config <config-id>", "Evaluator config ID")
|
|
649
|
-
.option("--json", "Output as JSON")
|
|
650
|
-
.action(async (promptId, options) => {
|
|
651
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
652
|
-
if (!options.name || !options.vars) {
|
|
653
|
-
error("Required: --name and --vars");
|
|
654
|
-
process.exit(1);
|
|
655
|
-
}
|
|
656
|
-
let inputVariables;
|
|
657
|
-
try {
|
|
658
|
-
inputVariables = JSON.parse(options.vars);
|
|
659
|
-
}
|
|
660
|
-
catch {
|
|
661
|
-
error("Invalid JSON in --vars");
|
|
662
|
-
process.exit(1);
|
|
663
|
-
}
|
|
664
|
-
let expectedOutputContains;
|
|
665
|
-
if (options.contains) {
|
|
666
|
-
try {
|
|
667
|
-
expectedOutputContains = JSON.parse(options.contains);
|
|
668
|
-
}
|
|
669
|
-
catch {
|
|
670
|
-
error("Invalid JSON in --contains");
|
|
671
|
-
process.exit(1);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
let expectedJsonSubset;
|
|
675
|
-
if (options.jsonSubset) {
|
|
676
|
-
try {
|
|
677
|
-
expectedJsonSubset = JSON.parse(options.jsonSubset);
|
|
678
|
-
}
|
|
679
|
-
catch {
|
|
680
|
-
error("Invalid JSON in --json-subset");
|
|
681
|
-
process.exit(1);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
const client = new ApiClient();
|
|
685
|
-
try {
|
|
686
|
-
const result = await client.createTestCase(resolvedAppId, "prompt", promptId, {
|
|
687
|
-
name: options.name,
|
|
688
|
-
inputVariables,
|
|
689
|
-
expectedOutputPattern: options.pattern,
|
|
690
|
-
expectedOutputContains,
|
|
691
|
-
expectedJsonSubset,
|
|
692
|
-
configId: options.config,
|
|
693
|
-
evaluatorPromptId: options.evaluatorPrompt,
|
|
694
|
-
evaluatorConfigId: options.evaluatorConfig,
|
|
695
|
-
});
|
|
696
|
-
if (options.json) {
|
|
697
|
-
json(result);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
success(`Test case created: ${result.name}`);
|
|
701
|
-
keyValue("Test Case ID", result.testCaseId);
|
|
702
|
-
}
|
|
703
|
-
catch (err) {
|
|
704
|
-
error(err.message);
|
|
705
|
-
process.exit(1);
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
539
|
// Get test case
|
|
709
540
|
tests
|
|
710
541
|
.command("get")
|
|
711
542
|
.description("Get test case details")
|
|
712
|
-
.argument("<prompt
|
|
543
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
713
544
|
.argument("<test-case-id>", "Test Case ID")
|
|
714
545
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
715
546
|
.option("--json", "Output as JSON")
|
|
716
|
-
.action(async (
|
|
547
|
+
.action(async (prompt, testCaseId, options) => {
|
|
717
548
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
718
549
|
const client = new ApiClient();
|
|
719
550
|
try {
|
|
551
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
720
552
|
const result = await client.getTestCase(resolvedAppId, "prompt", promptId, testCaseId);
|
|
721
553
|
if (options.json) {
|
|
722
554
|
json(result);
|
|
723
555
|
return;
|
|
724
556
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
557
|
+
printResult("Test Case ID", result.testCaseId);
|
|
558
|
+
printResult("Name", result.name);
|
|
559
|
+
printResult("Config ID", result.configId || "-");
|
|
560
|
+
printResult("Created", formatDate(result.createdAt));
|
|
729
561
|
divider();
|
|
730
562
|
info("Input Variables:");
|
|
731
563
|
try {
|
|
@@ -737,7 +569,7 @@ Examples:
|
|
|
737
569
|
}
|
|
738
570
|
if (result.expectedOutputPattern) {
|
|
739
571
|
divider();
|
|
740
|
-
|
|
572
|
+
printResult("Expected Pattern", result.expectedOutputPattern);
|
|
741
573
|
}
|
|
742
574
|
if (result.expectedOutputContains) {
|
|
743
575
|
divider();
|
|
@@ -761,8 +593,8 @@ Examples:
|
|
|
761
593
|
}
|
|
762
594
|
if (result.evaluatorPromptId) {
|
|
763
595
|
divider();
|
|
764
|
-
|
|
765
|
-
|
|
596
|
+
printResult("Evaluator Prompt", result.evaluatorPromptId);
|
|
597
|
+
printResult("Evaluator Config", result.evaluatorConfigId || "-");
|
|
766
598
|
}
|
|
767
599
|
}
|
|
768
600
|
catch (err) {
|
|
@@ -770,144 +602,26 @@ Examples:
|
|
|
770
602
|
process.exit(1);
|
|
771
603
|
}
|
|
772
604
|
});
|
|
773
|
-
// Update test case
|
|
774
|
-
tests
|
|
775
|
-
.command("update")
|
|
776
|
-
.description("Update a test case")
|
|
777
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
778
|
-
.argument("<test-case-id>", "Test Case ID")
|
|
779
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
780
|
-
.option("--name <name>", "Test case name")
|
|
781
|
-
.option("--vars <json>", "Input variables as JSON")
|
|
782
|
-
.option("--pattern <regex>", "Expected output pattern (regex)")
|
|
783
|
-
.option("--contains <json>", "Expected strings to contain (JSON array)")
|
|
784
|
-
.option("--json-subset <json>", "Expected JSON subset to match")
|
|
785
|
-
.option("--config <config-id>", "Config ID to use for this test")
|
|
786
|
-
.option("--clear-pattern", "Clear expected pattern")
|
|
787
|
-
.option("--clear-contains", "Clear expected contains")
|
|
788
|
-
.option("--clear-json-subset", "Clear expected JSON subset")
|
|
789
|
-
.option("--json", "Output as JSON")
|
|
790
|
-
.action(async (promptId, testCaseId, options) => {
|
|
791
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
792
|
-
const payload = {};
|
|
793
|
-
if (options.name)
|
|
794
|
-
payload.name = options.name;
|
|
795
|
-
if (options.vars) {
|
|
796
|
-
try {
|
|
797
|
-
payload.inputVariables = JSON.parse(options.vars);
|
|
798
|
-
}
|
|
799
|
-
catch {
|
|
800
|
-
error("Invalid JSON in --vars");
|
|
801
|
-
process.exit(1);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
if (options.clearPattern) {
|
|
805
|
-
payload.expectedOutputPattern = null;
|
|
806
|
-
}
|
|
807
|
-
else if (options.pattern) {
|
|
808
|
-
payload.expectedOutputPattern = options.pattern;
|
|
809
|
-
}
|
|
810
|
-
if (options.clearContains) {
|
|
811
|
-
payload.expectedOutputContains = null;
|
|
812
|
-
}
|
|
813
|
-
else if (options.contains) {
|
|
814
|
-
try {
|
|
815
|
-
payload.expectedOutputContains = JSON.parse(options.contains);
|
|
816
|
-
}
|
|
817
|
-
catch {
|
|
818
|
-
error("Invalid JSON in --contains");
|
|
819
|
-
process.exit(1);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
if (options.clearJsonSubset) {
|
|
823
|
-
payload.expectedJsonSubset = null;
|
|
824
|
-
}
|
|
825
|
-
else if (options.jsonSubset) {
|
|
826
|
-
try {
|
|
827
|
-
payload.expectedJsonSubset = JSON.parse(options.jsonSubset);
|
|
828
|
-
}
|
|
829
|
-
catch {
|
|
830
|
-
error("Invalid JSON in --json-subset");
|
|
831
|
-
process.exit(1);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
if (options.config)
|
|
835
|
-
payload.configId = options.config;
|
|
836
|
-
if (Object.keys(payload).length === 0) {
|
|
837
|
-
error("No update options specified.");
|
|
838
|
-
process.exit(1);
|
|
839
|
-
}
|
|
840
|
-
const client = new ApiClient();
|
|
841
|
-
try {
|
|
842
|
-
const result = await client.updateTestCase(resolvedAppId, "prompt", promptId, testCaseId, payload);
|
|
843
|
-
if (options.json) {
|
|
844
|
-
json(result);
|
|
845
|
-
return;
|
|
846
|
-
}
|
|
847
|
-
success("Test case updated.");
|
|
848
|
-
}
|
|
849
|
-
catch (err) {
|
|
850
|
-
error(err.message);
|
|
851
|
-
process.exit(1);
|
|
852
|
-
}
|
|
853
|
-
});
|
|
854
|
-
// Delete test case
|
|
855
|
-
tests
|
|
856
|
-
.command("delete")
|
|
857
|
-
.description("Delete a test case")
|
|
858
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
859
|
-
.argument("<test-case-id>", "Test Case ID")
|
|
860
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
861
|
-
.option("-y, --yes", "Skip confirmation prompt")
|
|
862
|
-
.action(async (promptId, testCaseId, options) => {
|
|
863
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
864
|
-
if (!options.yes) {
|
|
865
|
-
const inquirer = await import("inquirer");
|
|
866
|
-
const { confirm } = await inquirer.default.prompt([
|
|
867
|
-
{
|
|
868
|
-
type: "confirm",
|
|
869
|
-
name: "confirm",
|
|
870
|
-
message: `Are you sure you want to delete test case ${testCaseId}?`,
|
|
871
|
-
default: false,
|
|
872
|
-
},
|
|
873
|
-
]);
|
|
874
|
-
if (!confirm) {
|
|
875
|
-
info("Cancelled.");
|
|
876
|
-
return;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
const client = new ApiClient();
|
|
880
|
-
try {
|
|
881
|
-
await client.deleteTestCase(resolvedAppId, "prompt", promptId, testCaseId);
|
|
882
|
-
success("Test case deleted.");
|
|
883
|
-
}
|
|
884
|
-
catch (err) {
|
|
885
|
-
error(err.message);
|
|
886
|
-
process.exit(1);
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
605
|
// Run a single test case
|
|
890
606
|
tests
|
|
891
607
|
.command("run")
|
|
892
608
|
.description("Run a single test case")
|
|
893
|
-
.argument("<prompt
|
|
609
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
894
610
|
.argument("<test-case-id>", "Test Case ID")
|
|
895
611
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
896
612
|
.option("--config <config-id>", "Override config ID")
|
|
897
613
|
.option("--json", "Output as JSON")
|
|
898
|
-
.action(async (
|
|
614
|
+
.action(async (prompt, testCaseId, options) => {
|
|
899
615
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
900
616
|
const client = new ApiClient();
|
|
901
617
|
try {
|
|
618
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
902
619
|
// Get test case to retrieve its variables
|
|
903
620
|
const testCase = await client.getTestCase(resolvedAppId, "prompt", promptId, testCaseId);
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
catch {
|
|
909
|
-
// Use empty object if parsing fails
|
|
910
|
-
}
|
|
621
|
+
// #3158 — the case's stored input IS the run's input, and the server
|
|
622
|
+
// hands it back parsed; `JSON.parse` on that object threw and the run
|
|
623
|
+
// went ahead with `{}`, disagreeing with `run-all` over the same case.
|
|
624
|
+
const variables = requireTestCaseInputVariables(testCase.inputVariables, testCaseId);
|
|
911
625
|
const result = await client.executeBlockTest(resolvedAppId, "prompt", promptId, {
|
|
912
626
|
variables,
|
|
913
627
|
testCaseId,
|
|
@@ -962,15 +676,18 @@ Examples:
|
|
|
962
676
|
tests
|
|
963
677
|
.command("run-all")
|
|
964
678
|
.description("Run all test cases for a prompt, or a specific subset")
|
|
965
|
-
.argument("<prompt
|
|
679
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
966
680
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
967
681
|
.option("--config <config-id>", "Override config ID for all tests")
|
|
968
682
|
.option("--test-cases <ids>", "Comma-separated list of test case IDs to run (runs only these)")
|
|
969
683
|
.option("--json", "Output as JSON")
|
|
970
|
-
.action(async (
|
|
684
|
+
.action(async (prompt, options) => {
|
|
971
685
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
972
686
|
const client = new ApiClient();
|
|
973
687
|
try {
|
|
688
|
+
// #3249 — resolve first, so `Total Tests: 0` can only ever mean the
|
|
689
|
+
// prompt exists and has no cases, never that the identifier was wrong.
|
|
690
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
974
691
|
// Parse test case IDs if provided
|
|
975
692
|
let testCaseIds;
|
|
976
693
|
if (options.testCases) {
|
|
@@ -1028,15 +745,16 @@ Examples:
|
|
|
1028
745
|
tests
|
|
1029
746
|
.command("runs")
|
|
1030
747
|
.description("List recent test runs for a prompt")
|
|
1031
|
-
.argument("<prompt
|
|
748
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1032
749
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1033
750
|
.option("--limit <n>", "Maximum number of runs to show", "20")
|
|
1034
751
|
.option("--group <group>", "Filter by comparison group")
|
|
1035
752
|
.option("--json", "Output as JSON")
|
|
1036
|
-
.action(async (
|
|
753
|
+
.action(async (prompt, options) => {
|
|
1037
754
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1038
755
|
const client = new ApiClient();
|
|
1039
756
|
try {
|
|
757
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1040
758
|
const { items } = await client.listTestRuns(resolvedAppId, "prompt", promptId, {
|
|
1041
759
|
limit: parseInt(options.limit),
|
|
1042
760
|
comparisonGroup: options.group,
|
|
@@ -1078,24 +796,25 @@ Examples:
|
|
|
1078
796
|
.description("Run tests in parallel using workflow-based execution")
|
|
1079
797
|
.addHelpText("after", `
|
|
1080
798
|
Examples:
|
|
1081
|
-
$ primitive prompts tests batch start <prompt
|
|
1082
|
-
$ primitive prompts tests batch start <prompt
|
|
1083
|
-
$ primitive prompts tests batch status <prompt
|
|
1084
|
-
$ primitive prompts tests batch cancel <prompt
|
|
799
|
+
$ primitive prompts tests batch start <prompt>
|
|
800
|
+
$ primitive prompts tests batch start <prompt> --test-cases 01ABC,01DEF
|
|
801
|
+
$ primitive prompts tests batch status <prompt> <batch-id>
|
|
802
|
+
$ primitive prompts tests batch cancel <prompt> <batch-id>
|
|
1085
803
|
`);
|
|
1086
804
|
// Start batch tests
|
|
1087
805
|
batch
|
|
1088
806
|
.command("start")
|
|
1089
807
|
.description("Start parallel batch test execution")
|
|
1090
|
-
.argument("<prompt
|
|
808
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1091
809
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1092
810
|
.option("--config <config-id>", "Override config ID for all tests")
|
|
1093
811
|
.option("--test-cases <ids>", "Comma-separated list of test case IDs to run")
|
|
1094
812
|
.option("--json", "Output as JSON")
|
|
1095
|
-
.action(async (
|
|
813
|
+
.action(async (prompt, options) => {
|
|
1096
814
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1097
815
|
const client = new ApiClient();
|
|
1098
816
|
try {
|
|
817
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1099
818
|
let testCaseIds;
|
|
1100
819
|
if (options.testCases) {
|
|
1101
820
|
testCaseIds = options.testCases.split(",").map((id) => id.trim()).filter(Boolean);
|
|
@@ -1132,27 +851,37 @@ Examples:
|
|
|
1132
851
|
batch
|
|
1133
852
|
.command("status")
|
|
1134
853
|
.description("Get status of a batch test execution")
|
|
1135
|
-
.argument("<prompt
|
|
854
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1136
855
|
.argument("<batch-id>", "Batch ID")
|
|
1137
856
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1138
857
|
.option("--wait", "Wait for completion (polls every 2 seconds)")
|
|
1139
858
|
.option("--json", "Output as JSON")
|
|
1140
|
-
.action(async (
|
|
859
|
+
.action(async (prompt, batchId, options) => {
|
|
1141
860
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1142
861
|
const client = new ApiClient();
|
|
1143
862
|
try {
|
|
863
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1144
864
|
const fetchStatus = async () => {
|
|
1145
865
|
return client.getBatchTestStatus(resolvedAppId, "prompt", promptId, batchId);
|
|
1146
866
|
};
|
|
1147
867
|
let result = await fetchStatus();
|
|
1148
868
|
if (options.wait && result.status === "running") {
|
|
1149
869
|
info("Waiting for batch completion...");
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
870
|
+
// #1969 — shared poll primitive (delay-then-probe every 2s, honoring
|
|
871
|
+
// an AbortSignal). `onError: "throw"` preserves the prior loop's
|
|
872
|
+
// fail-fast behavior: a throwing fetchStatus (expired token, deleted
|
|
873
|
+
// batch → 401/404) propagates to the command-level catch below and
|
|
874
|
+
// exits non-zero, rather than spinning forever with a frozen progress
|
|
875
|
+
// line. (The follow/watch tail loops legitimately keep "continue".)
|
|
876
|
+
const controller = new AbortController();
|
|
877
|
+
result = await pollUntil(fetchStatus, (r) => r.status !== "running", {
|
|
878
|
+
intervalMs: 2000,
|
|
879
|
+
signal: controller.signal,
|
|
880
|
+
onError: "throw",
|
|
881
|
+
// Progress goes to stderr so it can't corrupt JSON on stdout under --json.
|
|
882
|
+
onValue: (r) => progress(` Completed: ${r.completed}/${r.results?.length || 0} `),
|
|
883
|
+
});
|
|
884
|
+
progressEnd();
|
|
1156
885
|
}
|
|
1157
886
|
if (options.json) {
|
|
1158
887
|
json(result);
|
|
@@ -1188,23 +917,22 @@ Examples:
|
|
|
1188
917
|
batch
|
|
1189
918
|
.command("cancel")
|
|
1190
919
|
.description("Cancel a running batch test execution")
|
|
1191
|
-
.argument("<prompt
|
|
920
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1192
921
|
.argument("<batch-id>", "Batch ID")
|
|
1193
922
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1194
923
|
.option("-y, --yes", "Skip confirmation prompt")
|
|
1195
924
|
.option("--json", "Output as JSON")
|
|
1196
|
-
.action(async (
|
|
925
|
+
.action(async (prompt, batchId, options) => {
|
|
1197
926
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1198
927
|
if (!options.yes) {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
{
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
]);
|
|
928
|
+
let confirm;
|
|
929
|
+
try {
|
|
930
|
+
confirm = await confirmPrompt(`Are you sure you want to cancel batch ${batchId}?`);
|
|
931
|
+
}
|
|
932
|
+
catch (err) {
|
|
933
|
+
error(err.message);
|
|
934
|
+
process.exit(1);
|
|
935
|
+
}
|
|
1208
936
|
if (!confirm) {
|
|
1209
937
|
info("Cancelled.");
|
|
1210
938
|
return;
|
|
@@ -1212,6 +940,7 @@ Examples:
|
|
|
1212
940
|
}
|
|
1213
941
|
const client = new ApiClient();
|
|
1214
942
|
try {
|
|
943
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1215
944
|
// First get current status to get instance IDs
|
|
1216
945
|
const status = await client.getBatchTestStatus(resolvedAppId, "prompt", promptId, batchId);
|
|
1217
946
|
// Get instance IDs that are still running
|
|
@@ -1244,26 +973,29 @@ Examples:
|
|
|
1244
973
|
// ============================================
|
|
1245
974
|
const attachments = tests
|
|
1246
975
|
.command("attachments")
|
|
1247
|
-
.description("
|
|
976
|
+
.description("Inspect test case file attachments")
|
|
1248
977
|
.addHelpText("after", `
|
|
978
|
+
Attachments are authored as files in prompts/<key>.tests/<name>/ and applied
|
|
979
|
+
with \`primitive config push\` (#2769); removing one and running
|
|
980
|
+
\`config push --prune\` deletes it server-side. These verbs read server state.
|
|
981
|
+
|
|
1249
982
|
Examples:
|
|
1250
|
-
$ primitive prompts tests attachments list <prompt
|
|
1251
|
-
$ primitive prompts tests attachments
|
|
1252
|
-
$ primitive prompts tests attachments download <prompt-id> <test-case-id> document.pdf
|
|
1253
|
-
$ primitive prompts tests attachments delete <prompt-id> <test-case-id> document.pdf
|
|
983
|
+
$ primitive prompts tests attachments list <prompt> <test-case-id>
|
|
984
|
+
$ primitive prompts tests attachments download <prompt> <test-case-id> document.pdf
|
|
1254
985
|
`);
|
|
1255
986
|
// List attachments
|
|
1256
987
|
attachments
|
|
1257
988
|
.command("list")
|
|
1258
989
|
.description("List attachments for a test case")
|
|
1259
|
-
.argument("<prompt
|
|
990
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1260
991
|
.argument("<test-case-id>", "Test Case ID")
|
|
1261
992
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1262
993
|
.option("--json", "Output as JSON")
|
|
1263
|
-
.action(async (
|
|
994
|
+
.action(async (prompt, testCaseId, options) => {
|
|
1264
995
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1265
996
|
const client = new ApiClient();
|
|
1266
997
|
try {
|
|
998
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1267
999
|
const result = await client.listTestCaseAttachments(resolvedAppId, "prompt", promptId, testCaseId);
|
|
1268
1000
|
if (options.json) {
|
|
1269
1001
|
json(result.attachments);
|
|
@@ -1288,62 +1020,20 @@ Examples:
|
|
|
1288
1020
|
process.exit(1);
|
|
1289
1021
|
}
|
|
1290
1022
|
});
|
|
1291
|
-
// Upload attachment
|
|
1292
|
-
attachments
|
|
1293
|
-
.command("upload")
|
|
1294
|
-
.description("Upload a file attachment to a test case")
|
|
1295
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
1296
|
-
.argument("<test-case-id>", "Test Case ID")
|
|
1297
|
-
.argument("<file-path>", "Path to the file to upload")
|
|
1298
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1299
|
-
.option("--name <name>", "Override the filename")
|
|
1300
|
-
.option("--json", "Output as JSON")
|
|
1301
|
-
.action(async (promptId, testCaseId, filePath, options) => {
|
|
1302
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
1303
|
-
const client = new ApiClient();
|
|
1304
|
-
try {
|
|
1305
|
-
// Check file exists and get stats
|
|
1306
|
-
const stats = statSync(filePath);
|
|
1307
|
-
if (!stats.isFile()) {
|
|
1308
|
-
error(`Not a file: ${filePath}`);
|
|
1309
|
-
process.exit(1);
|
|
1310
|
-
}
|
|
1311
|
-
// Check file size (10 MB limit)
|
|
1312
|
-
const TEN_MB = 10 * 1024 * 1024;
|
|
1313
|
-
if (stats.size > TEN_MB) {
|
|
1314
|
-
error(`File too large (max 10MB): ${formatFileSize(stats.size)}`);
|
|
1315
|
-
process.exit(1);
|
|
1316
|
-
}
|
|
1317
|
-
const filename = options.name || basename(filePath);
|
|
1318
|
-
const data = readFileSync(filePath);
|
|
1319
|
-
const contentType = mimeLookup(filePath) || "application/octet-stream";
|
|
1320
|
-
const result = await client.uploadTestCaseAttachment(resolvedAppId, "prompt", promptId, testCaseId, filename, data, contentType);
|
|
1321
|
-
if (options.json) {
|
|
1322
|
-
json(result);
|
|
1323
|
-
return;
|
|
1324
|
-
}
|
|
1325
|
-
success(`Uploaded: ${filename}`);
|
|
1326
|
-
keyValue("Size", formatFileSize(result.attachment.size));
|
|
1327
|
-
keyValue("Type", result.attachment.contentType);
|
|
1328
|
-
}
|
|
1329
|
-
catch (err) {
|
|
1330
|
-
error(err.message);
|
|
1331
|
-
process.exit(1);
|
|
1332
|
-
}
|
|
1333
|
-
});
|
|
1334
1023
|
// Download attachment
|
|
1335
1024
|
attachments
|
|
1336
1025
|
.command("download")
|
|
1337
1026
|
.description("Download a file attachment from a test case")
|
|
1338
|
-
.argument("<prompt
|
|
1027
|
+
.argument("<prompt>", "Prompt key or ID")
|
|
1339
1028
|
.argument("<test-case-id>", "Test Case ID")
|
|
1340
1029
|
.argument("<filename>", "Name of the file to download")
|
|
1341
1030
|
.argument("[output-path]", "Output path (defaults to current directory)")
|
|
1342
1031
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1343
|
-
.action(async (
|
|
1032
|
+
.action(async (prompt, testCaseId, filename, outputPath, options) => {
|
|
1344
1033
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1345
1034
|
const client = new ApiClient();
|
|
1346
1035
|
try {
|
|
1036
|
+
const promptId = await resolvePromptId(client, resolvedAppId, prompt);
|
|
1347
1037
|
const result = await client.downloadTestCaseAttachment(resolvedAppId, "prompt", promptId, testCaseId, filename);
|
|
1348
1038
|
const finalPath = outputPath || filename;
|
|
1349
1039
|
writeFileSync(finalPath, result.data);
|
|
@@ -1356,42 +1046,6 @@ Examples:
|
|
|
1356
1046
|
process.exit(1);
|
|
1357
1047
|
}
|
|
1358
1048
|
});
|
|
1359
|
-
// Delete attachment
|
|
1360
|
-
attachments
|
|
1361
|
-
.command("delete")
|
|
1362
|
-
.description("Delete a file attachment from a test case")
|
|
1363
|
-
.argument("<prompt-id>", "Prompt ID")
|
|
1364
|
-
.argument("<test-case-id>", "Test Case ID")
|
|
1365
|
-
.argument("<filename>", "Name of the file to delete")
|
|
1366
|
-
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1367
|
-
.option("-y, --yes", "Skip confirmation prompt")
|
|
1368
|
-
.action(async (promptId, testCaseId, filename, options) => {
|
|
1369
|
-
const resolvedAppId = resolveAppId(undefined, options);
|
|
1370
|
-
if (!options.yes) {
|
|
1371
|
-
const inquirer = await import("inquirer");
|
|
1372
|
-
const { confirm } = await inquirer.default.prompt([
|
|
1373
|
-
{
|
|
1374
|
-
type: "confirm",
|
|
1375
|
-
name: "confirm",
|
|
1376
|
-
message: `Are you sure you want to delete attachment "${filename}"?`,
|
|
1377
|
-
default: false,
|
|
1378
|
-
},
|
|
1379
|
-
]);
|
|
1380
|
-
if (!confirm) {
|
|
1381
|
-
info("Cancelled.");
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
const client = new ApiClient();
|
|
1386
|
-
try {
|
|
1387
|
-
await client.deleteTestCaseAttachment(resolvedAppId, "prompt", promptId, testCaseId, filename);
|
|
1388
|
-
success(`Deleted: ${filename}`);
|
|
1389
|
-
}
|
|
1390
|
-
catch (err) {
|
|
1391
|
-
error(err.message);
|
|
1392
|
-
process.exit(1);
|
|
1393
|
-
}
|
|
1394
|
-
});
|
|
1395
1049
|
}
|
|
1396
1050
|
function formatFileSize(bytes) {
|
|
1397
1051
|
if (bytes < 1024)
|