primitive-admin 1.0.63 → 1.0.64
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 +132 -42
- package/assets/skill/skills/primitive-platform/SKILL.md +142 -661
- package/dist/bin/primitive.js +121 -41
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/admins.js +37 -50
- package/dist/src/commands/admins.js.map +1 -1
- package/dist/src/commands/analytics.js +178 -9
- package/dist/src/commands/analytics.js.map +1 -1
- package/dist/src/commands/apps.js +12 -5
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/auth-sessions.d.ts +7 -0
- package/dist/src/commands/auth-sessions.js +144 -0
- package/dist/src/commands/auth-sessions.js.map +1 -0
- package/dist/src/commands/auth.js +76 -116
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/blob-buckets.js +2 -1
- package/dist/src/commands/blob-buckets.js.map +1 -1
- package/dist/src/commands/catalog.js +26 -10
- package/dist/src/commands/catalog.js.map +1 -1
- package/dist/src/commands/collection-type-configs.js +3 -10
- package/dist/src/commands/collection-type-configs.js.map +1 -1
- package/dist/src/commands/collections.js +736 -19
- package/dist/src/commands/collections.js.map +1 -1
- package/dist/src/commands/config.js +13 -27
- package/dist/src/commands/config.js.map +1 -1
- package/dist/src/commands/connections.js +8 -9
- package/dist/src/commands/connections.js.map +1 -1
- package/dist/src/commands/cron-triggers.js +2 -1
- package/dist/src/commands/cron-triggers.js.map +1 -1
- package/dist/src/commands/database-type-configs.js +5 -12
- package/dist/src/commands/database-type-configs.js.map +1 -1
- package/dist/src/commands/databases.js +59 -72
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.d.ts +58 -0
- package/dist/src/commands/documents.js +1623 -95
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/email-templates.js +2 -1
- package/dist/src/commands/email-templates.js.map +1 -1
- package/dist/src/commands/env.d.ts +1 -1
- package/dist/src/commands/env.js +89 -43
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/feature-flags.js +2 -1
- package/dist/src/commands/feature-flags.js.map +1 -1
- package/dist/src/commands/functions.d.ts +20 -0
- package/dist/src/commands/functions.js +1630 -0
- package/dist/src/commands/functions.js.map +1 -0
- package/dist/src/commands/group-type-configs.js +2 -1
- package/dist/src/commands/group-type-configs.js.map +1 -1
- package/dist/src/commands/groups.js +30 -17
- package/dist/src/commands/groups.js.map +1 -1
- package/dist/src/commands/guides.js +17 -11
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/init.d.ts +12 -15
- package/dist/src/commands/init.js +44 -92
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.js +35 -12
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/locks.js +17 -2
- package/dist/src/commands/locks.js.map +1 -1
- package/dist/src/commands/metadata-category-configs.js +2 -1
- package/dist/src/commands/metadata-category-configs.js.map +1 -1
- package/dist/src/commands/metadata.js +8 -1
- package/dist/src/commands/metadata.js.map +1 -1
- package/dist/src/commands/prompts.js +106 -59
- package/dist/src/commands/prompts.js.map +1 -1
- package/dist/src/commands/rule-sets.js +3 -10
- package/dist/src/commands/rule-sets.js.map +1 -1
- package/dist/src/commands/scripts.js +33 -28
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/secrets.js +2 -1
- package/dist/src/commands/secrets.js.map +1 -1
- package/dist/src/commands/sessions.js +10 -9
- package/dist/src/commands/sessions.js.map +1 -1
- package/dist/src/commands/sync-app-settings.js +3 -5
- package/dist/src/commands/sync-app-settings.js.map +1 -1
- package/dist/src/commands/sync.d.ts +390 -13
- package/dist/src/commands/sync.js +2613 -451
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.js +2 -1
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.js +19 -10
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/vars.js +2 -1
- package/dist/src/commands/vars.js.map +1 -1
- package/dist/src/commands/waitlist.js +2 -1
- package/dist/src/commands/waitlist.js.map +1 -1
- package/dist/src/commands/webhooks.d.ts +29 -0
- package/dist/src/commands/webhooks.js +135 -64
- package/dist/src/commands/webhooks.js.map +1 -1
- package/dist/src/commands/workflows.d.ts +1 -29
- package/dist/src/commands/workflows.js +113 -179
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +628 -14
- package/dist/src/lib/api-client.js +776 -70
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +1 -1
- package/dist/src/lib/app-settings-descriptor.js +9 -1
- package/dist/src/lib/app-settings-descriptor.js.map +1 -1
- 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/codegen-shared/resolveCodegenSourceDir.d.ts +24 -54
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +31 -153
- package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
- package/dist/src/lib/collection-export.d.ts +184 -0
- package/dist/src/lib/collection-export.js +252 -0
- package/dist/src/lib/collection-export.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.js +88 -6
- package/dist/src/lib/config-object-descriptor.js.map +1 -1
- package/dist/src/lib/config-payload.d.ts +8 -1
- package/dist/src/lib/config-payload.js +49 -4
- package/dist/src/lib/config-payload.js.map +1 -1
- package/dist/src/lib/config-surface.d.ts +12 -1
- package/dist/src/lib/config-surface.js +71 -3
- package/dist/src/lib/config-surface.js.map +1 -1
- package/dist/src/lib/config.d.ts +31 -13
- package/dist/src/lib/config.js +34 -70
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/credentials-store.d.ts +37 -22
- package/dist/src/lib/credentials-store.js +103 -97
- package/dist/src/lib/credentials-store.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.js +8 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -1
- package/dist/src/lib/deprecation.d.ts +22 -0
- package/dist/src/lib/deprecation.js +43 -0
- package/dist/src/lib/deprecation.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/document-ingest-artifact.d.ts +120 -0
- package/dist/src/lib/document-ingest-artifact.js +505 -0
- package/dist/src/lib/document-ingest-artifact.js.map +1 -0
- package/dist/src/lib/document-ingest-input.d.ts +51 -0
- package/dist/src/lib/document-ingest-input.js +132 -0
- package/dist/src/lib/document-ingest-input.js.map +1 -0
- package/dist/src/lib/document-ingest-rows.d.ts +137 -0
- package/dist/src/lib/document-ingest-rows.js +181 -0
- package/dist/src/lib/document-ingest-rows.js.map +1 -0
- package/dist/src/lib/document-ingest.d.ts +101 -0
- package/dist/src/lib/document-ingest.js +384 -0
- package/dist/src/lib/document-ingest.js.map +1 -0
- package/dist/src/lib/env-resolver-core.d.ts +89 -18
- package/dist/src/lib/env-resolver-core.js +145 -23
- package/dist/src/lib/env-resolver-core.js.map +1 -1
- package/dist/src/lib/env-resolver.d.ts +18 -3
- package/dist/src/lib/env-resolver.js +23 -3
- package/dist/src/lib/env-resolver.js.map +1 -1
- package/dist/src/lib/function-bundle.d.ts +147 -0
- package/dist/src/lib/function-bundle.js +341 -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 +610 -0
- package/dist/src/lib/function-collect.js.map +1 -0
- package/dist/src/lib/function-db-types.d.ts +202 -0
- package/dist/src/lib/function-db-types.js +870 -0
- package/dist/src/lib/function-db-types.js.map +1 -0
- package/dist/src/lib/function-document-types.d.ts +144 -0
- package/dist/src/lib/function-document-types.js +370 -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 +105 -0
- package/dist/src/lib/function-grants-preflight.js.map +1 -0
- package/dist/src/lib/function-log-lines.d.ts +76 -0
- package/dist/src/lib/function-log-lines.js +160 -0
- package/dist/src/lib/function-log-lines.js.map +1 -0
- package/dist/src/lib/function-log-row.d.ts +29 -0
- package/dist/src/lib/function-log-row.js +73 -0
- package/dist/src/lib/function-log-row.js.map +1 -0
- package/dist/src/lib/function-log-tail.d.ts +132 -0
- package/dist/src/lib/function-log-tail.js +262 -0
- package/dist/src/lib/function-log-tail.js.map +1 -0
- package/dist/src/lib/function-run.d.ts +289 -0
- package/dist/src/lib/function-run.js +389 -0
- package/dist/src/lib/function-run.js.map +1 -0
- package/dist/src/lib/function-schema-codegen.d.ts +143 -0
- package/dist/src/lib/function-schema-codegen.js +420 -0
- package/dist/src/lib/function-schema-codegen.js.map +1 -0
- package/dist/src/lib/function-sync.d.ts +459 -0
- package/dist/src/lib/function-sync.js +1258 -0
- package/dist/src/lib/function-sync.js.map +1 -0
- package/dist/src/lib/function-trigger-listing.d.ts +27 -0
- package/dist/src/lib/function-trigger-listing.js +70 -0
- package/dist/src/lib/function-trigger-listing.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/function-versions.d.ts +122 -0
- package/dist/src/lib/function-versions.js +182 -0
- package/dist/src/lib/function-versions.js.map +1 -0
- package/dist/src/lib/generated-allowlist.js +4 -0
- package/dist/src/lib/generated-allowlist.js.map +1 -1
- package/dist/src/lib/generated-config-surfaces.d.ts +2332 -78
- package/dist/src/lib/generated-config-surfaces.js +6979 -468
- package/dist/src/lib/generated-config-surfaces.js.map +1 -1
- 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/init-adopt.js +2 -2
- package/dist/src/lib/init-adopt.js.map +1 -1
- package/dist/src/lib/init-assets.js +3 -3
- package/dist/src/lib/init-config.d.ts +1 -1
- package/dist/src/lib/init-ios-links.d.ts +6 -5
- package/dist/src/lib/init-ios-links.js +9 -8
- package/dist/src/lib/init-ios-links.js.map +1 -1
- package/dist/src/lib/init-plan.d.ts +1 -1
- package/dist/src/lib/init-plan.js +1 -1
- package/dist/src/lib/init-xcode.d.ts +6 -5
- package/dist/src/lib/init-xcode.js +34 -10
- package/dist/src/lib/init-xcode.js.map +1 -1
- 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/list-options.d.ts +68 -0
- package/dist/src/lib/list-options.js +89 -0
- package/dist/src/lib/list-options.js.map +1 -0
- package/dist/src/lib/local-state.d.ts +1 -1
- package/dist/src/lib/local-state.js +1 -1
- package/dist/src/lib/local-test-cases.d.ts +1 -1
- package/dist/src/lib/local-test-cases.js +2 -1
- package/dist/src/lib/local-test-cases.js.map +1 -1
- package/dist/src/lib/log-inspection.d.ts +152 -5
- package/dist/src/lib/log-inspection.js +179 -2
- package/dist/src/lib/log-inspection.js.map +1 -1
- package/dist/src/lib/logout-admin-session.d.ts +33 -0
- package/dist/src/lib/logout-admin-session.js +70 -0
- package/dist/src/lib/logout-admin-session.js.map +1 -0
- package/dist/src/lib/output.d.ts +15 -0
- package/dist/src/lib/output.js +28 -0
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/paginate.d.ts +15 -0
- package/dist/src/lib/paginate.js +17 -0
- package/dist/src/lib/paginate.js.map +1 -1
- package/dist/src/lib/project-config.d.ts +38 -21
- package/dist/src/lib/project-config.js +57 -47
- package/dist/src/lib/project-config.js.map +1 -1
- package/dist/src/lib/prompt-cost-format.d.ts +11 -0
- package/dist/src/lib/prompt-cost-format.js +41 -0
- package/dist/src/lib/prompt-cost-format.js.map +1 -0
- package/dist/src/lib/prompt-schema-codegen.d.ts +147 -0
- package/dist/src/lib/prompt-schema-codegen.js +462 -0
- package/dist/src/lib/prompt-schema-codegen.js.map +1 -0
- package/dist/src/lib/refresh-admin-credentials.d.ts +9 -1
- package/dist/src/lib/refresh-admin-credentials.js +22 -2
- package/dist/src/lib/refresh-admin-credentials.js.map +1 -1
- package/dist/src/lib/resolve-owner.d.ts +19 -0
- package/dist/src/lib/resolve-owner.js +20 -0
- package/dist/src/lib/resolve-owner.js.map +1 -0
- package/dist/src/lib/skill-installer.d.ts +49 -3
- package/dist/src/lib/skill-installer.js +275 -100
- package/dist/src/lib/skill-installer.js.map +1 -1
- package/dist/src/lib/snapshot-audit-source.d.ts +45 -0
- package/dist/src/lib/snapshot-audit-source.js +58 -0
- package/dist/src/lib/snapshot-audit-source.js.map +1 -0
- package/dist/src/lib/snapshot-audit-store.d.ts +52 -0
- package/dist/src/lib/snapshot-audit-store.js +196 -0
- package/dist/src/lib/snapshot-audit-store.js.map +1 -0
- package/dist/src/lib/snapshot-audit.d.ts +207 -0
- package/dist/src/lib/snapshot-audit.js +431 -0
- package/dist/src/lib/snapshot-audit.js.map +1 -0
- package/dist/src/lib/snapshot-build-rows.d.ts +60 -0
- package/dist/src/lib/snapshot-build-rows.js +87 -0
- package/dist/src/lib/snapshot-build-rows.js.map +1 -0
- package/dist/src/lib/snapshot-build.d.ts +50 -0
- package/dist/src/lib/snapshot-build.js +111 -0
- package/dist/src/lib/snapshot-build.js.map +1 -0
- package/dist/src/lib/snapshot-manifest-layout.d.ts +61 -0
- package/dist/src/lib/snapshot-manifest-layout.js +70 -0
- package/dist/src/lib/snapshot-manifest-layout.js.map +1 -0
- package/dist/src/lib/snapshots.d.ts +8 -9
- package/dist/src/lib/snapshots.js +20 -83
- package/dist/src/lib/snapshots.js.map +1 -1
- package/dist/src/lib/step-run-table.d.ts +43 -0
- package/dist/src/lib/step-run-table.js +129 -0
- package/dist/src/lib/step-run-table.js.map +1 -0
- package/dist/src/lib/storage-pending-retry.d.ts +26 -0
- package/dist/src/lib/storage-pending-retry.js +42 -0
- package/dist/src/lib/storage-pending-retry.js.map +1 -0
- package/dist/src/lib/swift-codegen/agentGenerator.d.ts +42 -0
- package/dist/src/lib/swift-codegen/agentGenerator.js +118 -0
- package/dist/src/lib/swift-codegen/agentGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/banners.d.ts +24 -0
- package/dist/src/lib/swift-codegen/banners.js +25 -0
- package/dist/src/lib/swift-codegen/banners.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js +19 -7
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/swift-codegen/functionGenerator.d.ts +139 -0
- package/dist/src/lib/swift-codegen/functionGenerator.js +462 -0
- package/dist/src/lib/swift-codegen/functionGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/generator.d.ts +7 -1
- package/dist/src/lib/swift-codegen/generator.js +28 -11
- package/dist/src/lib/swift-codegen/generator.js.map +1 -1
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +15 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js +21 -4
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -1
- package/dist/src/lib/sync-paths.d.ts +72 -55
- package/dist/src/lib/sync-paths.js +97 -100
- package/dist/src/lib/sync-paths.js.map +1 -1
- package/dist/src/lib/sync-resource-types.d.ts +23 -4
- package/dist/src/lib/sync-resource-types.js +106 -8
- package/dist/src/lib/sync-resource-types.js.map +1 -1
- package/dist/src/lib/sync-selectors.d.ts +45 -2
- package/dist/src/lib/sync-selectors.js +66 -5
- package/dist/src/lib/sync-selectors.js.map +1 -1
- package/dist/src/lib/template.d.ts +2 -2
- package/dist/src/lib/template.js +2 -2
- package/dist/src/lib/test-case-keys.d.ts +1 -1
- package/dist/src/lib/test-case-keys.js +1 -1
- package/dist/src/lib/test-case-variables.d.ts +14 -0
- package/dist/src/lib/test-case-variables.js +42 -0
- package/dist/src/lib/test-case-variables.js.map +1 -1
- package/dist/src/lib/toml-database-config.js +19 -2
- package/dist/src/lib/toml-database-config.js.map +1 -1
- package/dist/src/lib/webhook-deliver.d.ts +209 -0
- package/dist/src/lib/webhook-deliver.js +519 -0
- package/dist/src/lib/webhook-deliver.js.map +1 -0
- package/dist/src/lib/workflow-codegen/generator.d.ts +1 -1
- package/dist/src/lib/workflow-codegen/generator.js +1 -1
- package/dist/src/lib/workflow-toml-validator.d.ts +17 -8
- package/dist/src/lib/workflow-toml-validator.js +25 -12
- package/dist/src/lib/workflow-toml-validator.js.map +1 -1
- package/dist/src/lib/workflow-usage.d.ts +196 -0
- package/dist/src/lib/workflow-usage.js +310 -0
- package/dist/src/lib/workflow-usage.js.map +1 -0
- package/dist/src/types/index.d.ts +12 -2
- package/package.json +5 -4
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Option } from "commander";
|
|
2
1
|
import { readFileSync, writeFileSync, readdirSync, } from "fs";
|
|
3
2
|
import * as path from "path";
|
|
4
3
|
import { stringifyConfigToml } from "../lib/config-toml.js";
|
|
@@ -6,17 +5,18 @@ import { generateWorkflowTypes, } from "../lib/workflow-codegen/generator.js";
|
|
|
6
5
|
import { generateWorkflowSwiftTypes } from "../lib/swift-codegen/generator.js";
|
|
7
6
|
import { ApiClient } from "../lib/api-client.js";
|
|
8
7
|
import { resolveAppId } from "../lib/config.js";
|
|
8
|
+
import { resolveWorkflowSelector } from "../lib/block-selector.js";
|
|
9
9
|
import { formatAccessRuleForDisplay } from "../lib/access-rule-display.js";
|
|
10
10
|
import { resolveCodegenSourceDir } from "../lib/codegen-shared/resolveCodegenSourceDir.js";
|
|
11
|
-
import { resolveSyncDirOverride } from "../lib/sync-dir-selector.js";
|
|
12
11
|
import { expandWorkflow } from "../lib/workflow-fragments.js";
|
|
13
12
|
import { confirmPrompt } from "../lib/confirm-prompt.js";
|
|
14
13
|
import { parseStatusFilter } from "../lib/object-status-filter.js";
|
|
15
|
-
import { buildWorkflowRunEnvelope, buildWorkflowStepEnvelope, collectWorkflowFailures, describeEmptyRunPage, describeFailureSweep, formatFailureCodeCell, formatFailureErrorCell, formatFailureStepCell, selectFailedStepRow, toWorkflowRunInspectionRow, DEFAULT_FAILURE_SWEEP_MAX_SCAN, FAILURE_SWEEP_MAX_REQUESTS, SERVER_SCAN_ROWS_PER_REQUEST, } from "../lib/log-inspection.js";
|
|
14
|
+
import { buildWorkflowRunEnvelope, buildWorkflowRunListEnvelope, buildWorkflowStepEnvelope, collectWorkflowFailures, describeEmptyRunPage, describeFailureSweep, formatFailureCodeCell, formatFailureErrorCell, formatFailureStepCell, selectFailedStepRow, toWorkflowRunInspectionRow, DEFAULT_FAILURE_SWEEP_MAX_SCAN, FAILURE_SWEEP_MAX_REQUESTS, SERVER_SCAN_ROWS_PER_REQUEST, } from "../lib/log-inspection.js";
|
|
16
15
|
import chalk from "chalk";
|
|
17
16
|
import { success, error, info, warn, keyValue, result as printResult, formatTable, formatId, formatDate, formatStatus, formatDuration, json, jsonLine, divider, dim, progress, progressEnd, } from "../lib/output.js";
|
|
18
17
|
import { pollUntil, followLoop, watchLoop, parseIntervalSeconds, } from "../lib/watch.js";
|
|
19
18
|
import { APPLY_RUN_STATUSES, RUN_STATUS_LIST, SETTLED_RUN_STATUSES, } from "../lib/run-status.js";
|
|
19
|
+
import { requireTestCaseInputVariables } from "../lib/test-case-variables.js";
|
|
20
20
|
/**
|
|
21
21
|
* Render the `Step Results` section of `workflows runs status`. Pure
|
|
22
22
|
* formatting helper — returns lines as strings so it's unit-testable
|
|
@@ -121,25 +121,15 @@ export function renderRunStatusStepResults(stepResults) {
|
|
|
121
121
|
}
|
|
122
122
|
return lines;
|
|
123
123
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*/
|
|
134
|
-
export function stepRunDisplayDurationMs(step, now = Date.now()) {
|
|
135
|
-
const stored = typeof step?.durationMs === "number" ? step.durationMs : null;
|
|
136
|
-
if (step?.status !== "running")
|
|
137
|
-
return stored;
|
|
138
|
-
const started = step?.startedAt ? new Date(step.startedAt).getTime() : NaN;
|
|
139
|
-
if (Number.isNaN(started))
|
|
140
|
-
return stored;
|
|
141
|
-
return Math.max(0, now - started);
|
|
142
|
-
}
|
|
124
|
+
// #3348 — the step table, the gap annotation and the running-step duration now
|
|
125
|
+
// live in `lib/step-run-table.ts`, shared with `functions runs steps`: a
|
|
126
|
+
// function run's steps are the same rows, and the two views must not be two
|
|
127
|
+
// tables that merely resemble each other. Re-exported from here because this is
|
|
128
|
+
// where the two helpers were first exported for testability.
|
|
129
|
+
export { annotateStepGaps, stepRunDisplayDurationMs, } from "../lib/step-run-table.js";
|
|
130
|
+
import { renderStepRunTable, stepRunDisplayDurationMs, } from "../lib/step-run-table.js";
|
|
131
|
+
import { normalizeCliListEnvelope, wholeListEnvelope, } from "../lib/paginate.js";
|
|
132
|
+
import { pageCursorOption, pageLimitOption, parsePageLimit, printEmptyPage, printPageHint, } from "../lib/list-options.js";
|
|
143
133
|
/**
|
|
144
134
|
* #2771 — the step lines `workflows runs status` should render.
|
|
145
135
|
*
|
|
@@ -163,53 +153,6 @@ export function stepResultsForRunStatus(instanceStepResults, persistedStepRuns,
|
|
|
163
153
|
output: row?.output,
|
|
164
154
|
}));
|
|
165
155
|
}
|
|
166
|
-
/**
|
|
167
|
-
* #1367 — annotate step-run rows with the inter-step gap: the wall-clock time
|
|
168
|
-
* between the previous step's `endedAt` and this step's `startedAt`. Sorts by
|
|
169
|
-
* `startedAt` when every row has a parseable one (tie-break `stepIndex`),
|
|
170
|
-
* otherwise by `stepIndex` for the whole list — the ordering mode must be
|
|
171
|
-
* chosen once for all rows, not per pair: a per-pair timestamp-vs-index
|
|
172
|
-
* fallback is not transitive when some rows lack a timestamp (A<B by index,
|
|
173
|
-
* B<C by index, C<A by time), and a non-transitive comparator leaves
|
|
174
|
-
* Array.prototype.sort free to return an arbitrary order, computing gaps
|
|
175
|
-
* against the wrong predecessor. The first step has no predecessor, so its
|
|
176
|
-
* `gapMs` is `null`. A gap is only meaningful when both adjacent timestamps
|
|
177
|
-
* parse and the gap is positive. When the immediate predecessor lacks a valid
|
|
178
|
-
* `endedAt`, the gap is left `null` rather than measured from an older,
|
|
179
|
-
* non-adjacent step — otherwise a later step could raise a false stall
|
|
180
|
-
* warning against a step it does not actually follow. Exported for
|
|
181
|
-
* testability.
|
|
182
|
-
*/
|
|
183
|
-
export function annotateStepGaps(steps) {
|
|
184
|
-
const rows = [...(steps || [])];
|
|
185
|
-
const allTimed = rows.every((r) => r?.startedAt && !Number.isNaN(new Date(r.startedAt).getTime()));
|
|
186
|
-
rows.sort((a, b) => {
|
|
187
|
-
if (allTimed) {
|
|
188
|
-
const sa = new Date(a.startedAt).getTime();
|
|
189
|
-
const sb = new Date(b.startedAt).getTime();
|
|
190
|
-
if (sa !== sb)
|
|
191
|
-
return sa - sb;
|
|
192
|
-
}
|
|
193
|
-
return (a?.stepIndex ?? 0) - (b?.stepIndex ?? 0);
|
|
194
|
-
});
|
|
195
|
-
let prevEnded = null;
|
|
196
|
-
for (const row of rows) {
|
|
197
|
-
const started = row?.startedAt ? new Date(row.startedAt).getTime() : NaN;
|
|
198
|
-
if (prevEnded != null && !Number.isNaN(started)) {
|
|
199
|
-
const gap = started - prevEnded;
|
|
200
|
-
row.gapMs = gap > 0 ? gap : 0;
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
row.gapMs = null;
|
|
204
|
-
}
|
|
205
|
-
// Only genuinely adjacent steps yield a gap: if this step lacks a valid
|
|
206
|
-
// `endedAt`, clear the predecessor so the NEXT step's gap is left null
|
|
207
|
-
// instead of being measured from a non-adjacent earlier step.
|
|
208
|
-
const ended = row?.endedAt ? new Date(row.endedAt).getTime() : NaN;
|
|
209
|
-
prevEnded = Number.isNaN(ended) ? null : ended;
|
|
210
|
-
}
|
|
211
|
-
return rows;
|
|
212
|
-
}
|
|
213
156
|
/**
|
|
214
157
|
* #1367 — compute min / p50 / p95 / max over a set of latency samples (ms).
|
|
215
158
|
* Ignores non-finite values. Returns `null` when there are no valid samples.
|
|
@@ -253,6 +196,17 @@ export function formatConfigSlotLabel(slot, configName, configId, prefixLength =
|
|
|
253
196
|
}
|
|
254
197
|
return slot;
|
|
255
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Resolve a workflow reference — its server id, or the author-chosen key its
|
|
201
|
+
* TOML file is named for — for the `tests` verbs (#3249).
|
|
202
|
+
*
|
|
203
|
+
* The key is what an operator has: `workflows/<key>.toml` is the object and
|
|
204
|
+
* `workflows/<key>.tests/` its cases. The resolution lives in
|
|
205
|
+
* `block-selector.ts`, shared with `prompts`.
|
|
206
|
+
*/
|
|
207
|
+
async function resolveWorkflowId(client, appId, ref) {
|
|
208
|
+
return (await resolveWorkflowSelector(client, appId, ref)).blockId;
|
|
209
|
+
}
|
|
256
210
|
export function registerWorkflowsCommands(program) {
|
|
257
211
|
const workflows = program
|
|
258
212
|
.command("workflows")
|
|
@@ -296,8 +250,11 @@ overview — the endpoint behind the retired overview command never existed.
|
|
|
296
250
|
.argument("[app-id]", "App ID (uses current app if not specified)")
|
|
297
251
|
.option("--app <app-id>", "App ID")
|
|
298
252
|
.option("--status <status>", "Filter by status: active, inactive, archived")
|
|
253
|
+
.addOption(pageLimitOption())
|
|
254
|
+
.addOption(pageCursorOption())
|
|
299
255
|
.option("--json", "Output as JSON")
|
|
300
256
|
.action(async (appId, options) => {
|
|
257
|
+
const limit = parsePageLimit(options.limit);
|
|
301
258
|
const resolvedAppId = resolveAppId(appId, options);
|
|
302
259
|
const client = new ApiClient();
|
|
303
260
|
try {
|
|
@@ -305,19 +262,22 @@ overview — the endpoint behind the retired overview command never existed.
|
|
|
305
262
|
// empty list a canonical filter would produce. #2887 added `archived`:
|
|
306
263
|
// the delete flow writes one now, so asking for the retired rows is a
|
|
307
264
|
// question with an answer rather than a 400.
|
|
308
|
-
const
|
|
265
|
+
const page = normalizeCliListEnvelope(await client.listWorkflows(resolvedAppId, {
|
|
309
266
|
status: parseStatusFilter("workflows", options.status, [
|
|
310
267
|
"active",
|
|
311
268
|
"inactive",
|
|
312
269
|
"archived",
|
|
313
270
|
]),
|
|
314
|
-
|
|
271
|
+
limit,
|
|
272
|
+
cursor: options.cursor,
|
|
273
|
+
}));
|
|
274
|
+
const items = page.items;
|
|
315
275
|
if (options.json) {
|
|
316
|
-
json(
|
|
276
|
+
json(page);
|
|
317
277
|
return;
|
|
318
278
|
}
|
|
319
|
-
if (
|
|
320
|
-
|
|
279
|
+
if (items.length === 0) {
|
|
280
|
+
printEmptyPage(page, "workflows");
|
|
321
281
|
return;
|
|
322
282
|
}
|
|
323
283
|
console.log(formatTable(items, [
|
|
@@ -327,6 +287,7 @@ overview — the endpoint behind the retired overview command never existed.
|
|
|
327
287
|
{ header: "STATUS", key: "status", format: formatStatus },
|
|
328
288
|
{ header: "MODIFIED", key: "modifiedAt", format: formatDate },
|
|
329
289
|
]));
|
|
290
|
+
printPageHint(page);
|
|
330
291
|
}
|
|
331
292
|
catch (err) {
|
|
332
293
|
error(err.message);
|
|
@@ -988,10 +949,11 @@ Reclaiming the key means hard-deleting the row and its cascade:
|
|
|
988
949
|
});
|
|
989
950
|
const { items } = page;
|
|
990
951
|
if (options.json) {
|
|
991
|
-
//
|
|
992
|
-
// bare array
|
|
993
|
-
// `cursor`
|
|
994
|
-
|
|
952
|
+
// The CLI's one list envelope with the shared inspection item
|
|
953
|
+
// shape — never a bare array, and since #3646 no `nextCursor:
|
|
954
|
+
// null` and no deprecated `cursor` alias either, because this is a
|
|
955
|
+
// `list` verb like any other (behaviors 6, 7).
|
|
956
|
+
json(buildWorkflowRunListEnvelope(items, page));
|
|
995
957
|
return;
|
|
996
958
|
}
|
|
997
959
|
// The cursor hint prints whether or not this page had rows: a
|
|
@@ -1105,7 +1067,7 @@ Reclaiming the key means hard-deleting the row and its cascade:
|
|
|
1105
1067
|
signal: controller.signal,
|
|
1106
1068
|
render: (items) => {
|
|
1107
1069
|
if (options.json) {
|
|
1108
|
-
json(
|
|
1070
|
+
json(buildWorkflowRunListEnvelope(items, lastPage));
|
|
1109
1071
|
return;
|
|
1110
1072
|
}
|
|
1111
1073
|
// Renderer owns the redraw: clear the screen, then print.
|
|
@@ -1225,49 +1187,7 @@ Reclaiming the key means hard-deleting the row and its cascade:
|
|
|
1225
1187
|
info("No step runs found.");
|
|
1226
1188
|
return;
|
|
1227
1189
|
}
|
|
1228
|
-
|
|
1229
|
-
// next starting. Only surfaced above a 1s threshold so normal
|
|
1230
|
-
// back-to-back steps stay quiet; a large gap flags a mid-run stall.
|
|
1231
|
-
const STEP_GAP_THRESHOLD_MS = 1000;
|
|
1232
|
-
// #2771 — an in-flight run also returns the step executing right now
|
|
1233
|
-
// (status `running`, duration not written yet). Show its elapsed time
|
|
1234
|
-
// so a step stuck retrying is visible as such.
|
|
1235
|
-
const rows = annotateStepGaps(items).map((row) => ({
|
|
1236
|
-
...row,
|
|
1237
|
-
displayDurationMs: stepRunDisplayDurationMs(row),
|
|
1238
|
-
}));
|
|
1239
|
-
console.log(formatTable(rows, [
|
|
1240
|
-
{ header: "STEP", key: "stepId" },
|
|
1241
|
-
{ header: "KIND", key: "stepKind" },
|
|
1242
|
-
{
|
|
1243
|
-
header: "STATUS",
|
|
1244
|
-
key: "status",
|
|
1245
|
-
format: (v) => v === "completed" ? chalk.green(v) :
|
|
1246
|
-
v === "failed" ? chalk.red(v) :
|
|
1247
|
-
v === "skipped" ? chalk.gray(v) :
|
|
1248
|
-
v === "error_captured" ? chalk.yellow(v) :
|
|
1249
|
-
// #2771 — the step executing right now.
|
|
1250
|
-
v === "running" ? chalk.cyan(v) : v,
|
|
1251
|
-
},
|
|
1252
|
-
{
|
|
1253
|
-
header: "GAP",
|
|
1254
|
-
key: "gapMs",
|
|
1255
|
-
format: (v) => typeof v === "number" && v >= STEP_GAP_THRESHOLD_MS
|
|
1256
|
-
? chalk.yellow(formatDuration(v))
|
|
1257
|
-
: chalk.dim("-"),
|
|
1258
|
-
},
|
|
1259
|
-
{ header: "DURATION", key: "displayDurationMs", format: formatDuration },
|
|
1260
|
-
{
|
|
1261
|
-
header: "TOKENS",
|
|
1262
|
-
key: "totalTokens",
|
|
1263
|
-
format: (v) => v ? String(v).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : "-",
|
|
1264
|
-
},
|
|
1265
|
-
{
|
|
1266
|
-
header: "ERROR",
|
|
1267
|
-
key: "error",
|
|
1268
|
-
format: (v) => v ? (v.length > 60 ? v.slice(0, 57) + "..." : v) : "",
|
|
1269
|
-
},
|
|
1270
|
-
]));
|
|
1190
|
+
console.log(renderStepRunTable(items));
|
|
1271
1191
|
}
|
|
1272
1192
|
catch (err) {
|
|
1273
1193
|
error(err.message);
|
|
@@ -1617,7 +1537,7 @@ Reclaiming the key means hard-deleting the row and its cascade:
|
|
|
1617
1537
|
try {
|
|
1618
1538
|
const { items } = await client.listIterations(resolvedAppId);
|
|
1619
1539
|
if (options.json) {
|
|
1620
|
-
json(items);
|
|
1540
|
+
json(wholeListEnvelope(items));
|
|
1621
1541
|
return;
|
|
1622
1542
|
}
|
|
1623
1543
|
if (!items || items.length === 0) {
|
|
@@ -1735,7 +1655,7 @@ activeConfigName in workflows/<key>.toml, then run 'primitive config push'.
|
|
|
1735
1655
|
try {
|
|
1736
1656
|
const { items } = await client.listWorkflowConfigs(resolvedAppId, workflowId);
|
|
1737
1657
|
if (options.json) {
|
|
1738
|
-
json(items);
|
|
1658
|
+
json(wholeListEnvelope(items));
|
|
1739
1659
|
return;
|
|
1740
1660
|
}
|
|
1741
1661
|
if (!items || items.length === 0) {
|
|
@@ -1809,29 +1729,44 @@ Test cases are authored in TOML at workflows/<key>.tests/<name>.toml and applied
|
|
|
1809
1729
|
with \`primitive config push\` (issue #2769); \`config fields workflow\` lists the
|
|
1810
1730
|
fields. Deleting a case is removing its file and running \`config push --prune\`.
|
|
1811
1731
|
|
|
1732
|
+
Every verb here takes the workflow's KEY or its ID (#3249). An identifier
|
|
1733
|
+
that names no workflow in the app fails; "No test cases found." only ever
|
|
1734
|
+
means the workflow exists and has no cases.
|
|
1735
|
+
|
|
1812
1736
|
Examples:
|
|
1813
|
-
$ primitive workflows tests list <workflow
|
|
1814
|
-
$ primitive workflows tests run <workflow
|
|
1815
|
-
$ primitive workflows tests run-all <workflow
|
|
1816
|
-
$ primitive workflows tests run-all <workflow
|
|
1737
|
+
$ primitive workflows tests list <workflow>
|
|
1738
|
+
$ primitive workflows tests run <workflow> <test-case-id>
|
|
1739
|
+
$ primitive workflows tests run-all <workflow>
|
|
1740
|
+
$ primitive workflows tests run-all <workflow> --test-cases 01ABC,01DEF,01GHI
|
|
1817
1741
|
`);
|
|
1818
1742
|
tests
|
|
1819
1743
|
.command("list")
|
|
1820
1744
|
.description("List test cases for a workflow")
|
|
1821
|
-
.argument("<workflow
|
|
1745
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
1822
1746
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1747
|
+
.addOption(pageLimitOption())
|
|
1748
|
+
.addOption(pageCursorOption())
|
|
1823
1749
|
.option("--json", "Output as JSON")
|
|
1824
|
-
.action(async (
|
|
1750
|
+
.action(async (workflow, options) => {
|
|
1751
|
+
const limit = parsePageLimit(options.limit);
|
|
1825
1752
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1826
1753
|
const client = new ApiClient();
|
|
1827
1754
|
try {
|
|
1828
|
-
|
|
1755
|
+
// #3249 — resolve BEFORE listing: the test-case endpoint answers an
|
|
1756
|
+
// unknown block with an empty page, so an unresolved identifier would
|
|
1757
|
+
// print "No test cases found." and exit 0.
|
|
1758
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
1759
|
+
const page = normalizeCliListEnvelope(await client.listTestCases(resolvedAppId, "workflow", workflowId, {
|
|
1760
|
+
limit,
|
|
1761
|
+
cursor: options.cursor,
|
|
1762
|
+
}));
|
|
1763
|
+
const items = page.items;
|
|
1829
1764
|
if (options.json) {
|
|
1830
|
-
json(
|
|
1765
|
+
json(page);
|
|
1831
1766
|
return;
|
|
1832
1767
|
}
|
|
1833
|
-
if (
|
|
1834
|
-
|
|
1768
|
+
if (items.length === 0) {
|
|
1769
|
+
printEmptyPage(page, "test cases");
|
|
1835
1770
|
return;
|
|
1836
1771
|
}
|
|
1837
1772
|
console.log(formatTable(items, [
|
|
@@ -1839,6 +1774,7 @@ Examples:
|
|
|
1839
1774
|
{ header: "NAME", key: "name" },
|
|
1840
1775
|
{ header: "CREATED", key: "createdAt", format: formatDate },
|
|
1841
1776
|
]));
|
|
1777
|
+
printPageHint(page);
|
|
1842
1778
|
}
|
|
1843
1779
|
catch (err) {
|
|
1844
1780
|
error(err.message);
|
|
@@ -1849,14 +1785,15 @@ Examples:
|
|
|
1849
1785
|
tests
|
|
1850
1786
|
.command("get")
|
|
1851
1787
|
.description("Get test case details")
|
|
1852
|
-
.argument("<workflow
|
|
1788
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
1853
1789
|
.argument("<test-case-id>", "Test Case ID")
|
|
1854
1790
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1855
1791
|
.option("--json", "Output as JSON")
|
|
1856
|
-
.action(async (
|
|
1792
|
+
.action(async (workflow, testCaseId, options) => {
|
|
1857
1793
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1858
1794
|
const client = new ApiClient();
|
|
1859
1795
|
try {
|
|
1796
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
1860
1797
|
const result = await client.getTestCase(resolvedAppId, "workflow", workflowId, testCaseId);
|
|
1861
1798
|
if (options.json) {
|
|
1862
1799
|
json(result);
|
|
@@ -1916,23 +1853,21 @@ Examples:
|
|
|
1916
1853
|
tests
|
|
1917
1854
|
.command("run")
|
|
1918
1855
|
.description("Run a single test case")
|
|
1919
|
-
.argument("<workflow
|
|
1856
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
1920
1857
|
.argument("<test-case-id>", "Test Case ID")
|
|
1921
1858
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1922
1859
|
.option("--json", "Output as JSON")
|
|
1923
|
-
.action(async (
|
|
1860
|
+
.action(async (workflow, testCaseId, options) => {
|
|
1924
1861
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1925
1862
|
const client = new ApiClient();
|
|
1926
1863
|
try {
|
|
1864
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
1927
1865
|
// Get test case to retrieve its variables
|
|
1928
1866
|
const testCase = await client.getTestCase(resolvedAppId, "workflow", workflowId, testCaseId);
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
catch {
|
|
1934
|
-
// Use empty object if parsing fails
|
|
1935
|
-
}
|
|
1867
|
+
// #3158 — the case's stored input IS the run's input, and the server
|
|
1868
|
+
// hands it back parsed; `JSON.parse` on that object threw and the run
|
|
1869
|
+
// went ahead with `{}`, disagreeing with `run-all` over the same case.
|
|
1870
|
+
const variables = requireTestCaseInputVariables(testCase.inputVariables, testCaseId);
|
|
1936
1871
|
const result = await client.executeBlockTest(resolvedAppId, "workflow", workflowId, {
|
|
1937
1872
|
variables,
|
|
1938
1873
|
testCaseId,
|
|
@@ -1985,14 +1920,17 @@ Examples:
|
|
|
1985
1920
|
tests
|
|
1986
1921
|
.command("run-all")
|
|
1987
1922
|
.description("Run all test cases for a workflow, or a specific subset")
|
|
1988
|
-
.argument("<workflow
|
|
1923
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
1989
1924
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
1990
1925
|
.option("--test-cases <ids>", "Comma-separated list of test case IDs to run (runs only these)")
|
|
1991
1926
|
.option("--json", "Output as JSON")
|
|
1992
|
-
.action(async (
|
|
1927
|
+
.action(async (workflow, options) => {
|
|
1993
1928
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
1994
1929
|
const client = new ApiClient();
|
|
1995
1930
|
try {
|
|
1931
|
+
// #3249 — resolve first, so `Total Tests: 0` can only ever mean the
|
|
1932
|
+
// workflow exists and has no cases, never that the identifier was wrong.
|
|
1933
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
1996
1934
|
// Parse test case IDs if provided
|
|
1997
1935
|
let testCaseIds;
|
|
1998
1936
|
if (options.testCases) {
|
|
@@ -2049,15 +1987,16 @@ Examples:
|
|
|
2049
1987
|
tests
|
|
2050
1988
|
.command("runs")
|
|
2051
1989
|
.description("List recent test runs for a workflow")
|
|
2052
|
-
.argument("<workflow
|
|
1990
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2053
1991
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2054
1992
|
.option("--limit <n>", "Maximum number of runs to show", "20")
|
|
2055
1993
|
.option("--group <group>", "Filter by comparison group")
|
|
2056
1994
|
.option("--json", "Output as JSON")
|
|
2057
|
-
.action(async (
|
|
1995
|
+
.action(async (workflow, options) => {
|
|
2058
1996
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2059
1997
|
const client = new ApiClient();
|
|
2060
1998
|
try {
|
|
1999
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2061
2000
|
const { items } = await client.listTestRuns(resolvedAppId, "workflow", workflowId, {
|
|
2062
2001
|
limit: parseInt(options.limit),
|
|
2063
2002
|
comparisonGroup: options.group,
|
|
@@ -2099,23 +2038,24 @@ Examples:
|
|
|
2099
2038
|
.description("Run tests in parallel using workflow-based execution")
|
|
2100
2039
|
.addHelpText("after", `
|
|
2101
2040
|
Examples:
|
|
2102
|
-
$ primitive workflows tests batch start <workflow
|
|
2103
|
-
$ primitive workflows tests batch start <workflow
|
|
2104
|
-
$ primitive workflows tests batch status <workflow
|
|
2105
|
-
$ primitive workflows tests batch cancel <workflow
|
|
2041
|
+
$ primitive workflows tests batch start <workflow>
|
|
2042
|
+
$ primitive workflows tests batch start <workflow> --test-cases 01ABC,01DEF
|
|
2043
|
+
$ primitive workflows tests batch status <workflow> <batch-id>
|
|
2044
|
+
$ primitive workflows tests batch cancel <workflow> <batch-id>
|
|
2106
2045
|
`);
|
|
2107
2046
|
// Start batch tests
|
|
2108
2047
|
batch
|
|
2109
2048
|
.command("start")
|
|
2110
2049
|
.description("Start parallel batch test execution")
|
|
2111
|
-
.argument("<workflow
|
|
2050
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2112
2051
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2113
2052
|
.option("--test-cases <ids>", "Comma-separated list of test case IDs to run")
|
|
2114
2053
|
.option("--json", "Output as JSON")
|
|
2115
|
-
.action(async (
|
|
2054
|
+
.action(async (workflow, options) => {
|
|
2116
2055
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2117
2056
|
const client = new ApiClient();
|
|
2118
2057
|
try {
|
|
2058
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2119
2059
|
let testCaseIds;
|
|
2120
2060
|
if (options.testCases) {
|
|
2121
2061
|
testCaseIds = options.testCases.split(",").map((id) => id.trim()).filter(Boolean);
|
|
@@ -2151,15 +2091,16 @@ Examples:
|
|
|
2151
2091
|
batch
|
|
2152
2092
|
.command("status")
|
|
2153
2093
|
.description("Get status of a batch test execution")
|
|
2154
|
-
.argument("<workflow
|
|
2094
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2155
2095
|
.argument("<batch-id>", "Batch ID")
|
|
2156
2096
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2157
2097
|
.option("--wait", "Wait for completion (polls every 2 seconds)")
|
|
2158
2098
|
.option("--json", "Output as JSON")
|
|
2159
|
-
.action(async (
|
|
2099
|
+
.action(async (workflow, batchId, options) => {
|
|
2160
2100
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2161
2101
|
const client = new ApiClient();
|
|
2162
2102
|
try {
|
|
2103
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2163
2104
|
const fetchStatus = async () => {
|
|
2164
2105
|
return client.getBatchTestStatus(resolvedAppId, "workflow", workflowId, batchId);
|
|
2165
2106
|
};
|
|
@@ -2216,12 +2157,12 @@ Examples:
|
|
|
2216
2157
|
batch
|
|
2217
2158
|
.command("cancel")
|
|
2218
2159
|
.description("Cancel a running batch test execution")
|
|
2219
|
-
.argument("<workflow
|
|
2160
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2220
2161
|
.argument("<batch-id>", "Batch ID")
|
|
2221
2162
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2222
2163
|
.option("-y, --yes", "Skip confirmation prompt")
|
|
2223
2164
|
.option("--json", "Output as JSON")
|
|
2224
|
-
.action(async (
|
|
2165
|
+
.action(async (workflow, batchId, options) => {
|
|
2225
2166
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2226
2167
|
if (!options.yes) {
|
|
2227
2168
|
let confirm;
|
|
@@ -2239,6 +2180,7 @@ Examples:
|
|
|
2239
2180
|
}
|
|
2240
2181
|
const client = new ApiClient();
|
|
2241
2182
|
try {
|
|
2183
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2242
2184
|
// First get current status to get instance IDs
|
|
2243
2185
|
const status = await client.getBatchTestStatus(resolvedAppId, "workflow", workflowId, batchId);
|
|
2244
2186
|
// Get instance IDs that are still running
|
|
@@ -2278,24 +2220,25 @@ with \`primitive config push\` (#2769); removing one and running
|
|
|
2278
2220
|
\`config push --prune\` deletes it server-side. These verbs read server state.
|
|
2279
2221
|
|
|
2280
2222
|
Examples:
|
|
2281
|
-
$ primitive workflows tests attachments list <workflow
|
|
2282
|
-
$ primitive workflows tests attachments download <workflow
|
|
2223
|
+
$ primitive workflows tests attachments list <workflow> <test-case-id>
|
|
2224
|
+
$ primitive workflows tests attachments download <workflow> <test-case-id> document.pdf
|
|
2283
2225
|
`);
|
|
2284
2226
|
// List attachments
|
|
2285
2227
|
attachments
|
|
2286
2228
|
.command("list")
|
|
2287
2229
|
.description("List attachments for a test case")
|
|
2288
|
-
.argument("<workflow
|
|
2230
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2289
2231
|
.argument("<test-case-id>", "Test Case ID")
|
|
2290
2232
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2291
2233
|
.option("--json", "Output as JSON")
|
|
2292
|
-
.action(async (
|
|
2234
|
+
.action(async (workflow, testCaseId, options) => {
|
|
2293
2235
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2294
2236
|
const client = new ApiClient();
|
|
2295
2237
|
try {
|
|
2238
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2296
2239
|
const result = await client.listTestCaseAttachments(resolvedAppId, "workflow", workflowId, testCaseId);
|
|
2297
2240
|
if (options.json) {
|
|
2298
|
-
json(result.attachments);
|
|
2241
|
+
json(wholeListEnvelope(result.attachments));
|
|
2299
2242
|
return;
|
|
2300
2243
|
}
|
|
2301
2244
|
if (!result.attachments || result.attachments.length === 0) {
|
|
@@ -2321,15 +2264,16 @@ Examples:
|
|
|
2321
2264
|
attachments
|
|
2322
2265
|
.command("download")
|
|
2323
2266
|
.description("Download a file attachment from a test case")
|
|
2324
|
-
.argument("<workflow
|
|
2267
|
+
.argument("<workflow>", "Workflow key or ID")
|
|
2325
2268
|
.argument("<test-case-id>", "Test Case ID")
|
|
2326
2269
|
.argument("<filename>", "Name of the file to download")
|
|
2327
2270
|
.argument("[output-path]", "Output path (defaults to current directory)")
|
|
2328
2271
|
.option("--app <app-id>", "App ID (uses current app if not specified)")
|
|
2329
|
-
.action(async (
|
|
2272
|
+
.action(async (workflow, testCaseId, filename, outputPath, options) => {
|
|
2330
2273
|
const resolvedAppId = resolveAppId(undefined, options);
|
|
2331
2274
|
const client = new ApiClient();
|
|
2332
2275
|
try {
|
|
2276
|
+
const workflowId = await resolveWorkflowId(client, resolvedAppId, workflow);
|
|
2333
2277
|
const result = await client.downloadTestCaseAttachment(resolvedAppId, "workflow", workflowId, testCaseId, filename);
|
|
2334
2278
|
const finalPath = outputPath || filename;
|
|
2335
2279
|
writeFileSync(finalPath, result.data);
|
|
@@ -2349,9 +2293,6 @@ Examples:
|
|
|
2349
2293
|
.command("codegen")
|
|
2350
2294
|
.description("Generate typed client signatures from the local workflows/*.toml schemas. TypeScript (default): one <key>.generated.ts per workflow (<Key>Input/<Key>Output types + a <key>(client) invoker factory). Swift (--lang swift): one <key>.generated.swift per workflow (<Key>Input/<Key>Output Codable types).\n\nFormatting: the emitted TypeScript is already formatted the way Prettier's DEFAULT config formats it, so a `codegen` -> `prettier --write` -> `codegen --check` pipeline stays green. If your project uses a NON-default Prettier config (a different printWidth, trailingComma, or quote style), Prettier will reformat the generated files and `--check` will then fail: add the generated directory to `.prettierignore` and commit the raw emission instead.")
|
|
2351
2295
|
.argument("[workflow-key]", "Generate for a single workflow (defaults to every workflows/*.toml found)")
|
|
2352
|
-
.option("--app <app-id>", "App ID")
|
|
2353
|
-
.option("--dir <path>", "Config directory (overrides the auto-resolved per-env path)")
|
|
2354
|
-
.addOption(new Option("--sync-dir <path>", "Deprecated alias of --dir").hideHelp())
|
|
2355
2296
|
.option("-o, --output <dir>", "Output directory for the generated files (defaults to <config-dir>/workflows/generated/)")
|
|
2356
2297
|
.option("--lang <lang>", "Target language for the generated types: 'ts' (default) or 'swift'.", "ts")
|
|
2357
2298
|
.option("--check", "Exit non-zero if generated output is out of date (CI guard); does not write. Compares byte-for-byte, so the file on disk must match the emission exactly.")
|
|
@@ -2365,17 +2306,10 @@ Examples:
|
|
|
2365
2306
|
error(`Unknown --lang "${options.lang}". Use "ts" or "swift".`);
|
|
2366
2307
|
process.exit(1);
|
|
2367
2308
|
}
|
|
2368
|
-
// 1.
|
|
2369
|
-
//
|
|
2370
|
-
// --app overrides, resolves the active env
|
|
2371
|
-
// (--env → PRIMITIVE_ENV → defaultEnvironment → single-env), and
|
|
2372
|
-
// preserves the legacy per-app scan fallback in bare-dir mode.
|
|
2309
|
+
// 1. The single source workflows/ directory: the environment's, and
|
|
2310
|
+
// only ever the environment's (#1510, #3154).
|
|
2373
2311
|
const workflowsSourceDir = resolveCodegenSourceDir({
|
|
2374
2312
|
subdir: "workflows",
|
|
2375
|
-
options: {
|
|
2376
|
-
app: options.app,
|
|
2377
|
-
syncDir: resolveSyncDirOverride(options, "workflows codegen"),
|
|
2378
|
-
},
|
|
2379
2313
|
});
|
|
2380
2314
|
// 2. Collect the source .toml files (one per workflow), filtered to a
|
|
2381
2315
|
// single workflow when an argument is given. Match on the file stem;
|
|
@@ -2396,7 +2330,7 @@ Examples:
|
|
|
2396
2330
|
}
|
|
2397
2331
|
if (inputs.length === 0) {
|
|
2398
2332
|
error(workflowKey
|
|
2399
|
-
? `No workflows/${workflowKey}.toml found under
|
|
2333
|
+
? `No workflows/${workflowKey}.toml found under primitive/<env>/.`
|
|
2400
2334
|
: "No workflows/*.toml files found to generate from.");
|
|
2401
2335
|
process.exit(1);
|
|
2402
2336
|
}
|