@12ui/design 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +484 -0
- package/dist/artifact-materializer.d.ts +17 -0
- package/dist/artifact-materializer.d.ts.map +1 -0
- package/dist/artifact-materializer.js +66 -0
- package/dist/artifact-materializer.js.map +1 -0
- package/dist/cli-arguments.d.ts +8 -0
- package/dist/cli-arguments.d.ts.map +1 -0
- package/dist/cli-arguments.js +39 -0
- package/dist/cli-arguments.js.map +1 -0
- package/dist/cli-auth-command.d.ts +3 -0
- package/dist/cli-auth-command.d.ts.map +1 -0
- package/dist/cli-auth-command.js +100 -0
- package/dist/cli-auth-command.js.map +1 -0
- package/dist/cli-corpus-command.d.ts +12 -0
- package/dist/cli-corpus-command.d.ts.map +1 -0
- package/dist/cli-corpus-command.js +120 -0
- package/dist/cli-corpus-command.js.map +1 -0
- package/dist/cli-corpus-evidence.d.ts +17 -0
- package/dist/cli-corpus-evidence.d.ts.map +1 -0
- package/dist/cli-corpus-evidence.js +150 -0
- package/dist/cli-corpus-evidence.js.map +1 -0
- package/dist/cli-corpus-reference-downloads.d.ts +8 -0
- package/dist/cli-corpus-reference-downloads.d.ts.map +1 -0
- package/dist/cli-corpus-reference-downloads.js +111 -0
- package/dist/cli-corpus-reference-downloads.js.map +1 -0
- package/dist/cli-corpus-reference-receipts.d.ts +36 -0
- package/dist/cli-corpus-reference-receipts.d.ts.map +1 -0
- package/dist/cli-corpus-reference-receipts.js +137 -0
- package/dist/cli-corpus-reference-receipts.js.map +1 -0
- package/dist/cli-corpus-run.d.ts +17 -0
- package/dist/cli-corpus-run.d.ts.map +1 -0
- package/dist/cli-corpus-run.js +94 -0
- package/dist/cli-corpus-run.js.map +1 -0
- package/dist/cli-corpus-types.d.ts +52 -0
- package/dist/cli-corpus-types.d.ts.map +1 -0
- package/dist/cli-corpus-types.js +6 -0
- package/dist/cli-corpus-types.js.map +1 -0
- package/dist/cli-export-command.d.ts +3 -0
- package/dist/cli-export-command.d.ts.map +1 -0
- package/dist/cli-export-command.js +234 -0
- package/dist/cli-export-command.js.map +1 -0
- package/dist/cli-image-command.d.ts +8 -0
- package/dist/cli-image-command.d.ts.map +1 -0
- package/dist/cli-image-command.js +193 -0
- package/dist/cli-image-command.js.map +1 -0
- package/dist/cli-persistence.d.ts +25 -0
- package/dist/cli-persistence.d.ts.map +1 -0
- package/dist/cli-persistence.js +253 -0
- package/dist/cli-persistence.js.map +1 -0
- package/dist/cli-skill-command.d.ts +9 -0
- package/dist/cli-skill-command.d.ts.map +1 -0
- package/dist/cli-skill-command.js +215 -0
- package/dist/cli-skill-command.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +272 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-skill-config.d.ts +3 -0
- package/dist/codex-skill-config.d.ts.map +1 -0
- package/dist/codex-skill-config.js +83 -0
- package/dist/codex-skill-config.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -0
- package/dist/conversion-client.d.ts +264 -0
- package/dist/conversion-client.d.ts.map +1 -0
- package/dist/conversion-client.js +445 -0
- package/dist/conversion-client.js.map +1 -0
- package/dist/conversion-models.d.ts +4 -0
- package/dist/conversion-models.d.ts.map +1 -0
- package/dist/conversion-models.js +3 -0
- package/dist/conversion-models.js.map +1 -0
- package/dist/conversion-outputs.d.ts +118 -0
- package/dist/conversion-outputs.d.ts.map +1 -0
- package/dist/conversion-outputs.js +84 -0
- package/dist/conversion-outputs.js.map +1 -0
- package/dist/conversion-problems.d.ts +3 -0
- package/dist/conversion-problems.d.ts.map +1 -0
- package/dist/conversion-problems.js +21 -0
- package/dist/conversion-problems.js.map +1 -0
- package/dist/corpus-client.d.ts +171 -0
- package/dist/corpus-client.d.ts.map +1 -0
- package/dist/corpus-client.js +85 -0
- package/dist/corpus-client.js.map +1 -0
- package/dist/credential-setup.d.ts +27 -0
- package/dist/credential-setup.d.ts.map +1 -0
- package/dist/credential-setup.js +242 -0
- package/dist/credential-setup.js.map +1 -0
- package/dist/credential-store.d.ts +12 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +103 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/idempotency-key.d.ts +2 -0
- package/dist/idempotency-key.d.ts.map +1 -0
- package/dist/idempotency-key.js +19 -0
- package/dist/idempotency-key.js.map +1 -0
- package/dist/image-generation-evidence.d.ts +26 -0
- package/dist/image-generation-evidence.d.ts.map +1 -0
- package/dist/image-generation-evidence.js +28 -0
- package/dist/image-generation-evidence.js.map +1 -0
- package/dist/image-output-width.d.ts +11 -0
- package/dist/image-output-width.d.ts.map +1 -0
- package/dist/image-output-width.js +55 -0
- package/dist/image-output-width.js.map +1 -0
- package/dist/image-provider-preflight.d.ts +21 -0
- package/dist/image-provider-preflight.d.ts.map +1 -0
- package/dist/image-provider-preflight.js +184 -0
- package/dist/image-provider-preflight.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy-codex-cleanup.d.ts +11 -0
- package/dist/legacy-codex-cleanup.d.ts.map +1 -0
- package/dist/legacy-codex-cleanup.js +147 -0
- package/dist/legacy-codex-cleanup.js.map +1 -0
- package/dist/legacy-skill-catalog.d.ts +5 -0
- package/dist/legacy-skill-catalog.d.ts.map +1 -0
- package/dist/legacy-skill-catalog.js +123 -0
- package/dist/legacy-skill-catalog.js.map +1 -0
- package/dist/local-conversion-input.d.ts +21 -0
- package/dist/local-conversion-input.d.ts.map +1 -0
- package/dist/local-conversion-input.js +54 -0
- package/dist/local-conversion-input.js.map +1 -0
- package/dist/login-auth.d.ts +63 -0
- package/dist/login-auth.d.ts.map +1 -0
- package/dist/login-auth.js +282 -0
- package/dist/login-auth.js.map +1 -0
- package/dist/package-client.d.ts +147 -0
- package/dist/package-client.d.ts.map +1 -0
- package/dist/package-client.js +119 -0
- package/dist/package-client.js.map +1 -0
- package/dist/project-profiles.d.ts +45 -0
- package/dist/project-profiles.d.ts.map +1 -0
- package/dist/project-profiles.js +162 -0
- package/dist/project-profiles.js.map +1 -0
- package/dist/responsive-quality.d.ts +26 -0
- package/dist/responsive-quality.d.ts.map +1 -0
- package/dist/responsive-quality.js +68 -0
- package/dist/responsive-quality.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +173 -0
- package/dist/server.js.map +1 -0
- package/dist/skill-installer.d.ts +51 -0
- package/dist/skill-installer.d.ts.map +1 -0
- package/dist/skill-installer.js +328 -0
- package/dist/skill-installer.js.map +1 -0
- package/package.json +53 -0
- package/skills/design/SKILL.md +156 -0
- package/skills/design/agents/openai.yaml +6 -0
- package/skills/design/references/selection-contract.md +44 -0
- package/skills/design-convert/SKILL.md +118 -0
- package/skills/design-convert/agents/openai.yaml +6 -0
- package/skills/design-search/SKILL.md +86 -0
- package/skills/design-search/agents/openai.yaml +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# @12ui/design
|
|
2
|
+
|
|
3
|
+
`@12ui/design` is the canonical 12UI CLI, SDK, MCP server, and agent-skill
|
|
4
|
+
package. The `12ui` binary stays stable while package imports and installation
|
|
5
|
+
use the new name.
|
|
6
|
+
|
|
7
|
+
Install with Node on macOS, Linux, or Windows:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx -y @12ui/design skill install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or use the genuinely npm-free macOS/Linux installer:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
curl -fsSL https://12ui.com/install.sh | sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Both paths pin the exact CLI version, install `design`, `design-search`, and
|
|
20
|
+
`design-convert` into every detected Codex and Claude Code installation, and
|
|
21
|
+
open the 12UI device-approval page. The resulting user-owned credential has
|
|
22
|
+
`design.convert` and `design.corpus.retrieve`, is verified before use, and is
|
|
23
|
+
stored mode-0600 at `$XDG_CONFIG_HOME/12ui/credentials.json` or
|
|
24
|
+
`~/.config/12ui/credentials.json`.
|
|
25
|
+
|
|
26
|
+
An already verified credential is reused. The installer migrates the legacy
|
|
27
|
+
`~/.config/just-every/12ui/credentials.json` location; two conflicting files
|
|
28
|
+
fail closed. Existing unknown or locally modified skills also fail closed
|
|
29
|
+
unless `--force` is explicit. Use `--skill design-search` (or either other
|
|
30
|
+
skill name) to install one skill instead of the complete bundle.
|
|
31
|
+
|
|
32
|
+
## Three visual interface skills
|
|
33
|
+
|
|
34
|
+
- `design` routes UI, web, and mobile work. Finished screenshots go directly
|
|
35
|
+
to conversion, tiny edits stay code-only, and rough briefs retrieve exactly
|
|
36
|
+
four references, generate four candidates conditioned on all four, select
|
|
37
|
+
one, convert only the winner, integrate it, and verify the real surface.
|
|
38
|
+
- `design-search` returns a ranked, diverse set of real Design Corpus
|
|
39
|
+
references while preserving endpoint order and metrics.
|
|
40
|
+
- `design-convert` turns a finished PNG, JPEG, or WebP into LayerDoc and any
|
|
41
|
+
supported responsive, fixed, project, or document export.
|
|
42
|
+
|
|
43
|
+
The design workflow exists because code-first agents often converge on safe,
|
|
44
|
+
generic visual defaults. Corpus-conditioned image generation expands the
|
|
45
|
+
design space and introduces personality; converting the selected image then
|
|
46
|
+
preserves that direction with near-pixel-perfect fidelity much faster than
|
|
47
|
+
manual recreation.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
12ui skill status --json
|
|
51
|
+
12ui auth status
|
|
52
|
+
12ui corpus inspire --query-file ./brief.txt --out-dir ./references --count 4
|
|
53
|
+
12ui image generate --prompt-file ./candidate-1.txt \
|
|
54
|
+
--reference-1 ./references/01.webp \
|
|
55
|
+
--reference-2 ./references/02.webp \
|
|
56
|
+
--reference-3 ./references/03.webp \
|
|
57
|
+
--reference-4 ./references/04.webp \
|
|
58
|
+
--out ./candidate-1.png \
|
|
59
|
+
--aspect landscape \
|
|
60
|
+
--project-root . \
|
|
61
|
+
--provider auto \
|
|
62
|
+
--idempotency-key product-candidate-1
|
|
63
|
+
12ui export <base-layerdoc-conversion-id> \
|
|
64
|
+
--output html,pdf,psd,pptx,sketch,web_project \
|
|
65
|
+
--out-dir ./exports \
|
|
66
|
+
--web-profile ./web-profile.json \
|
|
67
|
+
--idempotency-key product-exports-v1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`image generate` resolves one provider before dispatch: authenticated Codex,
|
|
71
|
+
then `OPENAI_API_KEY` from the process or exactly `<project-root>/.env`. It
|
|
72
|
+
refuses a Git-tracked `.env`, never stores or prints the key, persists attempt
|
|
73
|
+
evidence, and never switches providers after dispatch. Choose `--aspect`
|
|
74
|
+
explicitly for the target interface; it defaults to `landscape` for
|
|
75
|
+
compatibility.
|
|
76
|
+
|
|
77
|
+
`export` downloads one successful base LayerDoc once and dispatches the chosen
|
|
78
|
+
formats in parallel. Project exports require exact web/native profiles; image
|
|
79
|
+
extraction is not repeated.
|
|
80
|
+
|
|
81
|
+
## Design Corpus retrieval
|
|
82
|
+
|
|
83
|
+
`TwelveUiCorpusClient` uses an API key with the `design.corpus.retrieve` scope.
|
|
84
|
+
Use `mode: 'record'` for product allocations so exposure history can prevent
|
|
85
|
+
the same references from dominating later runs. Use `mode: 'ignore'` only for
|
|
86
|
+
operator diagnostics and search inspection.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { TwelveUiCorpusClient } from '@12ui/design';
|
|
90
|
+
|
|
91
|
+
const corpus = new TwelveUiCorpusClient({
|
|
92
|
+
origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
|
|
93
|
+
apiKey: process.env.TWELVE_UI_API_KEY!,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const status = await corpus.status();
|
|
97
|
+
const retrieved = await corpus.retrieve({
|
|
98
|
+
scope: 'r-track',
|
|
99
|
+
queries: [{
|
|
100
|
+
id: 'home',
|
|
101
|
+
brief: 'Editorial architecture home page',
|
|
102
|
+
direction: 'warm materiality and asymmetric typography',
|
|
103
|
+
targetCount: 6,
|
|
104
|
+
}],
|
|
105
|
+
context: {
|
|
106
|
+
mode: 'record',
|
|
107
|
+
purpose: 'run',
|
|
108
|
+
exposureScope: 'project:example',
|
|
109
|
+
allocationKey: 'example-home-v1',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const first = retrieved.allocations[0]!.results[0]!;
|
|
114
|
+
const metadata = await corpus.reference(first.referenceId);
|
|
115
|
+
const image = await corpus.download(first.referenceId, 'ref');
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The client sends the allocation key as the idempotency key. The API also
|
|
119
|
+
supports `logo-track`, batched queries, exclusions, preselected references, and
|
|
120
|
+
minimum quality thresholds. See
|
|
121
|
+
[`docs/corpus-v1.openapi.yaml`](https://github.com/just-every/12ui/blob/main/docs/corpus-v1.openapi.yaml).
|
|
122
|
+
|
|
123
|
+
For agent workflows that need four fresh, budget-metered inspiration images,
|
|
124
|
+
the CLI calls `/api/v1/corpus/inspire`, downloads the full reference images in
|
|
125
|
+
parallel, verifies each WebP, and writes a content-hashed manifest:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
node "$TWELVE_UI_REPO/packages/12ui/dist/cli.js" corpus inspire \
|
|
129
|
+
--query-file ./brief.txt \
|
|
130
|
+
--count 4 \
|
|
131
|
+
--wildness 0.6 \
|
|
132
|
+
--idempotency-key design-run:home-v1 \
|
|
133
|
+
--out-dir ./references
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The output directory must not already exist. Before dispatch, the CLI writes
|
|
137
|
+
`inspire-attempt.json` with the exact request and stable idempotency key. A
|
|
138
|
+
successful run also contains `manifest.json`, `inspire-evidence.json` with the
|
|
139
|
+
exact upstream response, four numbered reference files, and a durable digest
|
|
140
|
+
receipt for each image under `.reference-receipts/`. If the HTTP result is
|
|
141
|
+
ambiguous or one or more image downloads fail, finish the same allocation
|
|
142
|
+
without a second paid embedding:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
node "$TWELVE_UI_REPO/packages/12ui/dist/cli.js" corpus resume \
|
|
146
|
+
--out-dir ./references \
|
|
147
|
+
--origin https://12ui.com
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`corpus resume` reuses the attempt's idempotency key. The Worker either returns
|
|
151
|
+
the original stored response or reports the still-pending request; it never
|
|
152
|
+
dispatches a second embedding for that identity. Reusing a key with a different
|
|
153
|
+
validated request returns `409 idempotency_conflict`. A reference already on
|
|
154
|
+
disk is accepted only when its bytes match its exclusive digest receipt.
|
|
155
|
+
|
|
156
|
+
The CLI deliberately does not accept a free-form `--kind`: an unverified value
|
|
157
|
+
can consume the metered request while producing an empty set. Use the SDK's
|
|
158
|
+
`filters.kind` only when an integration has obtained and verified the exact
|
|
159
|
+
corpus kind value.
|
|
160
|
+
|
|
161
|
+
## Multi-page packages
|
|
162
|
+
|
|
163
|
+
`TwelveUiConversionPackageClient` accepts the version-1 package manifest plus
|
|
164
|
+
explicit screenshot, LayerDoc, and raster-asset parts. It polls one durable
|
|
165
|
+
parent operation while the service converts missing viewports and exports final
|
|
166
|
+
pages in parallel.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { TwelveUiConversionPackageClient } from '@12ui/design';
|
|
170
|
+
|
|
171
|
+
const packages = new TwelveUiConversionPackageClient({
|
|
172
|
+
origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
|
|
173
|
+
apiKey: process.env.TWELVE_UI_API_KEY!,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const created = await packages.createPackage({
|
|
177
|
+
manifest: {
|
|
178
|
+
version: 1,
|
|
179
|
+
output: 'layerdoc',
|
|
180
|
+
pages: [{
|
|
181
|
+
id: 'home',
|
|
182
|
+
ordinal: 0,
|
|
183
|
+
viewports: [{ id: 'hero', ordinal: 0, screenshot_part: 'home-hero' }],
|
|
184
|
+
}],
|
|
185
|
+
},
|
|
186
|
+
screenshots: [{
|
|
187
|
+
partId: 'home-hero',
|
|
188
|
+
bytes: screenshotBytes,
|
|
189
|
+
mediaType: 'image/png',
|
|
190
|
+
}],
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const completed = created.status === 'succeeded'
|
|
194
|
+
? created
|
|
195
|
+
: await packages.waitForPackage(created.id);
|
|
196
|
+
const home = await packages.downloadPage(completed, 'home');
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
See [`docs/CONVERSION_PACKAGES.md`](https://github.com/just-every/12ui/blob/main/docs/CONVERSION_PACKAGES.md) for the
|
|
200
|
+
strict manifest, asset mapping, normalization, page-join, and limit contract.
|
|
201
|
+
|
|
202
|
+
## CLI
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
export TWELVE_UI_API_KEY=your-key
|
|
206
|
+
12ui convert ./screen.png --output layerdoc --out ./screen.layerdoc.json
|
|
207
|
+
12ui convert ./screen.png --output html --model pro --width 1440 --out ./screen.html --timeout-ms 7200000
|
|
208
|
+
12ui convert ./screen.layerdoc.json --output html --out ./screen.html --idempotency-key screen-html-v1
|
|
209
|
+
12ui convert ./screen.layerdoc.json --output pptx --out ./screen.pptx --idempotency-key screen-pptx-v1
|
|
210
|
+
12ui convert ./screen.layerdoc.json --output web_project --profile ./react-tailwind.json --out ./screen-react.zip
|
|
211
|
+
12ui convert ./screen.layerdoc.json --output app_project --profile '{"version":1,"framework":"swiftui","styling":"native","language":"swift","packaging":"project"}' --out ./screen-ios.zip
|
|
212
|
+
12ui resume conversion-id --output layerdoc --out ./screen.layerdoc.json
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Each conversion also writes a verified `<out>.assets/manifest.json` plus every
|
|
216
|
+
signed raster artifact beside the requested result. Set `TWELVE_UI_ORIGIN` to
|
|
217
|
+
override `https://12ui.com`; waits default to the operation expiry and can be
|
|
218
|
+
bounded explicitly with `--timeout-ms`.
|
|
219
|
+
|
|
220
|
+
To retry an ambiguous create request safely, reuse the same explicit
|
|
221
|
+
`--idempotency-key`. When it is omitted, the client generates a new UUID.
|
|
222
|
+
|
|
223
|
+
Image conversions accept `--model fast|standard|pro`; omission selects
|
|
224
|
+
`standard`. In `layerdoc-worker-v148`, Fast, Standard, and Pro all use
|
|
225
|
+
`gpt-5.6-terra-low` for primary extraction. Fast retains color-guided
|
|
226
|
+
deterministic inpainting, source-grounded flat-border cutouts, and 1x source crops without
|
|
227
|
+
secondary metadata refinement, generative cleanup, provider background
|
|
228
|
+
removal, or upscaling. Standard has no secondary metadata refinement and uses
|
|
229
|
+
one atomic GPT Image 2 result for each opaque clean target, with Pixelcut-first
|
|
230
|
+
alpha isolation and Bria admitted only after a durable hard-invalid or
|
|
231
|
+
reconciled terminal Pixelcut failure. Standard performs no Luna candidate
|
|
232
|
+
review. Pro retains a separate `gpt-5.6-terra-low` metadata-refinement call, a
|
|
233
|
+
three-sample atomic opaque-clean portfolio with one comparative Luna review,
|
|
234
|
+
and the complete revision-frozen FAL alpha portfolio. GPT Image 2 is opaque-only.
|
|
235
|
+
Provider-routed cutouts keep enhanced upscaling; accepted deterministic Fast
|
|
236
|
+
cutouts are resized locally. The option is not accepted for LayerDoc input
|
|
237
|
+
because downstream compilation is deterministic.
|
|
238
|
+
|
|
239
|
+
Use `--width <px>` to set the native output canvas width. The CLI resizes image
|
|
240
|
+
input proportionally before upload, upscaling or downscaling as needed. The
|
|
241
|
+
selected model may analyze a smaller internal raster without changing that
|
|
242
|
+
authored width; do not switch to Pro merely because the native canvas exceeds
|
|
243
|
+
Standard's analysis edge. For example, an 800x600 source with `--width 1000`
|
|
244
|
+
becomes a 1000x750 conversion canvas, and a 1536x1024 Standard source remains a
|
|
245
|
+
1536x1024 native canvas while analysis is bounded to 1500x1000. `--width 390`
|
|
246
|
+
turns a 1170 px-wide 3x phone capture into a 390 px conversion canvas. The
|
|
247
|
+
option is not accepted for LayerDoc input or `resume`.
|
|
248
|
+
|
|
249
|
+
LayerDoc input accepts the public v2 JSON downloaded from the API. Its signed
|
|
250
|
+
raster references must still be valid and must belong to the same authenticated
|
|
251
|
+
account. The service resolves those owned artifacts directly; it does not fetch
|
|
252
|
+
arbitrary remote URLs. LayerDoc input produces `layerdoc`, `html`, `svg`, `png`, `jpg`, `webp`, `pdf`, `psd`,
|
|
253
|
+
`pptx`, `sketch`, `web_project`, or `app_project`. Project outputs require
|
|
254
|
+
`--profile <json|file>`; the CLI also accepts `--profile @file.json`.
|
|
255
|
+
|
|
256
|
+
## LayerDoc to downstream formats
|
|
257
|
+
|
|
258
|
+
The raw LayerDoc representation can be submitted directly to a second
|
|
259
|
+
conversion. This makes it possible to edit the document's text, geometry, or
|
|
260
|
+
style before compiling responsive HTML or a fixed export while retaining its
|
|
261
|
+
signed asset refs:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
import fs from 'node:fs';
|
|
265
|
+
import { TwelveUiConversionClient } from '@12ui/design';
|
|
266
|
+
|
|
267
|
+
const client = new TwelveUiConversionClient({
|
|
268
|
+
origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
|
|
269
|
+
apiKey: process.env.TWELVE_UI_API_KEY!,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const created = await client.createConversion({
|
|
273
|
+
layerdoc: new Uint8Array(await fs.promises.readFile('./screen.layerdoc.json')),
|
|
274
|
+
filename: 'screen.layerdoc.json',
|
|
275
|
+
output: 'html',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const completed = created.status === 'succeeded'
|
|
279
|
+
? created
|
|
280
|
+
: await client.waitForConversion(created.id, { expiresAt: created.expires_at });
|
|
281
|
+
const html = await client.downloadResult(completed.id, 'html');
|
|
282
|
+
await fs.promises.writeFile('./screen.html', html.bytes);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
For generated responsive layouts, derive from the successful image-to-LayerDoc
|
|
286
|
+
operation instead of uploading the image again:
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
const responsive = await client.createConversion({
|
|
290
|
+
sourceConversionId: imageToLayerDoc.id,
|
|
291
|
+
output: 'html',
|
|
292
|
+
responsiveQuality: 'pro', // standard | pro
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
This authenticated path reuses the canonical LayerDoc and raster assets from
|
|
297
|
+
`imageToLayerDoc`, consumes export quota, and starts directly at responsive
|
|
298
|
+
reference generation. The source conversion must still be retained and must
|
|
299
|
+
have been produced by the current pipeline revision.
|
|
300
|
+
|
|
301
|
+
While the operation is queued or running, poll it normally and read
|
|
302
|
+
`responsive_preview`. Its frames are returned in mobile, tablet, then compact
|
|
303
|
+
desktop plan order. Each frame moves through `waiting`, `generating`,
|
|
304
|
+
`generated`, `extracting`, `binding`, and `complete`; its signed `artifact`
|
|
305
|
+
appears immediately after the real generated reference PNG is durably
|
|
306
|
+
registered. `completed` and `total` count reference, extraction, and binding as
|
|
307
|
+
three durable steps per admitted anchor, while `progress.percent` remains the
|
|
308
|
+
overall conversion progress for a single progress bar.
|
|
309
|
+
|
|
310
|
+
Project output uses the same client method and returns a deterministic ZIP:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
const createdProject = await client.createConversion({
|
|
314
|
+
layerdoc: new Uint8Array(await fs.promises.readFile('./screen.layerdoc.json')),
|
|
315
|
+
filename: 'screen.layerdoc.json',
|
|
316
|
+
output: 'web_project',
|
|
317
|
+
profile: {
|
|
318
|
+
version: 1,
|
|
319
|
+
framework: 'react',
|
|
320
|
+
styling: 'tailwind',
|
|
321
|
+
language: 'typescript',
|
|
322
|
+
packaging: 'project',
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const projectOperation = createdProject.status === 'succeeded'
|
|
327
|
+
? createdProject
|
|
328
|
+
: await client.waitForConversion(createdProject.id, {
|
|
329
|
+
expiresAt: createdProject.expires_at,
|
|
330
|
+
});
|
|
331
|
+
const project = await client.downloadResult(projectOperation.id, 'web_project');
|
|
332
|
+
await fs.promises.writeFile('./screen-react.zip', project.bytes);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
The complete version-1 capability matrix is documented in
|
|
336
|
+
[`docs/EXPORT_FORMATS.md`](https://github.com/just-every/12ui/blob/main/docs/EXPORT_FORMATS.md). Unsupported framework,
|
|
337
|
+
styling, language, or packaging combinations fail before upload; the client
|
|
338
|
+
does not substitute a nearby target.
|
|
339
|
+
|
|
340
|
+
The 10 web framework slugs are `html`, `react`, `next`, `vue`, `nuxt`, `svelte`,
|
|
341
|
+
`sveltekit`, `angular`, `astro`, and `lit`. The 9 app framework slugs are `expo`,
|
|
342
|
+
`react_native`, `flutter`, `ionic_capacitor`, `swiftui`, `uikit`,
|
|
343
|
+
`jetpack_compose`, `android_views`, and `compose_multiplatform`. Import
|
|
344
|
+
`WEB_PROJECT_CAPABILITIES` and `APP_PROJECT_CAPABILITIES` from this package to
|
|
345
|
+
enumerate the exact styling, language, and packaging cross-products at runtime.
|
|
346
|
+
For web output, `component` is reusable component source, `page` is a route/page
|
|
347
|
+
entrypoint, and `project` is a runnable scaffold. For app output, `screen` is
|
|
348
|
+
integration-ready screen source for an existing app, while `project` adds the
|
|
349
|
+
runnable scaffold and build configuration.
|
|
350
|
+
|
|
351
|
+
## Hosted `/convert` two-phase workflow
|
|
352
|
+
|
|
353
|
+
The Node client above remains API-key authenticated and may request any valid
|
|
354
|
+
image output directly. The free hosted web page uses the same HTTP resources
|
|
355
|
+
with an intentionally narrower contract:
|
|
356
|
+
|
|
357
|
+
1. Create one image conversion with `output: "layerdoc"`.
|
|
358
|
+
2. Poll the operation and replace the interactive preview only when
|
|
359
|
+
`operation.preview.revision` increases.
|
|
360
|
+
3. Fetch the final LayerDoc representation after the source succeeds.
|
|
361
|
+
4. Keep that hydrated JSON in memory and create independent LayerDoc-input jobs
|
|
362
|
+
for `html`, `svg`, `png`, `jpg`, `webp`, `pdf`, `psd`, `pptx`, `sketch`, `web_project`, and
|
|
363
|
+
`app_project`. Different formats and project profiles can
|
|
364
|
+
run in parallel; a repeated completed format should download the cached
|
|
365
|
+
representation rather than create another run.
|
|
366
|
+
|
|
367
|
+
No special export endpoint is involved. The source conversion remains the web
|
|
368
|
+
session root, and each export is an ordinary `POST /api/v1/convert` followed by
|
|
369
|
+
polling `GET /api/v1/convert/:id`. LayerDoc input is accepted only after its
|
|
370
|
+
source run has succeeded because the Worker verifies its signed artifacts,
|
|
371
|
+
expiry, and ownership before importing them.
|
|
372
|
+
|
|
373
|
+
Anonymous hosted-page requests send `X-12UI-Public-Preview: 1` and the same
|
|
374
|
+
browser-generated `X-12UI-Public-Visitor` value. Public image creation also
|
|
375
|
+
includes `cf-turnstile-response` in multipart form data; its verified action is
|
|
376
|
+
`12ui_convert_image`. Public quotas are 5 Fast, 2 Standard, no Pro, and 20
|
|
377
|
+
exports per salted IP hash per UTC day. Signed-in and API accounts receive 50
|
|
378
|
+
Fast, 20 Standard, 2 Pro, and 200 exports per stable account id and UTC day.
|
|
379
|
+
`GET /api/v1/convert/quota` returns all buckets; successful POST responses
|
|
380
|
+
identify the admitted bucket and return its limit and remaining count. Daily
|
|
381
|
+
exhaustion returns `429` with `Retry-After`.
|
|
382
|
+
|
|
383
|
+
All runs are sponsored and do not check or debit Login credits. Provider,
|
|
384
|
+
model, request-id, reservation, actual-cost, principal-tier, and account-id
|
|
385
|
+
records are retained in durable ledgers independent of expiring conversion
|
|
386
|
+
artifacts. Public headers are for the trusted anonymous preview; CLI and MCP
|
|
387
|
+
consumers should keep using a Login-issued API key.
|
|
388
|
+
|
|
389
|
+
Running LayerDoc operations may include an immutable `preview`: `structure`
|
|
390
|
+
contains the final layer tree and prepared source, while `standard` adds 1×
|
|
391
|
+
crops and cleaned plates. `result` remains reserved for the final enhanced,
|
|
392
|
+
manifest-last publication. `progress.active` reports durable completed/total
|
|
393
|
+
counts for each materialization lane.
|
|
394
|
+
|
|
395
|
+
## Progressive Node consumer
|
|
396
|
+
|
|
397
|
+
`waitForConversion` intentionally returns only the terminal operation. A
|
|
398
|
+
consumer that wants live progress or previews should poll `getConversion` and
|
|
399
|
+
apply every operation snapshot:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
import fs from 'node:fs';
|
|
403
|
+
import { TwelveUiConversionClient } from '@12ui/design';
|
|
404
|
+
|
|
405
|
+
declare function renderLayerDoc(document: unknown): void;
|
|
406
|
+
|
|
407
|
+
const client = new TwelveUiConversionClient({
|
|
408
|
+
origin: process.env.TWELVE_UI_ORIGIN ?? 'https://12ui.com',
|
|
409
|
+
apiKey: process.env.TWELVE_UI_API_KEY!,
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const created = await client.createConversion({
|
|
413
|
+
bytes: new Uint8Array(await fs.promises.readFile('./screen.png')),
|
|
414
|
+
filename: 'screen.png',
|
|
415
|
+
mediaType: 'image/png',
|
|
416
|
+
output: 'layerdoc',
|
|
417
|
+
model: 'standard',
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
let operation = created;
|
|
421
|
+
let displayedRevision = 0;
|
|
422
|
+
|
|
423
|
+
while (operation.status === 'queued' || operation.status === 'running') {
|
|
424
|
+
const progress = operation.progress;
|
|
425
|
+
if (progress) {
|
|
426
|
+
console.log(progress.percent, progress.stage, progress.milestone);
|
|
427
|
+
for (const lane of progress.active ?? []) {
|
|
428
|
+
console.log(lane.kind, lane.completed, lane.total, lane.status);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (operation.preview && operation.preview.revision > displayedRevision) {
|
|
433
|
+
displayedRevision = operation.preview.revision;
|
|
434
|
+
renderLayerDoc(operation.preview.document);
|
|
435
|
+
// operation.preview.artifacts contain signed hrefs that are usable now.
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
await new Promise((resolve) => setTimeout(resolve, 1_000));
|
|
439
|
+
operation = await client.getConversion(operation.id);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (operation.status !== 'succeeded' || operation.result?.kind !== 'layerdoc') {
|
|
443
|
+
throw new Error(operation.error?.detail ?? `Conversion ${operation.status}`);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// The terminal result is authoritative and replaces any displayed preview.
|
|
447
|
+
renderLayerDoc(operation.result.document);
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Raw HTTP consumers should use `Accept: application/json` while polling and
|
|
451
|
+
respect the response's `Retry-After` header (currently one second). `Prefer:
|
|
452
|
+
wait=20` only allows the create request to wait for an early result; it is not
|
|
453
|
+
a streaming connection. There is no SSE or WebSocket contract.
|
|
454
|
+
|
|
455
|
+
Progress and preview rules:
|
|
456
|
+
|
|
457
|
+
- `progress.percent` is the weighted server calculation; do not derive a
|
|
458
|
+
percentage from the stage name.
|
|
459
|
+
- `progress.active` is optional and image-specific. Do not assume every lane
|
|
460
|
+
is present or that lane order is fixed.
|
|
461
|
+
- `milestone` is `structure_ready` or `standard_ready` once that preview is
|
|
462
|
+
available.
|
|
463
|
+
- Previews currently apply to `output=layerdoc`. Downstream HTML and fixed
|
|
464
|
+
export operations still expose progress, but publish only their terminal result.
|
|
465
|
+
- Preview revision 1 is `quality: "structure"`; revision 2 is
|
|
466
|
+
`quality: "standard"`. Treat revisions as immutable snapshots.
|
|
467
|
+
- A preview artifact id is never repointed to different bytes. Signed `href`
|
|
468
|
+
values expire with the operation; re-read the operation to refresh URLs.
|
|
469
|
+
- On `succeeded`, use `result` as authoritative. On `failed` or `expired`, use
|
|
470
|
+
`error` and discard any displayed preview as a non-terminal aid.
|
|
471
|
+
|
|
472
|
+
## MCP
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
12ui mcp
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
The server exposes one tool, `design.convert`, backed by the same
|
|
479
|
+
`POST /api/v1/convert` and `GET /api/v1/convert/:id` contract as the CLI. Pass
|
|
480
|
+
`imagePath` for PNG/JPEG/WebP input or `layerdocPath` for public LayerDoc v2
|
|
481
|
+
JSON input; `layerdocPath` accepts every downstream output. Pass the exact
|
|
482
|
+
`profile` object for `web_project` or `app_project`. Set the optional
|
|
483
|
+
`idempotencyKey` when an ambiguous create may need to be retried with the same
|
|
484
|
+
stable key; otherwise the client generates a new UUID.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TwelveUiConversionClient, type ConversionOperation } from './conversion-client.js';
|
|
2
|
+
export type MaterializedArtifact = {
|
|
3
|
+
id: string;
|
|
4
|
+
role: string;
|
|
5
|
+
mediaType: string;
|
|
6
|
+
sha256: string;
|
|
7
|
+
sourceHref: string;
|
|
8
|
+
localPath: string;
|
|
9
|
+
};
|
|
10
|
+
export type MaterializedArtifactManifest = {
|
|
11
|
+
conversionId: string;
|
|
12
|
+
operationExpiresAt: string;
|
|
13
|
+
manifestFile: string;
|
|
14
|
+
artifacts: MaterializedArtifact[];
|
|
15
|
+
};
|
|
16
|
+
export declare const materializeConversionArtifacts: (client: TwelveUiConversionClient, operation: ConversionOperation, resultFile: string) => Promise<MaterializedArtifactManifest>;
|
|
17
|
+
//# sourceMappingURL=artifact-materializer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-materializer.d.ts","sourceRoot":"","sources":["../src/artifact-materializer.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,wBAAwB,EAExB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC,CAAC;AA6BF,eAAO,MAAM,8BAA8B,GACzC,QAAQ,wBAAwB,EAChC,WAAW,mBAAmB,EAC9B,YAAY,MAAM,KACjB,OAAO,CAAC,4BAA4B,CA2BtC,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const extensionForMediaType = (mediaType) => {
|
|
5
|
+
const normalized = mediaType.toLowerCase().split(';', 1)[0]?.trim();
|
|
6
|
+
if (normalized === 'image/png')
|
|
7
|
+
return '.png';
|
|
8
|
+
if (normalized === 'image/jpeg')
|
|
9
|
+
return '.jpg';
|
|
10
|
+
if (normalized === 'image/webp')
|
|
11
|
+
return '.webp';
|
|
12
|
+
if (normalized === 'application/json')
|
|
13
|
+
return '.json';
|
|
14
|
+
if (normalized === 'text/html')
|
|
15
|
+
return '.html';
|
|
16
|
+
if (normalized === 'image/svg+xml')
|
|
17
|
+
return '.svg';
|
|
18
|
+
if (normalized === 'application/pdf')
|
|
19
|
+
return '.pdf';
|
|
20
|
+
if (normalized === 'image/vnd.adobe.photoshop')
|
|
21
|
+
return '.psd';
|
|
22
|
+
if (normalized === 'application/vnd.openxmlformats-officedocument.presentationml.presentation')
|
|
23
|
+
return '.pptx';
|
|
24
|
+
if (normalized === 'application/zip')
|
|
25
|
+
return '.sketch';
|
|
26
|
+
return '.bin';
|
|
27
|
+
};
|
|
28
|
+
const safeArtifactName = (artifact) => {
|
|
29
|
+
const stem = artifact.id.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'artifact';
|
|
30
|
+
return `${stem}-${artifact.sha256.slice(0, 12).toLowerCase()}${extensionForMediaType(artifact.media_type)}`;
|
|
31
|
+
};
|
|
32
|
+
const assertDigest = (artifact, bytes) => {
|
|
33
|
+
const digest = createHash('sha256').update(bytes).digest('hex');
|
|
34
|
+
if (digest !== artifact.sha256.toLowerCase()) {
|
|
35
|
+
throw new Error(`Conversion artifact ${artifact.id} failed SHA-256 verification`);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
export const materializeConversionArtifacts = async (client, operation, resultFile) => {
|
|
39
|
+
const artifacts = operation.result?.artifacts ?? [];
|
|
40
|
+
const directory = `${resultFile}.assets`;
|
|
41
|
+
await mkdir(directory, { recursive: true });
|
|
42
|
+
const materialized = await Promise.all(artifacts.map(async (artifact) => {
|
|
43
|
+
const downloaded = await client.downloadArtifact(artifact);
|
|
44
|
+
assertDigest(artifact, downloaded.bytes);
|
|
45
|
+
const localPath = path.join(directory, safeArtifactName(artifact));
|
|
46
|
+
await writeFile(localPath, downloaded.bytes);
|
|
47
|
+
return {
|
|
48
|
+
id: artifact.id,
|
|
49
|
+
role: artifact.role,
|
|
50
|
+
mediaType: downloaded.mediaType,
|
|
51
|
+
sha256: artifact.sha256,
|
|
52
|
+
sourceHref: artifact.href,
|
|
53
|
+
localPath,
|
|
54
|
+
};
|
|
55
|
+
}));
|
|
56
|
+
const manifestFile = path.join(directory, 'manifest.json');
|
|
57
|
+
const manifest = {
|
|
58
|
+
conversionId: operation.id,
|
|
59
|
+
operationExpiresAt: operation.expires_at,
|
|
60
|
+
manifestFile,
|
|
61
|
+
artifacts: materialized,
|
|
62
|
+
};
|
|
63
|
+
await writeFile(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
64
|
+
return manifest;
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=artifact-materializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-materializer.js","sourceRoot":"","sources":["../src/artifact-materializer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type CliFlags = Record<string, string | true>;
|
|
2
|
+
export declare const parseCliArguments: (argv: string[]) => {
|
|
3
|
+
command: string[];
|
|
4
|
+
flags: CliFlags;
|
|
5
|
+
};
|
|
6
|
+
export declare const stringFlag: (flags: CliFlags, name: string) => string | undefined;
|
|
7
|
+
export declare const booleanFlag: (flags: CliFlags, name: string) => boolean;
|
|
8
|
+
//# sourceMappingURL=cli-arguments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-arguments.d.ts","sourceRoot":"","sources":["../src/cli-arguments.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAWrD,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EAAE,KACb;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAqBtC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,OAAO,QAAQ,EAAE,MAAM,MAAM,KAAG,MAAM,GAAG,SAGnE,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,QAAQ,EAAE,MAAM,MAAM,KAAG,OAA+B,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const booleanFlags = new Set([
|
|
2
|
+
'detach',
|
|
3
|
+
'force',
|
|
4
|
+
'help',
|
|
5
|
+
'json',
|
|
6
|
+
'skip-auth',
|
|
7
|
+
'version',
|
|
8
|
+
]);
|
|
9
|
+
export const parseCliArguments = (argv) => {
|
|
10
|
+
const command = [];
|
|
11
|
+
const flags = {};
|
|
12
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
13
|
+
const value = argv[index];
|
|
14
|
+
if (!value?.startsWith('--')) {
|
|
15
|
+
if (value)
|
|
16
|
+
command.push(value);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const name = value.slice(2);
|
|
20
|
+
if (!name)
|
|
21
|
+
throw new Error('Invalid empty flag');
|
|
22
|
+
if (booleanFlags.has(name)) {
|
|
23
|
+
flags[name] = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const next = argv[index + 1];
|
|
27
|
+
if (!next || next.startsWith('--'))
|
|
28
|
+
throw new Error(`--${name} requires a value`);
|
|
29
|
+
flags[name] = next;
|
|
30
|
+
index += 1;
|
|
31
|
+
}
|
|
32
|
+
return { command, flags };
|
|
33
|
+
};
|
|
34
|
+
export const stringFlag = (flags, name) => {
|
|
35
|
+
const value = flags[name];
|
|
36
|
+
return typeof value === 'string' ? value : undefined;
|
|
37
|
+
};
|
|
38
|
+
export const booleanFlag = (flags, name) => flags[name] === true;
|
|
39
|
+
//# sourceMappingURL=cli-arguments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-arguments.js","sourceRoot":"","sources":["../src/cli-arguments.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,WAAW;IACX,SAAS;CACV,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAc,EAC0B,EAAE;IAC1C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,IAAI,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACjD,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACnB,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,KAAK,IAAI,mBAAmB,CAAC,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACnB,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAe,EAAE,IAAY,EAAsB,EAAE;IAC9E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAe,EAAE,IAAY,EAAW,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-auth-command.d.ts","sourceRoot":"","sources":["../src/cli-auth-command.ts"],"names":[],"mappings":"AAMA,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAgD5E,eAAO,MAAM,cAAc,GACzB,QAAQ,MAAM,GAAG,SAAS,EAC1B,OAAO,QAAQ,KACd,OAAO,CAAC,IAAI,CA+Dd,CAAC"}
|