@12ui/design 0.2.27 → 0.2.29
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 +141 -87
- package/SKILL.md +5 -5
- package/dist/branch-completion.d.ts.map +1 -1
- package/dist/branch-completion.js +37 -14
- package/dist/branch-completion.js.map +1 -1
- package/dist/branch-execution.d.ts.map +1 -1
- package/dist/branch-execution.js +28 -8
- package/dist/branch-execution.js.map +1 -1
- package/dist/branch-identity.d.ts +10 -4
- package/dist/branch-identity.d.ts.map +1 -1
- package/dist/branch-identity.js +9 -6
- package/dist/branch-identity.js.map +1 -1
- package/dist/branch-page-conversion.d.ts +9 -8
- package/dist/branch-page-conversion.d.ts.map +1 -1
- package/dist/branch-page-conversion.js +8 -2
- package/dist/branch-page-conversion.js.map +1 -1
- package/dist/branch-page-packaging.d.ts +31 -0
- package/dist/branch-page-packaging.d.ts.map +1 -0
- package/dist/branch-page-packaging.js +86 -0
- package/dist/branch-page-packaging.js.map +1 -0
- package/dist/branch-plan.d.ts +6 -0
- package/dist/branch-plan.d.ts.map +1 -1
- package/dist/branch-plan.js +6 -1
- package/dist/branch-plan.js.map +1 -1
- package/dist/branch-progress.d.ts +22 -0
- package/dist/branch-progress.d.ts.map +1 -1
- package/dist/branch-progress.js +33 -8
- package/dist/branch-progress.js.map +1 -1
- package/dist/branch-run-record.d.ts +9 -0
- package/dist/branch-run-record.d.ts.map +1 -1
- package/dist/branch-run-record.js.map +1 -1
- package/dist/branch-status.d.ts +2 -0
- package/dist/branch-status.d.ts.map +1 -1
- package/dist/branch-status.js +60 -15
- package/dist/branch-status.js.map +1 -1
- package/dist/branch-winner.d.ts +13 -15
- package/dist/branch-winner.d.ts.map +1 -1
- package/dist/branch-winner.js +25 -77
- package/dist/branch-winner.js.map +1 -1
- package/dist/cli-arguments.d.ts.map +1 -1
- package/dist/cli-arguments.js +1 -0
- package/dist/cli-arguments.js.map +1 -1
- package/dist/cli-auth-command.d.ts.map +1 -1
- package/dist/cli-auth-command.js +5 -0
- package/dist/cli-auth-command.js.map +1 -1
- package/dist/cli-auth-onboarding.d.ts +12 -0
- package/dist/cli-auth-onboarding.d.ts.map +1 -0
- package/dist/cli-auth-onboarding.js +21 -0
- package/dist/cli-auth-onboarding.js.map +1 -0
- package/dist/cli-branch-command.d.ts +14 -19
- package/dist/cli-branch-command.d.ts.map +1 -1
- package/dist/cli-branch-command.js +207 -137
- package/dist/cli-branch-command.js.map +1 -1
- package/dist/cli-capabilities.d.ts +16 -51
- package/dist/cli-capabilities.d.ts.map +1 -1
- package/dist/cli-capabilities.js +23 -26
- package/dist/cli-capabilities.js.map +1 -1
- package/dist/cli-cli-command.d.ts +3 -0
- package/dist/cli-cli-command.d.ts.map +1 -1
- package/dist/cli-cli-command.js +15 -3
- package/dist/cli-cli-command.js.map +1 -1
- package/dist/cli-conversion-derivation.d.ts +30 -0
- package/dist/cli-conversion-derivation.d.ts.map +1 -0
- package/dist/{cli-export-command.js → cli-conversion-derivation.js} +178 -110
- package/dist/cli-conversion-derivation.js.map +1 -0
- package/dist/cli-conversion-output-directory.d.ts +5 -0
- package/dist/cli-conversion-output-directory.d.ts.map +1 -0
- package/dist/{cli-export-output-directory.js → cli-conversion-output-directory.js} +10 -10
- package/dist/cli-conversion-output-directory.js.map +1 -0
- package/dist/cli-convert-command.d.ts +9 -0
- package/dist/cli-convert-command.d.ts.map +1 -1
- package/dist/cli-convert-command.js +528 -158
- package/dist/cli-convert-command.js.map +1 -1
- package/dist/cli-corpus-command.d.ts.map +1 -1
- package/dist/cli-corpus-command.js +77 -10
- package/dist/cli-corpus-command.js.map +1 -1
- package/dist/cli-corpus-reference-downloads.d.ts +5 -0
- package/dist/cli-corpus-reference-downloads.d.ts.map +1 -1
- package/dist/cli-corpus-reference-downloads.js +18 -7
- package/dist/cli-corpus-reference-downloads.js.map +1 -1
- package/dist/cli-corpus-run.d.ts +9 -0
- package/dist/cli-corpus-run.d.ts.map +1 -1
- package/dist/cli-corpus-run.js +18 -0
- package/dist/cli-corpus-run.js.map +1 -1
- package/dist/cli-detach.d.ts +12 -4
- package/dist/cli-detach.d.ts.map +1 -1
- package/dist/cli-detach.js +49 -17
- package/dist/cli-detach.js.map +1 -1
- package/dist/cli-draft-command.d.ts +44 -61
- package/dist/cli-draft-command.d.ts.map +1 -1
- package/dist/cli-draft-command.js +307 -180
- package/dist/cli-draft-command.js.map +1 -1
- package/dist/cli-help/conversion.d.ts +30 -0
- package/dist/cli-help/conversion.d.ts.map +1 -0
- package/dist/cli-help/conversion.js +55 -0
- package/dist/cli-help/conversion.js.map +1 -0
- package/dist/cli-help/design.d.ts +84 -0
- package/dist/cli-help/design.d.ts.map +1 -0
- package/dist/cli-help/design.js +152 -0
- package/dist/cli-help/design.js.map +1 -0
- package/dist/cli-help/index.d.ts +234 -0
- package/dist/cli-help/index.d.ts.map +1 -0
- package/dist/cli-help/index.js +32 -0
- package/dist/cli-help/index.js.map +1 -0
- package/dist/cli-help/meta.d.ts +24 -0
- package/dist/cli-help/meta.d.ts.map +1 -0
- package/dist/cli-help/meta.js +30 -0
- package/dist/cli-help/meta.js.map +1 -0
- package/dist/cli-help/render.d.ts +4 -0
- package/dist/cli-help/render.d.ts.map +1 -0
- package/dist/cli-help/render.js +28 -0
- package/dist/cli-help/render.js.map +1 -0
- package/dist/cli-help/setup.d.ts +93 -0
- package/dist/cli-help/setup.d.ts.map +1 -0
- package/dist/cli-help/setup.js +142 -0
- package/dist/cli-help/setup.js.map +1 -0
- package/dist/cli-help/types.d.ts +10 -0
- package/dist/cli-help/types.d.ts.map +1 -0
- package/dist/cli-help/types.js +2 -0
- package/dist/cli-help/types.js.map +1 -0
- package/dist/cli-next-command.d.ts +11 -8
- package/dist/cli-next-command.d.ts.map +1 -1
- package/dist/cli-next-command.js +288 -88
- package/dist/cli-next-command.js.map +1 -1
- package/dist/cli-output-paths.d.ts +2 -23
- package/dist/cli-output-paths.d.ts.map +1 -1
- package/dist/cli-output-paths.js +2 -36
- package/dist/cli-output-paths.js.map +1 -1
- package/dist/cli-package-command.d.ts +1 -0
- package/dist/cli-package-command.d.ts.map +1 -1
- package/dist/cli-package-command.js +107 -34
- package/dist/cli-package-command.js.map +1 -1
- package/dist/cli-pending-auth.d.ts +20 -0
- package/dist/cli-pending-auth.d.ts.map +1 -0
- package/dist/cli-pending-auth.js +160 -0
- package/dist/cli-pending-auth.js.map +1 -0
- package/dist/cli-progress.d.ts +256 -75
- package/dist/cli-progress.d.ts.map +1 -1
- package/dist/cli-progress.js +425 -98
- package/dist/cli-progress.js.map +1 -1
- package/dist/cli-review-command.d.ts +8 -0
- package/dist/cli-review-command.d.ts.map +1 -0
- package/dist/cli-review-command.js +71 -0
- package/dist/cli-review-command.js.map +1 -0
- package/dist/cli-run.d.ts +2 -0
- package/dist/cli-run.d.ts.map +1 -1
- package/dist/cli-run.js +62 -73
- package/dist/cli-run.js.map +1 -1
- package/dist/cli-skill-command.d.ts +3 -0
- package/dist/cli-skill-command.d.ts.map +1 -1
- package/dist/cli-skill-command.js +26 -3
- package/dist/cli-skill-command.js.map +1 -1
- package/dist/cli-usage.d.ts +17 -8
- package/dist/cli-usage.d.ts.map +1 -1
- package/dist/cli-usage.js +57 -40
- package/dist/cli-usage.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -2
- package/dist/config.js.map +1 -1
- package/dist/conversion-client.d.ts +4 -0
- package/dist/conversion-client.d.ts.map +1 -1
- package/dist/conversion-client.js +8 -1
- package/dist/conversion-client.js.map +1 -1
- package/dist/conversion-outputs.d.ts +11 -0
- package/dist/conversion-outputs.d.ts.map +1 -1
- package/dist/conversion-outputs.js +13 -1
- package/dist/conversion-outputs.js.map +1 -1
- package/dist/conversion-receipt.d.ts +1 -1
- package/dist/conversion-receipt.js +1 -1
- package/dist/conversion-recovery.d.ts +20 -0
- package/dist/conversion-recovery.d.ts.map +1 -0
- package/dist/conversion-recovery.js +61 -0
- package/dist/conversion-recovery.js.map +1 -0
- package/dist/conversion-status-contract.js +1 -1
- package/dist/conversion-status-contract.js.map +1 -1
- package/dist/credential-setup.d.ts +9 -1
- package/dist/credential-setup.d.ts.map +1 -1
- package/dist/credential-setup.js +13 -1
- package/dist/credential-setup.js.map +1 -1
- package/dist/draft-adoption.d.ts +9 -3
- package/dist/draft-adoption.d.ts.map +1 -1
- package/dist/draft-adoption.js +26 -41
- package/dist/draft-adoption.js.map +1 -1
- package/dist/draft-identity.d.ts +9 -12
- package/dist/draft-identity.d.ts.map +1 -1
- package/dist/draft-identity.js +0 -0
- package/dist/draft-identity.js.map +1 -1
- package/dist/draft-run.d.ts +9 -19
- package/dist/draft-run.d.ts.map +1 -1
- package/dist/draft-run.js +67 -95
- package/dist/draft-run.js.map +1 -1
- package/dist/draft-workspace.d.ts +26 -18
- package/dist/draft-workspace.d.ts.map +1 -1
- package/dist/draft-workspace.js +16 -5
- package/dist/draft-workspace.js.map +1 -1
- package/dist/hosted-draft-identity.d.ts +20 -0
- package/dist/hosted-draft-identity.d.ts.map +1 -0
- package/dist/hosted-draft-identity.js +30 -0
- package/dist/hosted-draft-identity.js.map +1 -0
- package/dist/hosted-draft-run.d.ts +60 -0
- package/dist/hosted-draft-run.d.ts.map +1 -0
- package/dist/hosted-draft-run.js +97 -0
- package/dist/hosted-draft-run.js.map +1 -0
- package/dist/legacy-codex-cleanup.d.ts +13 -0
- package/dist/legacy-codex-cleanup.d.ts.map +1 -1
- package/dist/legacy-codex-cleanup.js +83 -0
- package/dist/legacy-codex-cleanup.js.map +1 -1
- package/dist/legacy-skill-catalog.d.ts +2 -2
- package/dist/legacy-skill-catalog.d.ts.map +1 -1
- package/dist/legacy-skill-catalog.js +76 -5
- package/dist/legacy-skill-catalog.js.map +1 -1
- package/dist/login-auth.d.ts +38 -0
- package/dist/login-auth.d.ts.map +1 -1
- package/dist/login-auth.js +67 -16
- package/dist/login-auth.js.map +1 -1
- package/dist/mcp-tool-definitions.js +1 -1
- package/dist/mcp-tool-definitions.js.map +1 -1
- package/dist/next-target.d.ts +1 -4
- package/dist/next-target.d.ts.map +1 -1
- package/dist/next-target.js +5 -9
- package/dist/next-target.js.map +1 -1
- package/dist/next-wait-lease.d.ts +18 -0
- package/dist/next-wait-lease.d.ts.map +1 -0
- package/dist/next-wait-lease.js +143 -0
- package/dist/next-wait-lease.js.map +1 -0
- package/dist/next-wait-process.d.ts +17 -0
- package/dist/next-wait-process.d.ts.map +1 -0
- package/dist/next-wait-process.js +40 -0
- package/dist/next-wait-process.js.map +1 -0
- package/dist/package-client.d.ts +30 -0
- package/dist/package-client.d.ts.map +1 -1
- package/dist/package-client.js.map +1 -1
- package/dist/package-submission.d.ts +17 -0
- package/dist/package-submission.d.ts.map +1 -1
- package/dist/package-submission.js +13 -0
- package/dist/package-submission.js.map +1 -1
- package/dist/pending-auth-store.d.ts +15 -0
- package/dist/pending-auth-store.d.ts.map +1 -0
- package/dist/pending-auth-store.js +90 -0
- package/dist/pending-auth-store.js.map +1 -0
- package/dist/responsive-quality.d.ts +2 -2
- package/dist/responsive-quality.js +2 -2
- package/dist/review-discovery.d.ts +10 -0
- package/dist/review-discovery.d.ts.map +1 -0
- package/dist/review-discovery.js +381 -0
- package/dist/review-discovery.js.map +1 -0
- package/dist/review-edit-html.d.ts +6 -0
- package/dist/review-edit-html.d.ts.map +1 -0
- package/dist/review-edit-html.js +11 -0
- package/dist/review-edit-html.js.map +1 -0
- package/dist/review-edit-source.d.ts +22 -0
- package/dist/review-edit-source.d.ts.map +1 -0
- package/dist/review-edit-source.js +103 -0
- package/dist/review-edit-source.js.map +1 -0
- package/dist/review-edit.d.ts +15 -0
- package/dist/review-edit.d.ts.map +1 -0
- package/dist/review-edit.js +192 -0
- package/dist/review-edit.js.map +1 -0
- package/dist/review-layerdoc-diff.d.ts +7 -0
- package/dist/review-layerdoc-diff.d.ts.map +1 -0
- package/dist/review-layerdoc-diff.js +92 -0
- package/dist/review-layerdoc-diff.js.map +1 -0
- package/dist/review-page-assets.d.ts +3 -0
- package/dist/review-page-assets.d.ts.map +1 -0
- package/dist/review-page-assets.js +43 -0
- package/dist/review-page-assets.js.map +1 -0
- package/dist/review-page.d.ts +3 -0
- package/dist/review-page.d.ts.map +1 -0
- package/dist/review-page.js +237 -0
- package/dist/review-page.js.map +1 -0
- package/dist/review-pricing.d.ts +14 -0
- package/dist/review-pricing.d.ts.map +1 -0
- package/dist/review-pricing.js +23 -0
- package/dist/review-pricing.js.map +1 -0
- package/dist/review-server.d.ts +15 -0
- package/dist/review-server.d.ts.map +1 -0
- package/dist/review-server.js +204 -0
- package/dist/review-server.js.map +1 -0
- package/dist/review-store.d.ts +11 -0
- package/dist/review-store.d.ts.map +1 -0
- package/dist/review-store.js +96 -0
- package/dist/review-store.js.map +1 -0
- package/dist/review-types.d.ts +128 -0
- package/dist/review-types.d.ts.map +1 -0
- package/dist/review-types.js +2 -0
- package/dist/review-types.js.map +1 -0
- package/dist/run-journal-commands.d.ts.map +1 -1
- package/dist/run-journal-commands.js +34 -76
- package/dist/run-journal-commands.js.map +1 -1
- package/dist/run-journal-in-flight.d.ts +2 -2
- package/dist/run-journal-in-flight.d.ts.map +1 -1
- package/dist/run-journal-in-flight.js +0 -0
- package/dist/run-journal-in-flight.js.map +1 -1
- package/dist/skill-installer.d.ts +2 -2
- package/dist/skill-installer.d.ts.map +1 -1
- package/dist/skill-installer.js +2 -2
- package/dist/skill-installer.js.map +1 -1
- package/open-design.json +3 -3
- package/package.json +1 -1
- package/skills/12ui-design/SKILL.md +62 -0
- package/skills/12ui-design/agents/openai.yaml +6 -0
- package/skills/12ui-design/inspire.md +11 -0
- package/dist/cli-create-command.d.ts +0 -59
- package/dist/cli-create-command.d.ts.map +0 -1
- package/dist/cli-create-command.js +0 -354
- package/dist/cli-create-command.js.map +0 -1
- package/dist/cli-export-command.d.ts +0 -26
- package/dist/cli-export-command.d.ts.map +0 -1
- package/dist/cli-export-command.js.map +0 -1
- package/dist/cli-export-output-directory.d.ts +0 -5
- package/dist/cli-export-output-directory.d.ts.map +0 -1
- package/dist/cli-export-output-directory.js.map +0 -1
- package/dist/cli-image-batch-command.d.ts +0 -29
- package/dist/cli-image-batch-command.d.ts.map +0 -1
- package/dist/cli-image-batch-command.js +0 -236
- package/dist/cli-image-batch-command.js.map +0 -1
- package/dist/cli-image-batch-materialize.d.ts +0 -27
- package/dist/cli-image-batch-materialize.d.ts.map +0 -1
- package/dist/cli-image-batch-materialize.js +0 -41
- package/dist/cli-image-batch-materialize.js.map +0 -1
- package/dist/cli-image-batch-resume.d.ts +0 -36
- package/dist/cli-image-batch-resume.d.ts.map +0 -1
- package/dist/cli-image-batch-resume.js +0 -176
- package/dist/cli-image-batch-resume.js.map +0 -1
- package/dist/cli-image-command.d.ts +0 -10
- package/dist/cli-image-command.d.ts.map +0 -1
- package/dist/cli-image-command.js +0 -106
- package/dist/cli-image-command.js.map +0 -1
- package/dist/cli-select-command.d.ts +0 -16
- package/dist/cli-select-command.d.ts.map +0 -1
- package/dist/cli-select-command.js +0 -60
- package/dist/cli-select-command.js.map +0 -1
- package/dist/create-identity.d.ts +0 -25
- package/dist/create-identity.d.ts.map +0 -1
- package/dist/create-identity.js +0 -0
- package/dist/create-identity.js.map +0 -1
- package/dist/draft-prompts.d.ts +0 -35
- package/dist/draft-prompts.d.ts.map +0 -1
- package/dist/draft-prompts.js +0 -51
- package/dist/draft-prompts.js.map +0 -1
- package/dist/image-batch-status.d.ts +0 -42
- package/dist/image-batch-status.d.ts.map +0 -1
- package/dist/image-batch-status.js +0 -143
- package/dist/image-batch-status.js.map +0 -1
- package/dist/image-generation-batch-attempt.d.ts +0 -28
- package/dist/image-generation-batch-attempt.d.ts.map +0 -1
- package/dist/image-generation-batch-attempt.js +0 -48
- package/dist/image-generation-batch-attempt.js.map +0 -1
- package/dist/image-generation-batch-manifest.d.ts +0 -25
- package/dist/image-generation-batch-manifest.d.ts.map +0 -1
- package/dist/image-generation-batch-manifest.js +0 -97
- package/dist/image-generation-batch-manifest.js.map +0 -1
- package/dist/image-generation-completion.d.ts +0 -43
- package/dist/image-generation-completion.d.ts.map +0 -1
- package/dist/image-generation-completion.js +0 -54
- package/dist/image-generation-completion.js.map +0 -1
- package/dist/image-generation-error.d.ts +0 -3
- package/dist/image-generation-error.d.ts.map +0 -1
- package/dist/image-generation-error.js +0 -30
- package/dist/image-generation-error.js.map +0 -1
- package/dist/image-generation-evidence.d.ts +0 -43
- package/dist/image-generation-evidence.d.ts.map +0 -1
- package/dist/image-generation-evidence.js +0 -28
- package/dist/image-generation-evidence.js.map +0 -1
- package/dist/image-generation-fs.d.ts +0 -3
- package/dist/image-generation-fs.d.ts.map +0 -1
- package/dist/image-generation-fs.js +0 -23
- package/dist/image-generation-fs.js.map +0 -1
- package/dist/image-generation-output.d.ts +0 -3
- package/dist/image-generation-output.d.ts.map +0 -1
- package/dist/image-generation-output.js +0 -51
- package/dist/image-generation-output.js.map +0 -1
- package/dist/image-generation-request.d.ts +0 -43
- package/dist/image-generation-request.d.ts.map +0 -1
- package/dist/image-generation-request.js +0 -52
- package/dist/image-generation-request.js.map +0 -1
- package/dist/image-generation-resume.d.ts +0 -49
- package/dist/image-generation-resume.d.ts.map +0 -1
- package/dist/image-generation-resume.js +0 -96
- package/dist/image-generation-resume.js.map +0 -1
- package/dist/image-generation-run.d.ts +0 -46
- package/dist/image-generation-run.d.ts.map +0 -1
- package/dist/image-generation-run.js +0 -158
- package/dist/image-generation-run.js.map +0 -1
- package/dist/image-generation-staging.d.ts +0 -25
- package/dist/image-generation-staging.d.ts.map +0 -1
- package/dist/image-generation-staging.js +0 -80
- package/dist/image-generation-staging.js.map +0 -1
- package/dist/image-generation-usage.d.ts +0 -75
- package/dist/image-generation-usage.d.ts.map +0 -1
- package/dist/image-generation-usage.js +0 -219
- package/dist/image-generation-usage.js.map +0 -1
- package/dist/image-provider-preflight.d.ts +0 -21
- package/dist/image-provider-preflight.d.ts.map +0 -1
- package/dist/image-provider-preflight.js +0 -184
- package/dist/image-provider-preflight.js.map +0 -1
- package/dist/selection-record.d.ts +0 -97
- package/dist/selection-record.d.ts.map +0 -1
- package/dist/selection-record.js +0 -138
- package/dist/selection-record.js.map +0 -1
- package/skills/design/SKILL.md +0 -116
- package/skills/design/agents/openai.yaml +0 -8
- package/skills/design/assets/large-logo.svg +0 -3
- package/skills/design/assets/small-400px.png +0 -0
|
@@ -3,19 +3,21 @@ import { readFile, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { materializeConversionArtifacts } from './artifact-materializer.js';
|
|
5
5
|
import { booleanFlag, stringFlag } from './cli-arguments.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { prepareOutputDirectory, prepareOutputFile } from './cli-output-paths.js';
|
|
7
|
+
import { runConversionDerivation } from './cli-conversion-derivation.js';
|
|
8
|
+
import { CONVERSION_DURATION_HINTS, createLongRunningProgress, } from './cli-progress.js';
|
|
9
|
+
import { refuseUsage, usage, usageRefusal } from './cli-usage.js';
|
|
9
10
|
import { readConversionConfig } from './config.js';
|
|
10
11
|
import { TwelveUiConversionClient, } from './conversion-client.js';
|
|
11
12
|
import { isConversionModel } from './conversion-models.js';
|
|
12
|
-
import {
|
|
13
|
+
import { isCliConversionOutput, } from './conversion-outputs.js';
|
|
13
14
|
import { recordConvertedImageReceipt } from './conversion-receipt.js';
|
|
15
|
+
import { readConversionRecovery, writeConversionRecovery, } from './conversion-recovery.js';
|
|
14
16
|
import { isPendingConversionStatus, readConversionStatus, wrongConversionOutputRefusal, } from './conversion-status-contract.js';
|
|
15
17
|
import { normalizeOptionalIdempotencyKey } from './idempotency-key.js';
|
|
16
18
|
import { classifyLocalConversionInput, createInputForLocalFile, defaultConversionOutputPath, } from './local-conversion-input.js';
|
|
17
19
|
import { normalizeImageOutputWidth, parseImageOutputWidth, } from './image-output-width.js';
|
|
18
|
-
import {
|
|
20
|
+
import { resolveNextTarget } from './next-target.js';
|
|
19
21
|
import { isResponsiveConversionQuality, RESPONSIVE_CONVERSION_QUALITIES, } from './responsive-quality.js';
|
|
20
22
|
import { describeInFlightRecord, readInFlightRunJournal, } from './run-journal-in-flight.js';
|
|
21
23
|
/**
|
|
@@ -32,27 +34,6 @@ export const parseTimeoutMs = (value) => {
|
|
|
32
34
|
}
|
|
33
35
|
return Math.floor(timeoutMs);
|
|
34
36
|
};
|
|
35
|
-
const parseProjectProfileFlag = async (output, value) => {
|
|
36
|
-
if (!isProjectConversionOutput(output)) {
|
|
37
|
-
if (value !== undefined)
|
|
38
|
-
throw new Error('--profile is only valid for project outputs');
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
if (!value?.trim())
|
|
42
|
-
throw new Error(`--profile is required for ${output}`);
|
|
43
|
-
const trimmed = value.trim();
|
|
44
|
-
const source = trimmed.startsWith('{')
|
|
45
|
-
? trimmed
|
|
46
|
-
: await readFile(path.resolve(trimmed.startsWith('@') ? trimmed.slice(1) : trimmed), 'utf8');
|
|
47
|
-
let parsed;
|
|
48
|
-
try {
|
|
49
|
-
parsed = JSON.parse(source);
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
throw new Error(`--profile must contain valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
53
|
-
}
|
|
54
|
-
return parseConversionOutputProfile(output, parsed);
|
|
55
|
-
};
|
|
56
37
|
const downloadCompletedConversion = async (args) => {
|
|
57
38
|
const downloaded = await args.client.downloadResult(args.operation.id, args.output);
|
|
58
39
|
await writeFile(args.outFile, downloaded.bytes);
|
|
@@ -61,9 +42,47 @@ const downloadCompletedConversion = async (args) => {
|
|
|
61
42
|
id: args.operation.id,
|
|
62
43
|
output: args.output,
|
|
63
44
|
outFile: args.outFile,
|
|
64
|
-
|
|
45
|
+
// The artifact inventory lives in the on-disk manifest the materializer
|
|
46
|
+
// just wrote; the payload references it instead of inlining the array.
|
|
47
|
+
// The board's fused capture spent 243 of 257 lines printing the same 14
|
|
48
|
+
// artifacts twice — the manifest file already held every byte of it.
|
|
49
|
+
artifactManifest: {
|
|
50
|
+
conversionId: artifactManifest.conversionId,
|
|
51
|
+
operationExpiresAt: artifactManifest.operationExpiresAt,
|
|
52
|
+
manifestFile: artifactManifest.manifestFile,
|
|
53
|
+
artifactCount: artifactManifest.artifacts.length,
|
|
54
|
+
},
|
|
65
55
|
};
|
|
66
56
|
};
|
|
57
|
+
const reportConversion = (reporter, operation, detail) => {
|
|
58
|
+
reporter.update({
|
|
59
|
+
// A succeeded child can still be followed by local materialization or by
|
|
60
|
+
// another member of a fused request. Keep the overall line honest: the
|
|
61
|
+
// reporter owns terminality, while a child success means collection is
|
|
62
|
+
// beginning rather than `running | stage succeeded`.
|
|
63
|
+
stage: operation.status === 'succeeded'
|
|
64
|
+
? 'collecting'
|
|
65
|
+
: operation.progress?.stage ?? operation.status,
|
|
66
|
+
// The raw percent is deliberately NOT forwarded (owner, 2026-08-21):
|
|
67
|
+
// it is the measured stuck metric. The service's per-lane counters are
|
|
68
|
+
// the advancing signal behind every stale percent (`extracting layers
|
|
69
|
+
// 2%` held 45s on the board while the lanes moved); render them
|
|
70
|
+
// rather than discarding them.
|
|
71
|
+
...(operation.status !== 'succeeded' && operation.progress?.active?.length
|
|
72
|
+
? { lanes: operation.progress.active }
|
|
73
|
+
: {}),
|
|
74
|
+
...(operation.status !== 'succeeded' && operation.progress?.milestone
|
|
75
|
+
? { milestone: operation.progress.milestone }
|
|
76
|
+
: {}),
|
|
77
|
+
...(operation.status !== 'succeeded' && operation.progress?.stage_since
|
|
78
|
+
? { stageSince: operation.progress.stage_since }
|
|
79
|
+
: {}),
|
|
80
|
+
...(operation.status !== 'succeeded' && operation.progress?.attempt !== undefined
|
|
81
|
+
? { attempt: operation.progress.attempt }
|
|
82
|
+
: {}),
|
|
83
|
+
...(detail ? { detail } : {}),
|
|
84
|
+
});
|
|
85
|
+
};
|
|
67
86
|
/**
|
|
68
87
|
* A LayerDoc landed on disk and no page was written from it.
|
|
69
88
|
*
|
|
@@ -78,6 +97,20 @@ const downloadCompletedConversion = async (args) => {
|
|
|
78
97
|
export const layerDocPageAction = (outFile) => (`The document is written and no page was rendered from it. To render one:`
|
|
79
98
|
+ ` \`12ui convert ${outFile} --output html_fixed\`. A LayerDoc on disk is valid input for`
|
|
80
99
|
+ ' every output, so this derives the page rather than converting the image again.');
|
|
100
|
+
export const layerDocStateAction = (args) => {
|
|
101
|
+
const linked = args.linkedExport;
|
|
102
|
+
if (!linked)
|
|
103
|
+
return layerDocPageAction(args.outFile);
|
|
104
|
+
if (linked.status === 'succeeded') {
|
|
105
|
+
return `Responsive page already exported${linked.outFile ? `: ${linked.outFile}` : ''}`
|
|
106
|
+
+ ` (export ${linked.id}).`;
|
|
107
|
+
}
|
|
108
|
+
if (isPendingConversionStatus(linked.status)) {
|
|
109
|
+
return `Responsive page export ${linked.id} is ${linked.status};`
|
|
110
|
+
+ ' the original purchase is still working.';
|
|
111
|
+
}
|
|
112
|
+
return `Responsive page export ${linked.id} is ${linked.status}; no additional conversion was bought.`;
|
|
113
|
+
};
|
|
81
114
|
/**
|
|
82
115
|
* A conversion of these exact bytes is already running in this workspace.
|
|
83
116
|
*
|
|
@@ -105,30 +138,142 @@ export const secondConversionNotice = (args) => ('These exact bytes are already
|
|
|
105
138
|
+ ` Read it from any shell with \`12ui next ${args.workspace}\` — that costs nothing and does not`
|
|
106
139
|
+ ' wait on this command. Continuing starts a SECOND, independently paid conversion of the same'
|
|
107
140
|
+ ' image.');
|
|
108
|
-
/** The result JSON,
|
|
109
|
-
const conversionResultJson = (result) => JSON.stringify({
|
|
141
|
+
/** The result JSON, with guidance derived from the linked operation's real state. */
|
|
142
|
+
const conversionResultJson = (result, linkedExport) => JSON.stringify({
|
|
110
143
|
...result,
|
|
111
|
-
...(result.output === 'layerdoc'
|
|
144
|
+
...(result.output === 'layerdoc'
|
|
145
|
+
? { nextAction: layerDocStateAction({ outFile: result.outFile, ...(linkedExport ? { linkedExport } : {}) }) }
|
|
146
|
+
: {}),
|
|
112
147
|
}, null, 2);
|
|
113
|
-
|
|
114
|
-
|
|
148
|
+
/**
|
|
149
|
+
* stdout is the machine surface: exactly one JSON document, nothing else.
|
|
150
|
+
* Human summaries (paths, per-format states) live in the stderr terminal
|
|
151
|
+
* block, so an agent can parse stdout without stripping trailing prose.
|
|
152
|
+
*/
|
|
153
|
+
const writeResultWithSummary = (result) => {
|
|
154
|
+
console.log(JSON.stringify(result, null, 2));
|
|
155
|
+
};
|
|
156
|
+
const outputPathForRecovery = async (artifact, overrideDirectory) => prepareOutputFile(overrideDirectory
|
|
157
|
+
? path.join(overrideDirectory, path.basename(artifact.outFile))
|
|
158
|
+
: artifact.outFile);
|
|
159
|
+
const completedOperation = async (args) => {
|
|
160
|
+
const current = await args.client.getConversion(args.id);
|
|
161
|
+
args.onProgress?.(current);
|
|
162
|
+
return current.status === 'succeeded'
|
|
163
|
+
? current
|
|
164
|
+
: args.client.waitForConversion(current.id, {
|
|
165
|
+
expiresAt: current.expires_at,
|
|
166
|
+
timeoutMs: args.timeoutMs,
|
|
167
|
+
...(args.onProgress ? { onProgress: args.onProgress } : {}),
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
const recoverOriginalPurchase = async (args) => {
|
|
171
|
+
const overrideDirectory = args.outDir
|
|
172
|
+
? await prepareOutputDirectory(args.outDir)
|
|
173
|
+
: undefined;
|
|
174
|
+
const conversionOutFile = await outputPathForRecovery(args.record.conversion, overrideDirectory);
|
|
175
|
+
const linkedOutFile = args.record.linkedExport
|
|
176
|
+
? await outputPathForRecovery(args.record.linkedExport, overrideDirectory)
|
|
177
|
+
: undefined;
|
|
178
|
+
const conversion = await completedOperation({
|
|
179
|
+
client: args.client,
|
|
180
|
+
id: args.record.conversion.conversionId,
|
|
181
|
+
...(args.timeoutMs === undefined ? {} : { timeoutMs: args.timeoutMs }),
|
|
182
|
+
onProgress: (operation) => reportConversion(args.progress, operation, `recovering conversion ${args.record.conversion.conversionId}`),
|
|
183
|
+
});
|
|
184
|
+
if (conversion.output !== args.record.conversion.output) {
|
|
185
|
+
throw new Error(`Recovery record expects ${args.record.conversion.output}, but conversion ${conversion.id}`
|
|
186
|
+
+ ` produces ${conversion.output}.`);
|
|
187
|
+
}
|
|
188
|
+
const converted = await downloadCompletedConversion({
|
|
189
|
+
client: args.client,
|
|
190
|
+
operation: conversion,
|
|
191
|
+
output: args.record.conversion.output,
|
|
192
|
+
outFile: conversionOutFile,
|
|
193
|
+
});
|
|
194
|
+
let linkedResult;
|
|
195
|
+
let linkedOperation;
|
|
196
|
+
if (args.record.linkedExport && linkedOutFile) {
|
|
197
|
+
linkedOperation = await completedOperation({
|
|
198
|
+
client: args.client,
|
|
199
|
+
id: args.record.linkedExport.conversionId,
|
|
200
|
+
...(args.timeoutMs === undefined ? {} : { timeoutMs: args.timeoutMs }),
|
|
201
|
+
onProgress: (operation) => reportConversion(args.progress, operation, `recovering linked export ${args.record.linkedExport.conversionId}`),
|
|
202
|
+
});
|
|
203
|
+
if (linkedOperation.output !== args.record.linkedExport.output) {
|
|
204
|
+
throw new Error(`Recovery record expects ${args.record.linkedExport.output}, but linked conversion`
|
|
205
|
+
+ ` ${linkedOperation.id} produces ${linkedOperation.output}.`);
|
|
206
|
+
}
|
|
207
|
+
linkedResult = await downloadCompletedConversion({
|
|
208
|
+
client: args.client,
|
|
209
|
+
operation: linkedOperation,
|
|
210
|
+
output: args.record.linkedExport.output,
|
|
211
|
+
outFile: linkedOutFile,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const artifacts = [conversionOutFile, ...(linkedOutFile ? [linkedOutFile] : [])];
|
|
215
|
+
args.journal.note({ runId: conversion.id, artifacts, terminal: true });
|
|
216
|
+
const nextAction = conversion.output === 'layerdoc'
|
|
217
|
+
? layerDocStateAction({
|
|
218
|
+
outFile: conversionOutFile,
|
|
219
|
+
...(linkedOperation
|
|
220
|
+
? {
|
|
221
|
+
linkedExport: {
|
|
222
|
+
id: linkedOperation.id,
|
|
223
|
+
status: linkedOperation.status,
|
|
224
|
+
...(linkedOutFile ? { outFile: linkedOutFile } : {}),
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
: {}),
|
|
228
|
+
})
|
|
229
|
+
: undefined;
|
|
230
|
+
args.progress.finish('succeeded', {
|
|
231
|
+
artifacts: [
|
|
232
|
+
{
|
|
233
|
+
name: args.record.conversion.output,
|
|
234
|
+
state: 'recovered free',
|
|
235
|
+
path: conversionOutFile,
|
|
236
|
+
},
|
|
237
|
+
...(linkedOutFile
|
|
238
|
+
? [{ name: 'responsive html', state: 'recovered free', path: linkedOutFile }]
|
|
239
|
+
: []),
|
|
240
|
+
],
|
|
241
|
+
spend: 'nothing new — the original purchase was collected',
|
|
242
|
+
});
|
|
243
|
+
writeResultWithSummary({
|
|
244
|
+
...converted,
|
|
245
|
+
...(nextAction ? { nextAction } : {}),
|
|
246
|
+
...(linkedResult ? { export: { ...linkedResult, status: 'succeeded' } } : {}),
|
|
247
|
+
});
|
|
115
248
|
};
|
|
116
249
|
export const runConversionCommand = async (command, flags, journal) => {
|
|
117
250
|
const commandStartedAt = Date.now();
|
|
118
251
|
const verb = command[0];
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
252
|
+
if (verb === 'convert') {
|
|
253
|
+
const retiredFlags = [
|
|
254
|
+
'export', 'export-quality', 'export-out', 'out', 'profile',
|
|
255
|
+
'web-profile', 'app-profile', 'detach',
|
|
256
|
+
].filter((flag) => flags[flag] !== undefined);
|
|
257
|
+
if (retiredFlags.length > 0) {
|
|
258
|
+
throw new Error(`${retiredFlags.map((flag) => `--${flag}`).join(', ')} retired from 12ui convert.`
|
|
259
|
+
+ ' Use --output to name the result and --out-dir to name its directory.');
|
|
260
|
+
}
|
|
261
|
+
const target = command[1] ? await resolveNextTarget(command[1]) : null;
|
|
262
|
+
if (target?.kind === 'conversion') {
|
|
263
|
+
for (const flag of ['model', 'width']) {
|
|
264
|
+
if (flags[flag] !== undefined) {
|
|
265
|
+
throw new Error(`--${flag} applies to image input, not a conversion id`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const derived = await runConversionDerivation(target.conversionId, flags);
|
|
269
|
+
journal.note({
|
|
270
|
+
runId: target.conversionId,
|
|
271
|
+
artifacts: [derived.manifestPath, ...derived.results.map((result) => result.outFile)],
|
|
272
|
+
purchased: derived.results.map((result) => result.conversionId),
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
132
277
|
const timeoutMs = parseTimeoutMs(stringFlag(flags, 'timeout-ms'));
|
|
133
278
|
// Credentials resolve only after the invocation has proven usable: a usage
|
|
134
279
|
// refusal must never depend on having an API key. The deploy gate caught the
|
|
@@ -138,58 +283,189 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
138
283
|
apiKey: stringFlag(flags, 'api-key'),
|
|
139
284
|
}));
|
|
140
285
|
if (verb === 'resume') {
|
|
141
|
-
if (stringFlag(flags, '
|
|
142
|
-
|| stringFlag(flags, 'model') !== undefined
|
|
286
|
+
if (stringFlag(flags, 'model') !== undefined
|
|
143
287
|
|| stringFlag(flags, 'width') !== undefined
|
|
144
288
|
|| stringFlag(flags, 'responsive-quality') !== undefined
|
|
145
289
|
|| booleanFlag(flags, 'detach')) {
|
|
146
|
-
throw new Error('--
|
|
290
|
+
throw new Error('--model, --width, --responsive-quality, and --detach are not accepted by resume');
|
|
147
291
|
}
|
|
148
292
|
const conversionId = command[1]?.trim();
|
|
149
|
-
const outFile = stringFlag(flags, 'out');
|
|
150
293
|
if (!conversionId) {
|
|
151
294
|
refuseUsage({
|
|
152
|
-
reason: 'A resume collects one
|
|
295
|
+
reason: 'A resume collects one purchase already bought, and no conversion id was given.'
|
|
153
296
|
+ ' Every command that starts one prints it.',
|
|
154
297
|
code: 'cli_usage',
|
|
155
298
|
verb: ['resume'],
|
|
156
299
|
});
|
|
157
300
|
}
|
|
158
|
-
// File-only on purpose: a resume writes exactly one artifact, so there is
|
|
159
|
-
// nothing here to derive a name from the way `convert --out <dir>` does.
|
|
160
|
-
const resolvedOutFile = await prepareOutputFile(outFile || refuseUsage({
|
|
161
|
-
reason: 'A resume writes the collected result to a file, and --out was not given.',
|
|
162
|
-
code: 'cli_usage',
|
|
163
|
-
verb: ['resume'],
|
|
164
|
-
}));
|
|
165
301
|
const client = conversionClient();
|
|
166
|
-
const
|
|
167
|
-
|
|
302
|
+
const outputValue = stringFlag(flags, 'output');
|
|
303
|
+
const outFile = stringFlag(flags, 'out');
|
|
304
|
+
if (outputValue === undefined && outFile === undefined) {
|
|
305
|
+
const recovery = await readConversionRecovery(conversionId);
|
|
306
|
+
if (!recovery) {
|
|
307
|
+
throw usageRefusal({
|
|
308
|
+
reason: `No local recovery record was found for ${conversionId}. Bare resume works for`
|
|
309
|
+
+ ' purchases started by this CLI; use the power form below for an older or foreign id.',
|
|
310
|
+
code: 'resume_recovery_missing',
|
|
311
|
+
verb: ['resume'],
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
const progress = createLongRunningProgress({
|
|
315
|
+
label: `resume ${conversionId}`,
|
|
316
|
+
typicalSeconds: recovery.linkedExport
|
|
317
|
+
? CONVERSION_DURATION_HINTS.fused
|
|
318
|
+
: CONVERSION_DURATION_HINTS.convert,
|
|
319
|
+
quiet: booleanFlag(flags, 'quiet'),
|
|
320
|
+
});
|
|
321
|
+
// A resume collects work already bought. Settled work arrives in
|
|
322
|
+
// seconds, so no expectation is quoted (the board's bare resume quoted
|
|
323
|
+
// ~5m for a 4s collection); only work still running server-side waits.
|
|
324
|
+
// The done paths honor --out-dir: the v2 board caught the brief quoting
|
|
325
|
+
// the record's original directory while the artifacts landed elsewhere.
|
|
326
|
+
const overrideDir = stringFlag(flags, 'out-dir');
|
|
327
|
+
const shownPath = (file) => (overrideDir
|
|
328
|
+
? path.join(path.resolve(overrideDir), path.basename(file))
|
|
329
|
+
: file);
|
|
330
|
+
progress.brief({
|
|
331
|
+
request: `resume ${conversionId}: collect the original purchase`,
|
|
332
|
+
free: 'everything already settled server-side is recovered without buying again',
|
|
333
|
+
done: recovery.linkedExport
|
|
334
|
+
? `${shownPath(recovery.conversion.outFile)} + ${shownPath(recovery.linkedExport.outFile)}`
|
|
335
|
+
: shownPath(recovery.conversion.outFile),
|
|
336
|
+
blocking: true,
|
|
337
|
+
});
|
|
338
|
+
progress.update({ stage: 'prepare', detail: 'reading the original purchase' });
|
|
339
|
+
try {
|
|
340
|
+
await recoverOriginalPurchase({
|
|
341
|
+
client,
|
|
342
|
+
record: recovery,
|
|
343
|
+
journal,
|
|
344
|
+
progress,
|
|
345
|
+
...(stringFlag(flags, 'out-dir') ? { outDir: stringFlag(flags, 'out-dir') } : {}),
|
|
346
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
progress.finish('stopped', {
|
|
351
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
352
|
+
next: `re-run 12ui resume ${conversionId}; collection is free until the purchase expires`,
|
|
353
|
+
});
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (outputValue === undefined || outFile === undefined) {
|
|
359
|
+
throw usageRefusal({
|
|
360
|
+
reason: 'The optional power form needs both --output and --out; omit both to recover the'
|
|
361
|
+
+ ' original purchase and filenames.',
|
|
362
|
+
code: 'resume_power_form_incomplete',
|
|
363
|
+
verb: ['resume'],
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (stringFlag(flags, 'out-dir') !== undefined) {
|
|
367
|
+
throw new Error('--out-dir overrides original filenames only on bare resume; power resume uses --out');
|
|
368
|
+
}
|
|
369
|
+
const requestedOutput = isCliConversionOutput(outputValue)
|
|
370
|
+
? outputValue
|
|
371
|
+
: refuseUsage({
|
|
372
|
+
reason: `\`${outputValue}\` is not one of the outputs this CLI produces.`,
|
|
373
|
+
code: 'cli_usage',
|
|
374
|
+
verb: ['resume'],
|
|
375
|
+
});
|
|
376
|
+
const resolvedOutFile = await prepareOutputFile(outFile);
|
|
377
|
+
const progress = createLongRunningProgress({
|
|
378
|
+
label: `resume ${conversionId}`,
|
|
379
|
+
typicalSeconds: requestedOutput === 'html'
|
|
380
|
+
? CONVERSION_DURATION_HINTS.export
|
|
381
|
+
: CONVERSION_DURATION_HINTS.convert,
|
|
382
|
+
quiet: booleanFlag(flags, 'quiet'),
|
|
383
|
+
});
|
|
384
|
+
progress.brief({
|
|
385
|
+
request: `resume ${conversionId}: collect ${requestedOutput}`,
|
|
386
|
+
free: 'a settled purchase is recovered without buying again',
|
|
387
|
+
done: resolvedOutFile,
|
|
388
|
+
blocking: true,
|
|
389
|
+
});
|
|
390
|
+
progress.update({ stage: 'prepare', detail: 'reading the existing purchase' });
|
|
391
|
+
const current = await client.getConversion(conversionId).catch((error) => {
|
|
392
|
+
progress.finish('stopped', {
|
|
393
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
394
|
+
});
|
|
395
|
+
throw error;
|
|
396
|
+
});
|
|
397
|
+
if (current.output !== requestedOutput) {
|
|
398
|
+
progress.finish('stopped', {
|
|
399
|
+
detail: `purchase produces ${current.output}, not ${requestedOutput}`,
|
|
400
|
+
});
|
|
168
401
|
// The refusal is written from an object that carries the id the caller
|
|
169
402
|
// actually wants, so it names both rather than only the unusable one.
|
|
170
403
|
throw new Error(wrongConversionOutputRefusal({
|
|
171
404
|
operation: current,
|
|
172
|
-
requested:
|
|
405
|
+
requested: requestedOutput,
|
|
173
406
|
collect: (id, kind) => `12ui resume ${id} --output ${kind} --out <file>`,
|
|
174
407
|
}));
|
|
175
408
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
409
|
+
reportConversion(progress, current, `collecting ${requestedOutput}`);
|
|
410
|
+
let completed;
|
|
411
|
+
try {
|
|
412
|
+
completed = current.status === 'succeeded'
|
|
413
|
+
? current
|
|
414
|
+
: await client.waitForConversion(current.id, {
|
|
415
|
+
expiresAt: current.expires_at,
|
|
416
|
+
timeoutMs,
|
|
417
|
+
onProgress: (operation) => reportConversion(progress, operation, `collecting ${requestedOutput}`),
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
progress.finish('stopped', {
|
|
422
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
423
|
+
next: `re-run 12ui resume ${conversionId} --output ${requestedOutput} --out ${resolvedOutFile};`
|
|
424
|
+
+ ' collection is free until the purchase expires',
|
|
181
425
|
});
|
|
182
|
-
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
const downloaded = await downloadCompletedConversion({
|
|
183
429
|
client,
|
|
184
430
|
operation: completed,
|
|
185
|
-
output,
|
|
431
|
+
output: requestedOutput,
|
|
186
432
|
outFile: resolvedOutFile,
|
|
187
433
|
});
|
|
188
434
|
journal.note({ runId: completed.id, artifacts: [resolvedOutFile] });
|
|
435
|
+
let linkedExport;
|
|
436
|
+
if (completed.output === 'layerdoc' && completed.export?.conversion_id) {
|
|
437
|
+
const linked = await client.getConversion(completed.export.conversion_id);
|
|
438
|
+
linkedExport = { id: linked.id, status: linked.status };
|
|
439
|
+
}
|
|
440
|
+
progress.finish('succeeded', {
|
|
441
|
+
artifacts: [{ name: requestedOutput, state: 'recovered free', path: resolvedOutFile }],
|
|
442
|
+
spend: 'nothing new — the existing purchase was collected',
|
|
443
|
+
});
|
|
444
|
+
writeResultWithSummary({
|
|
445
|
+
...downloaded,
|
|
446
|
+
...(downloaded.output === 'layerdoc'
|
|
447
|
+
? {
|
|
448
|
+
nextAction: layerDocStateAction({
|
|
449
|
+
outFile: downloaded.outFile,
|
|
450
|
+
...(linkedExport ? { linkedExport } : {}),
|
|
451
|
+
}),
|
|
452
|
+
}
|
|
453
|
+
: {}),
|
|
454
|
+
});
|
|
189
455
|
return;
|
|
190
456
|
}
|
|
191
457
|
if (verb !== 'convert')
|
|
192
458
|
usage();
|
|
459
|
+
const outputValue = stringFlag(flags, 'output');
|
|
460
|
+
const requestedOutput = isCliConversionOutput(outputValue)
|
|
461
|
+
? outputValue
|
|
462
|
+
: refuseUsage({
|
|
463
|
+
reason: outputValue === undefined
|
|
464
|
+
? 'A conversion produces one named format, and --output was not given.'
|
|
465
|
+
: `\`${outputValue}\` is not one of the outputs this CLI produces.`,
|
|
466
|
+
code: 'cli_usage',
|
|
467
|
+
verb: ['convert'],
|
|
468
|
+
});
|
|
193
469
|
if (!command[1]) {
|
|
194
470
|
refuseUsage({
|
|
195
471
|
reason: 'A conversion starts from one image or one LayerDoc on disk, and no input was named.',
|
|
@@ -211,9 +487,10 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
211
487
|
if (responsiveValue !== undefined && !isResponsiveConversionQuality(responsiveValue)) {
|
|
212
488
|
throw new Error(`--responsive-quality must be one of: ${RESPONSIVE_CONVERSION_QUALITIES.join(', ')}`);
|
|
213
489
|
}
|
|
214
|
-
const profile = await parseProjectProfileFlag(output, stringFlag(flags, 'profile'));
|
|
215
490
|
const inputPath = path.resolve(command[1]);
|
|
216
491
|
const localInput = classifyLocalConversionInput(inputPath);
|
|
492
|
+
const fusedHtml = localInput.kind === 'image' && requestedOutput === 'html';
|
|
493
|
+
const output = fusedHtml ? 'layerdoc' : requestedOutput;
|
|
217
494
|
const outputWidth = parseImageOutputWidth(stringFlag(flags, 'width'));
|
|
218
495
|
if (outputWidth !== undefined && localInput.kind === 'layerdoc') {
|
|
219
496
|
throw new Error('--width is only valid for image input');
|
|
@@ -230,7 +507,6 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
230
507
|
bytes: inputBytes,
|
|
231
508
|
filePath: inputPath,
|
|
232
509
|
output,
|
|
233
|
-
...(profile ? { profile } : {}),
|
|
234
510
|
});
|
|
235
511
|
const idempotencyKey = normalizeOptionalIdempotencyKey(stringFlag(flags, 'idempotency-key'), '--idempotency-key');
|
|
236
512
|
if (input.layerdoc !== undefined && model)
|
|
@@ -238,67 +514,48 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
238
514
|
if (input.layerdoc !== undefined && responsiveValue) {
|
|
239
515
|
throw new Error('--responsive-quality with LayerDoc input requires the SDK source-conversion workflow');
|
|
240
516
|
}
|
|
241
|
-
if (responsiveValue &&
|
|
517
|
+
if (responsiveValue && requestedOutput !== 'html') {
|
|
242
518
|
throw new Error('--responsive-quality is only valid with --output html');
|
|
243
519
|
}
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (exportValue !== undefined && exportValue !== 'html') {
|
|
249
|
-
throw new Error('--export must be html');
|
|
250
|
-
}
|
|
251
|
-
const exportQualityValue = stringFlag(flags, 'export-quality');
|
|
252
|
-
if (exportQualityValue !== undefined && !isResponsiveConversionQuality(exportQualityValue)) {
|
|
253
|
-
throw new Error(`--export-quality must be one of: ${RESPONSIVE_CONVERSION_QUALITIES.join(', ')}`);
|
|
254
|
-
}
|
|
255
|
-
if (exportQualityValue !== undefined && exportValue === undefined) {
|
|
256
|
-
throw new Error('--export-quality requires --export html');
|
|
257
|
-
}
|
|
258
|
-
const exportOutValue = stringFlag(flags, 'export-out');
|
|
259
|
-
if (exportOutValue !== undefined && exportValue === undefined) {
|
|
260
|
-
throw new Error('--export-out requires --export html');
|
|
261
|
-
}
|
|
262
|
-
if (exportValue !== undefined) {
|
|
263
|
-
if (input.layerdoc !== undefined)
|
|
264
|
-
throw new Error('--export requires image input');
|
|
265
|
-
if (output !== 'layerdoc')
|
|
266
|
-
throw new Error('--export requires --output layerdoc');
|
|
267
|
-
}
|
|
268
|
-
const exportHtml = exportValue === 'html'
|
|
269
|
-
? { ...(exportQualityValue ? { responsiveQuality: exportQualityValue } : {}) }
|
|
520
|
+
// Owner-facing `--output html` maps to the existing v1 fused wire shape.
|
|
521
|
+
// The API remains output=layerdoc + exportHtml; only the CLI vocabulary moves.
|
|
522
|
+
const exportHtml = fusedHtml
|
|
523
|
+
? { ...(responsiveValue ? { responsiveQuality: responsiveValue } : {}) }
|
|
270
524
|
: undefined;
|
|
271
525
|
const conversionInput = input.layerdoc !== undefined
|
|
272
526
|
? input
|
|
273
527
|
: {
|
|
274
528
|
...input,
|
|
275
529
|
...(model ? { model } : {}),
|
|
276
|
-
...(responsiveValue ? { responsiveQuality: responsiveValue } : {}),
|
|
530
|
+
...(!fusedHtml && responsiveValue ? { responsiveQuality: responsiveValue } : {}),
|
|
277
531
|
...(exportHtml ? { exportHtml } : {}),
|
|
278
532
|
};
|
|
279
|
-
const detach = booleanFlag(flags, 'detach');
|
|
280
533
|
const quiet = booleanFlag(flags, 'quiet');
|
|
281
534
|
// Both destinations are made writable BEFORE the conversion is bought. The
|
|
282
535
|
// paid call used to move first, so a missing parent directory lost the
|
|
283
536
|
// settled document, its export, and the journal line that recorded the
|
|
284
537
|
// purchase. See cli-output-paths.ts.
|
|
285
538
|
//
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
: await prepareOutputFile(defaultConversionOutputPath(inputPath, output));
|
|
539
|
+
// Convert has one directory spelling. Filenames are always derived from the
|
|
540
|
+
// input, so fused output cannot split a file flag and a directory flag again.
|
|
541
|
+
const outDirectory = stringFlag(flags, 'out-dir')
|
|
542
|
+
? await prepareOutputDirectory(stringFlag(flags, 'out-dir'))
|
|
543
|
+
: path.dirname(inputPath);
|
|
544
|
+
const outFile = await prepareOutputFile(path.join(outDirectory, path.basename(defaultConversionOutputPath(inputPath, output))));
|
|
293
545
|
const exportOutFile = exportHtml
|
|
294
|
-
? await prepareOutputFile(
|
|
295
|
-
?? path.join(path.dirname(outFile), path.basename(defaultConversionOutputPath(inputPath, 'html'))))
|
|
546
|
+
? await prepareOutputFile(path.join(outDirectory, path.basename(defaultConversionOutputPath(inputPath, 'html'))))
|
|
296
547
|
: null;
|
|
297
548
|
// Everything below happens BEFORE the paid dispatch, in the workspace the
|
|
298
549
|
// artifacts land in — which is where this command's journal lives, so a
|
|
299
550
|
// second shell reading it is reading the same file.
|
|
300
551
|
const workspace = path.dirname(outFile);
|
|
301
|
-
|
|
552
|
+
// A fused run stays on the fused median even at --model fast: its wall is
|
|
553
|
+
// anchor-dominated, not extraction-dominated (measured 1m53-5m6 fast).
|
|
554
|
+
const typicalSeconds = exportHtml
|
|
555
|
+
? CONVERSION_DURATION_HINTS.fused
|
|
556
|
+
: model === 'fast'
|
|
557
|
+
? CONVERSION_DURATION_HINTS.convertFast
|
|
558
|
+
: CONVERSION_DURATION_HINTS.convert;
|
|
302
559
|
const sourceSha256 = createHash('sha256').update(inputBytes).digest('hex');
|
|
303
560
|
journal.note({
|
|
304
561
|
sourceSha256,
|
|
@@ -321,52 +578,75 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
321
578
|
elapsedSeconds: (Date.now() - commandStartedAt) / 1000,
|
|
322
579
|
typicalSeconds,
|
|
323
580
|
});
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
581
|
+
const progress = createLongRunningProgress({
|
|
582
|
+
label: exportHtml ? 'convert (image + responsive HTML)' : 'convert',
|
|
583
|
+
typicalSeconds,
|
|
584
|
+
quiet,
|
|
585
|
+
heartbeat,
|
|
586
|
+
});
|
|
587
|
+
progress.brief({
|
|
588
|
+
request: `convert ${path.basename(inputPath)} -> ${exportHtml
|
|
589
|
+
? 'layerdoc + responsive html (one fused purchase)'
|
|
590
|
+
: requestedOutput}`,
|
|
591
|
+
paid: input.layerdoc !== undefined
|
|
592
|
+
? 'one derived conversion from the LayerDoc on disk'
|
|
593
|
+
: `1 ${model ?? 'standard'} conversion${exportHtml ? ' + 1 responsive export' : ''}`,
|
|
594
|
+
done: exportOutFile ? `${outFile} + ${exportOutFile}` : outFile,
|
|
595
|
+
expectation: {
|
|
596
|
+
typicalSeconds,
|
|
597
|
+
basis: `measured median, ${model ?? 'standard'} model${exportHtml ? ', fused' : ''}`,
|
|
598
|
+
},
|
|
599
|
+
blocking: true,
|
|
329
600
|
});
|
|
601
|
+
progress.update({ stage: 'dispatching' });
|
|
602
|
+
const client = conversionClient();
|
|
603
|
+
let created;
|
|
604
|
+
try {
|
|
605
|
+
created = await client.createConversion({
|
|
606
|
+
...conversionInput,
|
|
607
|
+
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
608
|
+
waitSeconds: 20,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
catch (error) {
|
|
612
|
+
progress.finish('failed', {
|
|
613
|
+
detail: `the paid dispatch itself failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
614
|
+
});
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
330
617
|
journal.note({
|
|
331
618
|
runId: created.id,
|
|
332
619
|
purchased: [created.id, ...(created.export?.conversion_id ? [created.export.conversion_id] : [])],
|
|
333
620
|
});
|
|
334
|
-
if (detach) {
|
|
335
|
-
const resumeCommand = `12ui resume ${created.id} --output ${output} --out <file>`;
|
|
336
|
-
console.log(JSON.stringify({
|
|
337
|
-
id: created.id,
|
|
338
|
-
status: created.status,
|
|
339
|
-
output: created.output,
|
|
340
|
-
...(created.export ? { export: created.export } : {}),
|
|
341
|
-
expiresAt: created.expires_at,
|
|
342
|
-
// A detached operation is the one case with nothing streaming, so the
|
|
343
|
-
// response has to say how long it takes and how to collect it.
|
|
344
|
-
nextAction: nextActionLine({
|
|
345
|
-
what: 'A conversion',
|
|
346
|
-
typicalSeconds: CONVERSION_DURATION_HINTS[created.export ? 'fused' : 'convert'],
|
|
347
|
-
statusCommand: resumeCommand,
|
|
348
|
-
waitHint: 'which blocks until it finishes and writes the result',
|
|
349
|
-
}),
|
|
350
|
-
}, null, 2));
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
621
|
const exportOperationId = created.export?.conversion_id ?? null;
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
622
|
+
const recovery = {
|
|
623
|
+
version: 1,
|
|
624
|
+
createdAt: created.created_at,
|
|
625
|
+
expiresAt: created.expires_at,
|
|
626
|
+
conversion: { conversionId: created.id, output, outFile },
|
|
627
|
+
...(exportOperationId && exportOutFile
|
|
628
|
+
? {
|
|
629
|
+
linkedExport: {
|
|
630
|
+
conversionId: exportOperationId,
|
|
631
|
+
output: 'html',
|
|
632
|
+
outFile: exportOutFile,
|
|
633
|
+
},
|
|
634
|
+
}
|
|
635
|
+
: {}),
|
|
636
|
+
};
|
|
637
|
+
await writeConversionRecovery(recovery).catch((error) => {
|
|
638
|
+
if (!quiet) {
|
|
639
|
+
process.stderr.write(`Could not record bare-resume recovery for ${created.id}:`
|
|
640
|
+
+ ` ${error instanceof Error ? error.message : String(error)}.`
|
|
641
|
+
+ ` If interrupted, use \`12ui resume ${created.id} --output ${output} --out ${outFile}\`.\n`);
|
|
642
|
+
}
|
|
369
643
|
});
|
|
644
|
+
// Identity is said once, here, and again in the terminal block — never on
|
|
645
|
+
// ticks. The board's fused capture repeated both ids on 11 of 13 lines.
|
|
646
|
+
progress.note(`claimed conversion ${created.id}${exportOperationId
|
|
647
|
+
? `; its linked responsive export is ${exportOperationId}`
|
|
648
|
+
: ''}`);
|
|
649
|
+
reportConversion(progress, created);
|
|
370
650
|
let operation;
|
|
371
651
|
try {
|
|
372
652
|
operation = created.status === 'succeeded'
|
|
@@ -374,14 +654,26 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
374
654
|
: await client.waitForConversion(created.id, {
|
|
375
655
|
expiresAt: created.expires_at,
|
|
376
656
|
timeoutMs,
|
|
377
|
-
onProgress:
|
|
657
|
+
onProgress: (current) => { reportConversion(progress, current); },
|
|
378
658
|
});
|
|
379
659
|
}
|
|
380
660
|
catch (error) {
|
|
381
661
|
const detail = error instanceof Error ? error.message : String(error);
|
|
662
|
+
progress.finish('stopped', {
|
|
663
|
+
detail: `conversion ${created.id} did not settle: ${detail}`,
|
|
664
|
+
...(exportOperationId && exportOutFile
|
|
665
|
+
? {
|
|
666
|
+
artifacts: [
|
|
667
|
+
{ name: output, state: 'not collected' },
|
|
668
|
+
{ name: 'responsive html', state: 'unknown — the linked export was not read' },
|
|
669
|
+
],
|
|
670
|
+
next: `12ui resume ${created.id} recovers both halves without re-buying`,
|
|
671
|
+
}
|
|
672
|
+
: { next: `12ui resume ${created.id} recovers the purchase without re-buying` }),
|
|
673
|
+
});
|
|
382
674
|
throw new Error(`Conversion ${created.id} failed: ${detail}`, { cause: error });
|
|
383
675
|
}
|
|
384
|
-
|
|
676
|
+
reportConversion(progress, operation);
|
|
385
677
|
// The proof that pairs these exact bytes with the conversion just bought, so
|
|
386
678
|
// a later `12ui branch execute` from the same image attaches it instead of
|
|
387
679
|
// buying viewport 1 of its source page a second time. It goes to the per-user
|
|
@@ -399,6 +691,20 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
399
691
|
journal.note({ artifacts: [outFile] });
|
|
400
692
|
if (!exportOperationId || !exportOutFile) {
|
|
401
693
|
// No export ran, so a `layerdoc` result here IS a document with no page.
|
|
694
|
+
progress.finish('succeeded', {
|
|
695
|
+
artifacts: [{
|
|
696
|
+
name: output,
|
|
697
|
+
state: 'succeeded',
|
|
698
|
+
path: outFile,
|
|
699
|
+
...(result.artifactManifest.artifactCount > 0
|
|
700
|
+
? { note: `${result.artifactManifest.artifactCount} assets, manifest ${result.artifactManifest.manifestFile}` }
|
|
701
|
+
: {}),
|
|
702
|
+
}],
|
|
703
|
+
spend: input.layerdoc !== undefined
|
|
704
|
+
? 'one derived conversion purchased'
|
|
705
|
+
: `1 ${model ?? 'standard'} conversion purchased`,
|
|
706
|
+
next: `free replay: 12ui resume ${created.id}`,
|
|
707
|
+
});
|
|
402
708
|
console.log(conversionResultJson(result));
|
|
403
709
|
return;
|
|
404
710
|
}
|
|
@@ -406,21 +712,28 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
406
712
|
// running after the budget must not take it back: the two halves are
|
|
407
713
|
// separate operations and the conversion is the authoritative answer for its
|
|
408
714
|
// own half.
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
715
|
+
//
|
|
716
|
+
// The handoff is said in words: the fused purchase's second half has its
|
|
717
|
+
// own stages and its own percent starting at 0. Rendering it silently into
|
|
718
|
+
// the same line was the board's 99% -> 29% whiplash.
|
|
719
|
+
progress.beginScope({
|
|
720
|
+
name: 'export',
|
|
412
721
|
typicalSeconds: CONVERSION_DURATION_HINTS.export,
|
|
413
|
-
|
|
722
|
+
sentence: 'conversion finished and its document is on disk; now the linked responsive'
|
|
723
|
+
+ ' export (second half of this purchase) — it ran alongside the conversion, its'
|
|
724
|
+
+ ' own percent starts at 0, and it usually finishes well inside the ~4m a'
|
|
725
|
+
+ ' standalone export measures',
|
|
414
726
|
});
|
|
415
727
|
let exportResult = null;
|
|
728
|
+
let exportOperation = null;
|
|
416
729
|
let exportError = null;
|
|
417
730
|
try {
|
|
418
|
-
|
|
731
|
+
exportOperation = await client.waitForConversion(exportOperationId, {
|
|
419
732
|
expiresAt: created.expires_at,
|
|
420
733
|
timeoutMs,
|
|
421
|
-
onProgress:
|
|
734
|
+
onProgress: (current) => { reportConversion(progress, current); },
|
|
422
735
|
});
|
|
423
|
-
|
|
736
|
+
reportConversion(progress, exportOperation);
|
|
424
737
|
exportResult = await downloadCompletedConversion({
|
|
425
738
|
client,
|
|
426
739
|
operation: exportOperation,
|
|
@@ -440,8 +753,16 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
440
753
|
: await readConversionStatus(client, exportOperationId);
|
|
441
754
|
const pending = isPendingConversionStatus(exportStatus);
|
|
442
755
|
const collect = `12ui resume ${exportOperationId} --output html --out <file>`;
|
|
443
|
-
|
|
756
|
+
const report = {
|
|
444
757
|
...result,
|
|
758
|
+
nextAction: layerDocStateAction({
|
|
759
|
+
outFile,
|
|
760
|
+
linkedExport: {
|
|
761
|
+
id: exportOperationId,
|
|
762
|
+
status: exportResult ? 'succeeded' : exportStatus,
|
|
763
|
+
...(exportResult ? { outFile: exportOutFile } : {}),
|
|
764
|
+
},
|
|
765
|
+
}),
|
|
445
766
|
export: exportResult
|
|
446
767
|
? { ...exportResult, status: 'succeeded' }
|
|
447
768
|
: {
|
|
@@ -450,7 +771,56 @@ export const runConversionCommand = async (command, flags, journal) => {
|
|
|
450
771
|
status: exportStatus,
|
|
451
772
|
...(pending ? { nextAction: collect } : { error: exportError }),
|
|
452
773
|
},
|
|
453
|
-
}
|
|
774
|
+
};
|
|
775
|
+
const layerdocRow = {
|
|
776
|
+
name: 'layerdoc',
|
|
777
|
+
state: 'succeeded',
|
|
778
|
+
path: outFile,
|
|
779
|
+
};
|
|
780
|
+
const spendLine = `1 ${model ?? 'standard'} conversion + 1 responsive export purchased`;
|
|
781
|
+
if (exportResult) {
|
|
782
|
+
progress.finish('succeeded', {
|
|
783
|
+
artifacts: [
|
|
784
|
+
layerdocRow,
|
|
785
|
+
{ name: 'responsive html', state: 'succeeded', path: exportOutFile },
|
|
786
|
+
],
|
|
787
|
+
spend: spendLine,
|
|
788
|
+
next: `free replay: 12ui resume ${created.id}`,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
else if (pending) {
|
|
792
|
+
// Terminal for this command, NOT for the purchase: the block must not
|
|
793
|
+
// look final while a paid format is live server-side.
|
|
794
|
+
progress.finish('deadline', {
|
|
795
|
+
detail: 'client wait ended; the paid export continues server-side',
|
|
796
|
+
artifacts: [
|
|
797
|
+
layerdocRow,
|
|
798
|
+
{
|
|
799
|
+
name: 'responsive html',
|
|
800
|
+
state: `still running server-side (${exportStatus})`,
|
|
801
|
+
note: `collect free with: ${collect}`,
|
|
802
|
+
},
|
|
803
|
+
],
|
|
804
|
+
spend: spendLine,
|
|
805
|
+
next: `the purchase stays collectable until ${created.expires_at}`,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
progress.finish('failed', {
|
|
810
|
+
detail: `the linked responsive export ${exportOperationId} ${exportStatus}`,
|
|
811
|
+
artifacts: [
|
|
812
|
+
layerdocRow,
|
|
813
|
+
{
|
|
814
|
+
name: 'responsive html',
|
|
815
|
+
state: exportStatus,
|
|
816
|
+
...(exportError ? { note: exportError } : {}),
|
|
817
|
+
},
|
|
818
|
+
],
|
|
819
|
+
spend: spendLine,
|
|
820
|
+
next: `render a fixed page free from the document: 12ui convert ${outFile} --output html_fixed`,
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
writeResultWithSummary(report);
|
|
454
824
|
if (!exportResult) {
|
|
455
825
|
throw new Error(pending
|
|
456
826
|
? `Conversion ${created.id} succeeded and was written to ${outFile}. Its responsive HTML`
|