@miketromba/ploof 0.1.1 → 0.1.3
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 +28 -9
- package/SPEC.md +16 -4
- package/assets/brand/ploof-banner.png +0 -0
- package/dist/ploof.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<p align="center">
|
|
6
|
-
AI asset generation from the command line.
|
|
2
|
+
<img src="assets/brand/ploof-banner.png" alt="Ploof - AI asset generation from the command line." width="100%" />
|
|
7
3
|
</p>
|
|
8
4
|
|
|
9
5
|
<p align="center">
|
|
@@ -62,7 +58,7 @@ ploof login openai --api-key <your-api-key>
|
|
|
62
58
|
ploof image generate \
|
|
63
59
|
--prompt "Studio product photo of a matte black water bottle" \
|
|
64
60
|
--out assets/hero.png \
|
|
65
|
-
--model gpt-image-
|
|
61
|
+
--model gpt-image-2 \
|
|
66
62
|
--size 1024x1024
|
|
67
63
|
|
|
68
64
|
# Edit an image with context
|
|
@@ -118,7 +114,7 @@ ploof image generate \
|
|
|
118
114
|
--profile default \
|
|
119
115
|
--prompt "Editorial portrait, dramatic side light" \
|
|
120
116
|
--out assets/portrait.png \
|
|
121
|
-
--model gpt-image-
|
|
117
|
+
--model gpt-image-2 \
|
|
122
118
|
--size 1024x1024 \
|
|
123
119
|
--quality high \
|
|
124
120
|
--format png
|
|
@@ -165,7 +161,7 @@ tasks:
|
|
|
165
161
|
provider: openai
|
|
166
162
|
prompt: "Studio product photo"
|
|
167
163
|
params:
|
|
168
|
-
model: gpt-image-
|
|
164
|
+
model: gpt-image-2
|
|
169
165
|
size: 1024x1024
|
|
170
166
|
quality: high
|
|
171
167
|
output: assets/base.png
|
|
@@ -269,10 +265,33 @@ PLOOF_OPENAI_API_KEY=sk-... bun test tests/e2e
|
|
|
269
265
|
Optional live-test overrides:
|
|
270
266
|
|
|
271
267
|
```bash
|
|
272
|
-
PLOOF_OPENAI_LIVE_MODEL=gpt-image-
|
|
268
|
+
PLOOF_OPENAI_LIVE_MODEL=gpt-image-2
|
|
273
269
|
PLOOF_OPENAI_LIVE_SIZE=1024x1024
|
|
274
270
|
```
|
|
275
271
|
|
|
272
|
+
## Publishing
|
|
273
|
+
|
|
274
|
+
Local release verification stops at packaging:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
bun run release
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Publishing should happen from GitHub Actions by pushing a `v*` tag. The npm
|
|
281
|
+
package must have a Trusted Publisher configured with:
|
|
282
|
+
|
|
283
|
+
| Field | Value |
|
|
284
|
+
| --- | --- |
|
|
285
|
+
| Provider | GitHub Actions |
|
|
286
|
+
| Organization or user | `miketromba` |
|
|
287
|
+
| Repository | `ploof` |
|
|
288
|
+
| Workflow filename | `publish.yml` |
|
|
289
|
+
| Environment | blank |
|
|
290
|
+
| Allowed action | `npm publish` |
|
|
291
|
+
|
|
292
|
+
Do not publish from a local terminal unless intentionally doing a manual
|
|
293
|
+
emergency release.
|
|
294
|
+
|
|
276
295
|
## License
|
|
277
296
|
|
|
278
297
|
MIT
|
package/SPEC.md
CHANGED
|
@@ -51,9 +51,21 @@ Conventions to preserve:
|
|
|
51
51
|
- Published package runs on Node 18+ and does not require Bun.
|
|
52
52
|
- Published files are constrained to runtime artifacts, README, LICENSE, spec, and skill files.
|
|
53
53
|
- GitHub Actions CI runs typecheck, tests, and build.
|
|
54
|
-
- GitHub Actions publish runs on `v*` tags
|
|
54
|
+
- GitHub Actions publish runs on `v*` tags through npm trusted publishing/OIDC.
|
|
55
55
|
- Human-readable output in TTY, compact output when piped, JSON/JSONL for agents and scripts.
|
|
56
56
|
|
|
57
|
+
NPM trusted publisher settings for `@miketromba/ploof`:
|
|
58
|
+
|
|
59
|
+
- Provider: GitHub Actions.
|
|
60
|
+
- Organization or user: `miketromba`.
|
|
61
|
+
- Repository: `ploof`.
|
|
62
|
+
- Workflow filename: `publish.yml`.
|
|
63
|
+
- Environment: blank.
|
|
64
|
+
- Allowed action: `npm publish`.
|
|
65
|
+
|
|
66
|
+
Local release verification must stop at `npm pack --dry-run`; do not run local
|
|
67
|
+
`npm publish` for normal releases.
|
|
68
|
+
|
|
57
69
|
## Core Goals
|
|
58
70
|
|
|
59
71
|
1. Authenticate with multiple asset generation providers.
|
|
@@ -170,7 +182,7 @@ ploof image generate \
|
|
|
170
182
|
--profile default \
|
|
171
183
|
--prompt "Studio product photo" \
|
|
172
184
|
--out assets/hero.png \
|
|
173
|
-
--model gpt-image-
|
|
185
|
+
--model gpt-image-2 \
|
|
174
186
|
--size 1024x1024 \
|
|
175
187
|
--quality high \
|
|
176
188
|
--format png
|
|
@@ -214,7 +226,7 @@ tasks:
|
|
|
214
226
|
provider: openai
|
|
215
227
|
prompt: "Studio product photo"
|
|
216
228
|
params:
|
|
217
|
-
model: gpt-image-
|
|
229
|
+
model: gpt-image-2
|
|
218
230
|
size: 1024x1024
|
|
219
231
|
quality: high
|
|
220
232
|
output: assets/base.png
|
|
@@ -313,7 +325,7 @@ Asset-producing commands should write the asset to disk and print structured met
|
|
|
313
325
|
"provider": "openai",
|
|
314
326
|
"outputs": ["assets/hero.png"],
|
|
315
327
|
"metadata": {
|
|
316
|
-
"model": "gpt-image-
|
|
328
|
+
"model": "gpt-image-2"
|
|
317
329
|
}
|
|
318
330
|
}
|
|
319
331
|
```
|
|
Binary file
|
package/dist/ploof.js
CHANGED
|
@@ -259,7 +259,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
259
259
|
`,z)}while(J!==-1);return X+=$.slice(z),X}var{stdout:GV,stderr:NV}=zV,i3=Symbol("GENERATOR"),dU=Symbol("STYLER"),H0=Symbol("IS_EMPTY"),_V=["ansi","ansi","ansi256","ansi16m"],nU=Object.create(null),MT=($,U={})=>{if(U.level&&!(Number.isInteger(U.level)&&U.level>=0&&U.level<=3))throw Error("The `level` option should be an integer from 0 to 3");let w=GV?GV.level:0;$.level=U.level===void 0?w:U.level};var vT=($)=>{let U=(...w)=>w.join(" ");return MT(U,$),Object.setPrototypeOf(U,K0.prototype),U};function K0($){return vT($)}Object.setPrototypeOf(K0.prototype,Function.prototype);for(let[$,U]of Object.entries(t$))nU[$]={get(){let w=$J(this,m3(U.open,U.close,this[dU]),this[H0]);return Object.defineProperty(this,$,{value:w}),w}};nU.visible={get(){let $=$J(this,this[dU],!0);return Object.defineProperty(this,"visible",{value:$}),$}};var h3=($,U,w,...J)=>{if($==="rgb"){if(U==="ansi16m")return t$[w].ansi16m(...J);if(U==="ansi256")return t$[w].ansi256(t$.rgbToAnsi256(...J));return t$[w].ansi(t$.rgbToAnsi(...J))}if($==="hex")return h3("rgb",U,w,...t$.hexToRgb(...J));return t$[w][$](...J)},ST=["rgb","hex","ansi256"];for(let $ of ST){nU[$]={get(){let{level:w}=this;return function(...J){let z=m3(h3($,_V[w],"color",...J),t$.color.close,this[dU]);return $J(this,z,this[H0])}}};let U="bg"+$[0].toUpperCase()+$.slice(1);nU[U]={get(){let{level:w}=this;return function(...J){let z=m3(h3($,_V[w],"bgColor",...J),t$.bgColor.close,this[dU]);return $J(this,z,this[H0])}}}}var bT=Object.defineProperties(()=>{},{...nU,level:{enumerable:!0,get(){return this[i3].level},set($){this[i3].level=$}}}),m3=($,U,w)=>{let J,z;if(w===void 0)J=$,z=U;else J=w.openAll+$,z=U+w.closeAll;return{open:$,close:U,openAll:J,closeAll:z,parent:w}},$J=($,U,w)=>{let J=(...z)=>ET(J,z.length===1?""+z[0]:z.join(" "));return Object.setPrototypeOf(J,bT),J[i3]=$,J[dU]=U,J[H0]=w,J},ET=($,U)=>{if($.level<=0||!U)return $[H0]?"":U;let w=$[dU];if(w===void 0)return U;let{openAll:J,closeAll:z}=w;if(U.includes("\x1B"))while(w!==void 0)U=JV(U,w.close,w.open),w=w.parent;let X=U.indexOf(`
|
|
260
260
|
`);if(X!==-1)U=XV(U,z,J,X);return J+U+z};Object.defineProperties(K0.prototype,nU);var AT=K0(),vr=K0({level:NV?NV.level:0});var UJ=AT;class y$ extends Error{code;constructor($,U=1){super($);this.code=U;this.name="CliError"}}function YV($,U=!1){let w=$ instanceof Error?$.message:String($);if(U)return`Error: ${w}`;return`${UJ.red("Error:")} ${w}`}function QV($){return`${$.join(`
|
|
261
261
|
`).trim()}
|
|
262
|
-
`}var RT=QV(["# Generate assets with the ploof CLI","","Ploof is an AI asset generation CLI. Use it when a task needs generated or edited images, batch asset creation, provider authentication, image context inputs, or reusable generation manifests.","","Package name: `@miketromba/ploof`. Command name: `ploof`. Supported today: OpenAI image generation and image editing.","","## Core workflow","","1. Run `ploof whoami openai`. If unauthenticated, ask the user to run `ploof login openai` or provide `PLOOF_OPENAI_API_KEY` in their shell.","2. For one asset, use `ploof image generate` or `ploof image edit` with an explicit `--out` path.","3. For multiple assets, dependencies, or parallel work, write a YAML manifest and run `ploof run <manifest.yaml>`.","4. Use `--output json` for commands another tool or agent must parse. Use `--output jsonl` for batch streams.","5. After a command completes, verify every path in `outputs` exists before telling the user generation succeeded.","","## Authentication","","```bash","ploof login openai --api-key <key>","ploof whoami openai","ploof profiles openai","```","","There is no `ploof auth` namespace. The authentication commands are top-level: `login`, `whoami`, `profiles`, and `logout`.","","Environment variables override stored credentials:","","```bash","PLOOF_OPENAI_API_KEY=...","OPENAI_API_KEY=...","```","","Use `--profile <name>` on `login`, `whoami`, `image generate`, `image edit`, and manifest tasks when the user has multiple OpenAI credentials. Never print or store secrets in generated project files.","","## Image generation","","```bash","ploof image generate \\"," --provider openai \\",' --prompt "Studio product photo" \\'," --out assets/hero.png \\"," --model gpt-image-
|
|
262
|
+
`}var RT=QV(["# Generate assets with the ploof CLI","","Ploof is an AI asset generation CLI. Use it when a task needs generated or edited images, batch asset creation, provider authentication, image context inputs, or reusable generation manifests.","","Package name: `@miketromba/ploof`. Command name: `ploof`. Supported today: OpenAI image generation and image editing.","","## Core workflow","","1. Run `ploof whoami openai`. If unauthenticated, ask the user to run `ploof login openai` or provide `PLOOF_OPENAI_API_KEY` in their shell.","2. For one asset, use `ploof image generate` or `ploof image edit` with an explicit `--out` path.","3. For multiple assets, dependencies, or parallel work, write a YAML manifest and run `ploof run <manifest.yaml>`.","4. Use `--output json` for commands another tool or agent must parse. Use `--output jsonl` for batch streams.","5. After a command completes, verify every path in `outputs` exists before telling the user generation succeeded.","","## Authentication","","```bash","ploof login openai --api-key <key>","ploof whoami openai","ploof profiles openai","```","","There is no `ploof auth` namespace. The authentication commands are top-level: `login`, `whoami`, `profiles`, and `logout`.","","Environment variables override stored credentials:","","```bash","PLOOF_OPENAI_API_KEY=...","OPENAI_API_KEY=...","```","","Use `--profile <name>` on `login`, `whoami`, `image generate`, `image edit`, and manifest tasks when the user has multiple OpenAI credentials. Never print or store secrets in generated project files.","","## Image generation","","```bash","ploof image generate \\"," --provider openai \\",' --prompt "Studio product photo" \\'," --out assets/hero.png \\"," --model gpt-image-2 \\"," --size 1024x1024 \\"," --quality high \\"," --format png \\"," --output json","```","","Important: `--format png` controls the generated asset format. `--output json` controls CLI output formatting.","","First-class OpenAI image flags:","","- `--model <model>`: for example `gpt-image-2`.","- `--size <size>`: provider size such as `1024x1024`.","- `--quality <quality>`: provider quality such as `low`, `medium`, or `high` when supported.","- `--format <format>` or `--output-format <format>`: provider image format, usually `png`, `jpeg`, or `webp` when supported.","- `--background <value>`, `--moderation <value>`, `--n <count>`, `--output-compression <number>`, `--partial-images <number>`, `--response-format <format>`, `--style <style>`, `--user <id>`, `--stream`.","- `--param key=value`: pass one provider-specific parameter. Nested keys work, such as `--param extra.foo=bar`.","- `--json '{...}'`: merge a provider-specific JSON object into the request. Explicit first-class flags override overlapping JSON keys.","","Use `--quality low` for cheap smoke tests. Use the user's requested quality and size for final assets.","","## Image editing and context images","","```bash","ploof image edit \\"," --provider openai \\"," --image input.png \\"," --image reference.png \\"," --mask mask.png \\",' --prompt "Replace the background" \\'," --out assets/edited.png \\"," --model gpt-image-2 \\"," --format png \\"," --output json","```","","Pass every source image the provider should see with repeated `--image`. Use `--mask` only when the provider/model supports masked edits. Edit also supports `--input-fidelity <value>`.","","Input assets can be local paths, `http://` or `https://` URLs, or `-` for stdin. Ploof infers common image MIME types from file extensions and preserves generated files locally.","","## Outputs and verification","","`--out <path>` can be a file path or directory. When generating multiple images with `--n`, a file path is expanded with `-1`, `-2`, etc. If `--out` is omitted, Ploof writes in the current directory using default names like `image.png` or `edited-image.png`.","","Default sidecar metadata is enabled. For each output file, Ploof writes `<output>.json` with the operation, prompt, params, outputs, provider metadata, and timestamp.","","Parseable result shape:","","```json","{",' "kind": "image.generate",',' "provider": "openai",',' "profile": "default",',' "outputs": ["assets/hero.png"],',' "metadata": { "model": "gpt-image-2" }',"}","```","","Useful global output flags:","","- `--output json|jsonl|compact|table`: choose CLI output format.","- `--fields outputs,metadata.usage.total_tokens`: select fields for parseable outputs.","- `--detail`, `--quiet`, `--no-color`, `--verbose`.","","## Batch manifests","","```yaml","version: 1","parallel: 4","tasks:"," - id: base"," kind: image.generate"," provider: openai"," profile: default",' prompt: "Studio product photo"'," output: assets/base.png"," params:"," model: gpt-image-2"," size: 1024x1024"," quality: high"," output_format: png",""," - id: edit"," kind: image.edit"," provider: openai"," needs: [base]"," inputs:"," images:"," - task: base"," - source: ./reference.png"," mask:"," source: ./mask.png",' prompt: "Add a premium background"'," output: assets/final.png"," params:"," model: gpt-image-2"," size: 1024x1024","```","","Run it with:","","```bash","ploof run assets.yaml --parallel 4 --output json","```","","Manifest notes:","","- `version: 1`, `parallel`, and `tasks` are supported.","- Task kinds are `image.generate` and `image.edit`.","- Task fields: `id`, `kind`, `provider`, `profile`, `needs`, `prompt`, `output`, `params`, `sidecar`, `inputs`.","- Relative paths are resolved from the manifest file location.","- `inputs.images` accepts strings, `{ source }`, or `{ task }`. `{ task: base }` uses the first output from that completed task.","- Run `ploof run assets.yaml --dry-run --output json` before expensive batches.","","## Configuration","","```bash","ploof config list","ploof config set output json","ploof config set defaultParallel 4","ploof config set sidecar true","ploof config reset","```","","Config is stored at `~/.ploof/config.json`. Credentials are stored separately at `~/.ploof/credentials.json`.","","## Agent guidance","","- Prefer exact user-provided prompts, dimensions, source images, and output paths. Ask only when a missing choice would change the intended asset.","- Keep prompts and params explicit in commands or manifests.","- Use deterministic output paths, usually under the user's requested asset directory or a temp directory for tests.","- Use manifests for parallel generation, dependency chains, or more than one related asset.","- Keep `--parallel` modest unless the user requests volume; generation costs money and provider rate limits may apply.","- Report generated file paths and any relevant metadata such as model and token usage.","- Do not claim assets were generated unless the command completed successfully and output files exist.","- If a command fails, report the command goal, the error, and the next concrete fix. Do not fabricate assets.","- Run `ploof <command> --help` when a detail is unclear; prefer the installed CLI help over memory."]);function WV(){return QV(["Usage: ploof learn [options]","","Print AI-agent instructions for using the installed ploof CLI.","","Options:"," --help, -h Show this help","","Examples:"," ploof learn"])}function VV($=[]){if($.includes("--help")||$.includes("-h"))return WV();let U=$.find((w)=>w.trim()!=="");if(U)throw Error(`Unknown learn argument: ${U}
|
|
263
263
|
|
|
264
264
|
${WV()}`);return RT}import{readFile as RE}from"node:fs/promises";import{dirname as kE,extname as fE,resolve as Eq}from"node:path";var lb=hY(),rb=k0(),db=FY(),sY=f0(),nb=P0(),e4=p(),pb=n4(),tb=N$(),ab=t4(),ob=a4(),td=iJ(),eb=aY(),sb=oY(),$E=eY(),lJ=Zq(),Tq=L0();var UE=lb.Composer,wE=rb.Document,zE=db.Schema,JE=sY.YAMLError,XE=sY.YAMLParseError,GE=sY.YAMLWarning,NE=nb.Alias,_E=e4.isAlias,YE=e4.isCollection,WE=e4.isDocument,QE=e4.isMap,VE=e4.isNode,BE=e4.isPair,qE=e4.isScalar,HE=e4.isSeq,KE=pb.Pair,LE=tb.Scalar,IE=ab.YAMLMap,PE=ob.YAMLSeq;var ZE=eb.Lexer,TE=sb.LineCounter,gE=$E.Parser,$W=lJ.parse,DE=lJ.parseAllDocuments,OE=lJ.parseDocument,FE=lJ.stringify,ME=Tq.visit,vE=Tq.visitAsync;class UW{id="openai";capabilities=["image.generate","image.edit"];async runImageGenerate($,U){let w=gq(U),J={...$.params,prompt:$.prompt},z=await Dq(w).generate(J),X=await Oq({response:z,output:$.output,format:Mq($.params),defaultName:$.id??"image"}),G={id:$.id,kind:"image.generate",provider:this.id,profile:U.credential.profile,outputs:X,metadata:Fq(z,$.params)};if($.sidecar??U.sidecar??!0)await iX(G,$,"image.generate");return G}async runImageEdit($,U){let w=gq(U),J=$.inputs.filter((V)=>V.role==="image"),z=$.inputs.find((V)=>V.role==="mask");if(J.length===0)throw Error("At least one --image input is required for image edits.");let X=await Promise.all(J.map(yX)),G=z?await yX(z):void 0,N=X.length===1?X[0]:X,_={...$.params,prompt:$.prompt,image:N,...G?{mask:G}:{}},Y=await Dq(w).edit(_),W=await Oq({response:Y,output:$.output,format:Mq($.params),defaultName:$.id??"edited-image"}),Q={id:$.id,kind:"image.edit",provider:this.id,profile:U.credential.profile,outputs:W,metadata:Fq(Y,$.params)};if($.sidecar??U.sidecar??!0)await iX(Q,$,"image.edit");return Q}}function gq($){let U=$.credential;if(!U.apiKey)throw Error("No OpenAI API key found. Run 'ploof login openai --api-key <key>' or set PLOOF_OPENAI_API_KEY.");return new i({apiKey:U.apiKey,organization:U.organization,project:U.project,baseURL:U.baseURL})}function Dq($){return $.images}async function Oq($){if(EE($.response))return SE($);let U=vq($.response),w=U.length,J=[];for(let z=0;z<U.length;z++){let X=U[z];if(X.b64_json)J.push(await Pz({data:X.b64_json,output:$.output,index:z,total:w,format:$.format,defaultName:$.defaultName}));else if(X.url)J.push(await dQ({url:X.url,output:$.output,index:z,total:w,format:$.format,defaultName:$.defaultName}))}if(J.length===0)throw Error("OpenAI response did not include image data or URLs.");return J}async function SE($){let U=[],w=0;for await(let J of $.response)for(let z of bE(J))U.push(await Pz({data:z,output:$.output,index:w,total:2,format:$.format,defaultName:$.defaultName})),w+=1;return U}function Fq($,U){let w=$&&typeof $==="object"?$:{};return{model:U?.model,created:w.created,usage:w.usage,revisedPrompts:vq($).map((J)=>J.revised_prompt).filter(Boolean)}}function vq($){if(!$||typeof $!=="object")return[];let U=$.data;return Array.isArray(U)?U:[]}function bE($){if(!$||typeof $!=="object")return[];let U=[],w=(J)=>{if(!J||typeof J!=="object")return;for(let[z,X]of Object.entries(J))if(typeof X==="string"&&(z==="b64_json"||z==="partial_image_b64"||z==="image_b64"))U.push(X);else if(typeof X==="object")w(X)};return w($),U}function Mq($){return $?.output_format??$?.format}function EE($){return Boolean($&&typeof $==="object"&&Symbol.asyncIterator in $)}var AE=[new UW];function rJ($){let U=AE.find((w)=>w.id===$);if(!U)throw Error(`Unknown provider: ${$}`);return U}var Sq=y.union([y.string(),y.object({source:y.string().optional(),task:y.string().optional(),mime:y.string().optional(),name:y.string().optional()})]),jE=y.object({id:y.string(),kind:y.enum(["image.generate","image.edit"]),provider:y.string().default("openai"),profile:y.string().optional(),needs:y.array(y.string()).default([]),prompt:y.string(),params:y.record(y.string(),y.unknown()).default({}),output:y.string().optional(),sidecar:y.boolean().optional(),inputs:y.object({images:y.array(Sq).optional(),mask:Sq.optional()}).optional()}),CE=y.object({version:y.union([y.literal(1),y.string()]).default(1),parallel:y.number().int().positive().optional(),tasks:y.array(jE).min(1)});async function uE($){let U=await RE($,"utf-8"),J=fE($).toLowerCase()===".json"?JSON.parse(U):$W(U),z=CE.parse(J);return xE(z),z}async function Aq($,U={}){let w=await uE($),J=U.parallel??w.parallel??4,z=kE(Eq($));if(U.dryRun)return w.tasks.map((Q)=>({id:Q.id,kind:Q.kind,provider:Q.provider,profile:Q.profile,outputs:Q.output?[dJ(z,Q.output)]:[],metadata:{dryRun:!0,needs:Q.needs}}));let X=U.auth??new g4,G=new Map,N=new Map,_=new Map(w.tasks.map((Q)=>[Q.id,Q])),Y=[],W;while(_.size>0||N.size>0){if(W)throw W;for(let[Q,V]of[..._]){if(N.size>=J)break;if(!V.needs.every((K)=>G.has(K)))continue;_.delete(Q);let B=yE(V,{auth:X,baseDir:z,completed:G,verbose:U.verbose,sidecar:U.config?.get("sidecar")??!0}).then((K)=>{G.set(Q,K),Y.push(K)}).catch((K)=>{W=K}).finally(()=>{N.delete(Q)});N.set(Q,B)}if(N.size===0&&_.size>0)throw Error("Manifest has unresolved dependencies.");if(N.size>0)await Promise.race(N.values())}if(W)throw W;return Y}function xE($){let U=new Set;for(let w of $.tasks){if(U.has(w.id))throw Error(`Duplicate task id: ${w.id}`);U.add(w.id)}for(let w of $.tasks)for(let J of w.needs)if(!U.has(J))throw Error(`Task ${w.id} depends on unknown task ${J}.`)}async function yE($,U){let w=rJ($.provider),J=U.auth.getCredential($.provider,$.profile);if(!J?.apiKey)throw Error(`No credentials found for ${$.provider}. Run 'ploof login ${$.provider}'.`);let z={id:$.id,kind:$.kind,provider:$.provider,profile:$.profile,prompt:$.prompt,params:$.params,output:$.output?dJ(U.baseDir,$.output):void 0,sidecar:$.sidecar??U.sidecar};if($.kind==="image.generate")return w.runImageGenerate({...z,kind:"image.generate"},{credential:J,verbose:U.verbose,sidecar:z.sidecar});let X=iE($,U);return w.runImageEdit({...z,kind:"image.edit",inputs:X},{credential:J,verbose:U.verbose,sidecar:z.sidecar})}function iE($,U){let w=[];for(let J of $.inputs?.images??[])w.push({role:"image",source:bq(J,U)});if($.inputs?.mask)w.push({role:"mask",source:bq($.inputs.mask,U)});return w}function bq($,U){if(typeof $==="string")return dJ(U.baseDir,$);if($.task){let J=U.completed.get($.task)?.outputs[0];if(!J)throw Error(`Task output not available: ${$.task}`);return J}if($.source)return dJ(U.baseDir,$.source);throw Error("Input reference must include source or task.")}function dJ($,U){if(U.startsWith("/")||U.startsWith("http://")||U.startsWith("https://")||U==="-")return U;return Eq($,U)}function Rq($,U,w,J){let z=$??w??U;if(z&&z!=="auto"){if(rE(z))return z;throw Error(`Invalid output format: ${z}`)}return J?"table":"compact"}function kq($,U){let w=Array.isArray($)?$:[$],J=U.fields?.length?w.map((z)=>cE(z,U.fields)):w;switch(U.format){case"json":return JSON.stringify(Array.isArray($)?J:J[0],null,2);case"jsonl":return J.map((z)=>JSON.stringify(z)).join(`
|
|
265
265
|
`);case"table":return mE(w,U);case"compact":return w.map(hE).join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miketromba/ploof",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "AI asset generation CLI for OpenAI images today, designed for multi-provider creative workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"skills",
|
|
12
|
+
"assets/brand/ploof-banner.png",
|
|
12
13
|
"README.md",
|
|
13
14
|
"LICENSE",
|
|
14
15
|
"SPEC.md"
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
"format": "bunx biome format --write .",
|
|
27
28
|
"typecheck": "bunx tsc --noEmit",
|
|
28
29
|
"prepublishOnly": "bun run lint && bun run typecheck && bun test && bun run build",
|
|
29
|
-
"release": "bun run lint && bun run typecheck && bun test && bun run build && npm pack --dry-run
|
|
30
|
+
"release": "bun run lint && bun run typecheck && bun test && bun run build && npm pack --dry-run",
|
|
30
31
|
"ploof": "bun run bin/ploof.ts",
|
|
31
32
|
"prepare": "husky || true"
|
|
32
33
|
},
|