pixcli 0.1.1
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/dist/commands/edit.d.ts +2 -0
- package/dist/commands/edit.js +134 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/image.d.ts +2 -0
- package/dist/commands/image.js +140 -0
- package/dist/commands/image.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/client.d.ts +29 -0
- package/dist/lib/client.js +76 -0
- package/dist/lib/client.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.js +12 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/download.d.ts +13 -0
- package/dist/lib/download.js +65 -0
- package/dist/lib/download.js.map +1 -0
- package/dist/lib/output.d.ts +11 -0
- package/dist/lib/output.js +56 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/poller.d.ts +30 -0
- package/dist/lib/poller.js +18 -0
- package/dist/lib/poller.js.map +1 -0
- package/dist/lib/upload.d.ts +10 -0
- package/dist/lib/upload.js +52 -0
- package/dist/lib/upload.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { PixClient } from "../lib/client.js";
|
|
3
|
+
import { resolveApiKey, resolveBaseUrl } from "../lib/config.js";
|
|
4
|
+
import { pollJob, getJobResult } from "../lib/poller.js";
|
|
5
|
+
import { downloadAssets } from "../lib/download.js";
|
|
6
|
+
import { setJsonMode, isJsonMode, startSpinner, updateSpinner, succeedSpinner, failSpinner, printSuccess, printInfo, printJson, printError, } from "../lib/output.js";
|
|
7
|
+
import { ApiError } from "../lib/client.js";
|
|
8
|
+
import { resolveImageArgs } from "../lib/upload.js";
|
|
9
|
+
export const editCommand = new Command("edit")
|
|
10
|
+
.description("Edit an existing image with a text prompt")
|
|
11
|
+
.argument("<prompt>", "Text description of the edit to perform")
|
|
12
|
+
.requiredOption("-i, --image <path-or-url>", "Source image — local file or URL (repeat for multiple: -i a.png -i b.png)", (val, prev) => prev.concat(val), [])
|
|
13
|
+
.option("-q, --quality <level>", "Quality level (draft, standard, high)", "standard")
|
|
14
|
+
.option("-m, --model <model>", "Specific model ID (uses advanced endpoint)")
|
|
15
|
+
.option("-o, --output <path>", "Output file or directory path")
|
|
16
|
+
.option("--json", "Output machine-readable JSON", false)
|
|
17
|
+
.option("--no-enrich", "Skip prompt enrichment (advanced mode only)")
|
|
18
|
+
.action(async (prompt, opts) => {
|
|
19
|
+
const globalOpts = editCommand.parent?.opts();
|
|
20
|
+
if (opts.json)
|
|
21
|
+
setJsonMode(true);
|
|
22
|
+
let client;
|
|
23
|
+
try {
|
|
24
|
+
const apiKey = resolveApiKey(globalOpts);
|
|
25
|
+
const baseUrl = resolveBaseUrl(globalOpts);
|
|
26
|
+
client = new PixClient(baseUrl, apiKey);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
printError(err.message);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
const start = Date.now();
|
|
33
|
+
try {
|
|
34
|
+
const images = opts.image;
|
|
35
|
+
if (images.length === 0) {
|
|
36
|
+
printError("At least one image is required (-i <path-or-url>)");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
startSpinner(images.length > 1 ? `Preparing ${images.length} images...` : "Preparing...");
|
|
40
|
+
const imageUrls = await resolveImageArgs(client, images, (i, total) => {
|
|
41
|
+
updateSpinner(total > 1 ? `Uploading image ${i}/${total}...` : "Uploading image...");
|
|
42
|
+
});
|
|
43
|
+
const imagePayload = imageUrls.length === 1 ? imageUrls[0] : imageUrls;
|
|
44
|
+
let response;
|
|
45
|
+
if (opts.model) {
|
|
46
|
+
updateSpinner(`Editing with ${opts.model}...`);
|
|
47
|
+
response = await client.post("/api/v1/edit/advanced", {
|
|
48
|
+
prompt,
|
|
49
|
+
model: opts.model,
|
|
50
|
+
image: imagePayload,
|
|
51
|
+
enrich_prompt: opts.enrich !== false ? true : false,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
updateSpinner("Editing...");
|
|
56
|
+
response = await client.post("/api/v1/edit", {
|
|
57
|
+
prompt,
|
|
58
|
+
image: imagePayload,
|
|
59
|
+
quality: opts.quality,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (!isJsonMode()) {
|
|
63
|
+
printInfo(`Job ${response.job_id} submitted (model: ${response.model || "auto"})`);
|
|
64
|
+
}
|
|
65
|
+
updateSpinner("Processing...");
|
|
66
|
+
const finalStatus = await pollJob(client, response.job_id, {
|
|
67
|
+
onStatus: (s) => {
|
|
68
|
+
if (s.total_steps > 1) {
|
|
69
|
+
updateSpinner(`Processing step ${s.current_step}/${s.total_steps}...`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
if (finalStatus.status !== "completed") {
|
|
74
|
+
failSpinner(`Job failed: ${finalStatus.error || "unknown error"}`);
|
|
75
|
+
if (isJsonMode()) {
|
|
76
|
+
printJson({
|
|
77
|
+
job_id: response.job_id,
|
|
78
|
+
status: finalStatus.status,
|
|
79
|
+
error: finalStatus.error,
|
|
80
|
+
elapsed_ms: Date.now() - start,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
const result = await getJobResult(client, response.job_id);
|
|
86
|
+
if (result.assets.length === 0) {
|
|
87
|
+
failSpinner("No assets returned");
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
updateSpinner("Downloading...");
|
|
91
|
+
const files = await downloadAssets(client, result.assets, prompt, opts.output);
|
|
92
|
+
const elapsed = Date.now() - start;
|
|
93
|
+
succeedSpinner("Done!");
|
|
94
|
+
if (isJsonMode()) {
|
|
95
|
+
printJson({
|
|
96
|
+
job_id: response.job_id,
|
|
97
|
+
status: "completed",
|
|
98
|
+
files: files.map((f) => ({
|
|
99
|
+
path: f.path,
|
|
100
|
+
width: f.width,
|
|
101
|
+
height: f.height,
|
|
102
|
+
mime_type: f.mime_type,
|
|
103
|
+
})),
|
|
104
|
+
model: response.model,
|
|
105
|
+
cost: finalStatus.cost,
|
|
106
|
+
elapsed_ms: elapsed,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
for (const f of files) {
|
|
111
|
+
const dims = f.width && f.height ? ` (${f.width}x${f.height})` : "";
|
|
112
|
+
printSuccess(`Edited ${f.path}${dims}`);
|
|
113
|
+
}
|
|
114
|
+
printInfo(`${files.length} file(s) · ${(elapsed / 1000).toFixed(1)}s · cost: ${finalStatus.cost ?? "n/a"}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
failSpinner("Failed");
|
|
119
|
+
if (err instanceof ApiError) {
|
|
120
|
+
printError(`API error (${err.status}): ${err.message}`);
|
|
121
|
+
if (isJsonMode()) {
|
|
122
|
+
printJson({ error: err.message, status: err.status, elapsed_ms: Date.now() - start });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
printError(err.message);
|
|
127
|
+
if (isJsonMode()) {
|
|
128
|
+
printJson({ error: err.message, elapsed_ms: Date.now() - start });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/commands/edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { PixClient } from "../lib/client.js";
|
|
3
|
+
import { resolveApiKey, resolveBaseUrl } from "../lib/config.js";
|
|
4
|
+
import { pollJob, getJobResult } from "../lib/poller.js";
|
|
5
|
+
import { downloadAssets } from "../lib/download.js";
|
|
6
|
+
import { setJsonMode, isJsonMode, startSpinner, updateSpinner, succeedSpinner, failSpinner, printSuccess, printInfo, printJson, printError, } from "../lib/output.js";
|
|
7
|
+
import { ApiError } from "../lib/client.js";
|
|
8
|
+
import { resolveImageArg } from "../lib/upload.js";
|
|
9
|
+
export const imageCommand = new Command("image")
|
|
10
|
+
.description("Generate an image from a text prompt")
|
|
11
|
+
.argument("<prompt>", "Text description of the image to generate")
|
|
12
|
+
.option("-r, --ratio <ratio>", "Aspect ratio (1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3)", "1:1")
|
|
13
|
+
.option("-q, --quality <level>", "Quality level (draft, standard, high)", "standard")
|
|
14
|
+
.option("-t, --transparent", "Generate with transparent background", false)
|
|
15
|
+
.option("-n, --count <number>", "Number of images (1-4)", "1")
|
|
16
|
+
.option("--from <path-or-url>", "Source image (local file or URL) for image-to-image generation")
|
|
17
|
+
.option("-m, --model <model>", "Specific model ID (uses advanced endpoint)")
|
|
18
|
+
.option("-o, --output <path>", "Output file or directory path")
|
|
19
|
+
.option("--json", "Output machine-readable JSON", false)
|
|
20
|
+
.option("--no-enrich", "Skip prompt enrichment (advanced mode only)")
|
|
21
|
+
.action(async (prompt, opts) => {
|
|
22
|
+
const globalOpts = imageCommand.parent?.opts();
|
|
23
|
+
if (opts.json)
|
|
24
|
+
setJsonMode(true);
|
|
25
|
+
let client;
|
|
26
|
+
try {
|
|
27
|
+
const apiKey = resolveApiKey(globalOpts);
|
|
28
|
+
const baseUrl = resolveBaseUrl(globalOpts);
|
|
29
|
+
client = new PixClient(baseUrl, apiKey);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
printError(err.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
try {
|
|
37
|
+
let fromUrl;
|
|
38
|
+
if (opts.from) {
|
|
39
|
+
startSpinner("Preparing...");
|
|
40
|
+
fromUrl = await resolveImageArg(client, opts.from, () => {
|
|
41
|
+
updateSpinner("Uploading source image...");
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
let response;
|
|
45
|
+
if (opts.model) {
|
|
46
|
+
startSpinner(`Generating with ${opts.model}...`);
|
|
47
|
+
response = await client.post("/api/v1/generate/advanced", {
|
|
48
|
+
prompt,
|
|
49
|
+
model: opts.model,
|
|
50
|
+
image: fromUrl,
|
|
51
|
+
enrich_prompt: opts.enrich !== false ? true : false,
|
|
52
|
+
params: {
|
|
53
|
+
aspect_ratio: opts.ratio,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
startSpinner("Generating...");
|
|
59
|
+
response = await client.post("/api/v1/generate", {
|
|
60
|
+
prompt,
|
|
61
|
+
image: fromUrl,
|
|
62
|
+
aspect_ratio: opts.ratio,
|
|
63
|
+
quality: opts.quality,
|
|
64
|
+
transparent: opts.transparent,
|
|
65
|
+
num_images: parseInt(opts.count, 10),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (!isJsonMode()) {
|
|
69
|
+
printInfo(`Job ${response.job_id} submitted (model: ${response.model || "auto"})`);
|
|
70
|
+
}
|
|
71
|
+
updateSpinner("Processing...");
|
|
72
|
+
const finalStatus = await pollJob(client, response.job_id, {
|
|
73
|
+
onStatus: (s) => {
|
|
74
|
+
if (s.total_steps > 1) {
|
|
75
|
+
updateSpinner(`Processing step ${s.current_step}/${s.total_steps}...`);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
if (finalStatus.status !== "completed") {
|
|
80
|
+
failSpinner(`Job failed: ${finalStatus.error || "unknown error"}`);
|
|
81
|
+
if (isJsonMode()) {
|
|
82
|
+
printJson({
|
|
83
|
+
job_id: response.job_id,
|
|
84
|
+
status: finalStatus.status,
|
|
85
|
+
error: finalStatus.error,
|
|
86
|
+
elapsed_ms: Date.now() - start,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const result = await getJobResult(client, response.job_id);
|
|
92
|
+
if (result.assets.length === 0) {
|
|
93
|
+
failSpinner("No assets returned");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
updateSpinner("Downloading...");
|
|
97
|
+
const files = await downloadAssets(client, result.assets, prompt, opts.output);
|
|
98
|
+
const elapsed = Date.now() - start;
|
|
99
|
+
succeedSpinner("Done!");
|
|
100
|
+
if (isJsonMode()) {
|
|
101
|
+
printJson({
|
|
102
|
+
job_id: response.job_id,
|
|
103
|
+
status: "completed",
|
|
104
|
+
files: files.map((f) => ({
|
|
105
|
+
path: f.path,
|
|
106
|
+
width: f.width,
|
|
107
|
+
height: f.height,
|
|
108
|
+
mime_type: f.mime_type,
|
|
109
|
+
})),
|
|
110
|
+
model: response.model,
|
|
111
|
+
cost: finalStatus.cost,
|
|
112
|
+
elapsed_ms: elapsed,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
for (const f of files) {
|
|
117
|
+
const dims = f.width && f.height ? ` (${f.width}x${f.height})` : "";
|
|
118
|
+
printSuccess(`Created ${f.path}${dims}`);
|
|
119
|
+
}
|
|
120
|
+
printInfo(`${files.length} file(s) · ${(elapsed / 1000).toFixed(1)}s · cost: ${finalStatus.cost ?? "n/a"}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
failSpinner("Failed");
|
|
125
|
+
if (err instanceof ApiError) {
|
|
126
|
+
printError(`API error (${err.status}): ${err.message}`);
|
|
127
|
+
if (isJsonMode()) {
|
|
128
|
+
printJson({ error: err.message, status: err.status, elapsed_ms: Date.now() - start });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
printError(err.message);
|
|
133
|
+
if (isJsonMode()) {
|
|
134
|
+
printJson({ error: err.message, elapsed_ms: Date.now() - start });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/commands/image.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { imageCommand } from "./commands/image.js";
|
|
4
|
+
import { editCommand } from "./commands/edit.js";
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name("pixcli")
|
|
8
|
+
.description("The creative toolkit for AI agents — generate and edit images from the command line.")
|
|
9
|
+
.version("0.1.0")
|
|
10
|
+
.option("--key <api_key>", "API key (overrides PIXCLI_API_KEY env var)")
|
|
11
|
+
.option("--api-url <url>", "Base API URL (overrides PIXCLI_API_URL env var)");
|
|
12
|
+
program.addCommand(imageCommand);
|
|
13
|
+
program.addCommand(editCommand);
|
|
14
|
+
program.parse();
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACL,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,sFAAsF,CAAC;KACnG,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,iBAAiB,EAAE,4CAA4C,CAAC;KACvE,MAAM,CAAC,iBAAiB,EAAE,iDAAiD,CAAC,CAAC;AAE/E,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
body: {
|
|
4
|
+
error: string;
|
|
5
|
+
details?: unknown;
|
|
6
|
+
};
|
|
7
|
+
constructor(status: number, body: {
|
|
8
|
+
error: string;
|
|
9
|
+
details?: unknown;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export declare class PixClient {
|
|
13
|
+
private baseUrl;
|
|
14
|
+
private apiKey;
|
|
15
|
+
constructor(baseUrl: string, apiKey: string);
|
|
16
|
+
private headers;
|
|
17
|
+
post<T = unknown>(path: string, body: unknown): Promise<T>;
|
|
18
|
+
get<T = unknown>(path: string): Promise<T>;
|
|
19
|
+
upload(path: string, formData: FormData): Promise<{
|
|
20
|
+
url: string;
|
|
21
|
+
hash: string;
|
|
22
|
+
mime_type: string;
|
|
23
|
+
size: number;
|
|
24
|
+
}>;
|
|
25
|
+
getStream(path: string): Promise<{
|
|
26
|
+
body: ReadableStream<Uint8Array>;
|
|
27
|
+
contentType: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
body;
|
|
4
|
+
constructor(status, body) {
|
|
5
|
+
const details = body.details
|
|
6
|
+
? `\n${body.details.map((d) => ` - ${d.path}: ${d.message}`).join("\n")}`
|
|
7
|
+
: "";
|
|
8
|
+
super(`${body.error}${details}`);
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.body = body;
|
|
11
|
+
this.name = "ApiError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class PixClient {
|
|
15
|
+
baseUrl;
|
|
16
|
+
apiKey;
|
|
17
|
+
constructor(baseUrl, apiKey) {
|
|
18
|
+
this.baseUrl = baseUrl;
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
}
|
|
21
|
+
headers(json = true) {
|
|
22
|
+
const h = {
|
|
23
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
24
|
+
};
|
|
25
|
+
if (json)
|
|
26
|
+
h["Content-Type"] = "application/json";
|
|
27
|
+
return h;
|
|
28
|
+
}
|
|
29
|
+
async post(path, body) {
|
|
30
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: this.headers(),
|
|
33
|
+
body: JSON.stringify(body),
|
|
34
|
+
});
|
|
35
|
+
const data = await res.json();
|
|
36
|
+
if (!res.ok)
|
|
37
|
+
throw new ApiError(res.status, data);
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
async get(path) {
|
|
41
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
42
|
+
headers: this.headers(false),
|
|
43
|
+
});
|
|
44
|
+
const data = await res.json();
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
throw new ApiError(res.status, data);
|
|
47
|
+
return data;
|
|
48
|
+
}
|
|
49
|
+
async upload(path, formData) {
|
|
50
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
53
|
+
body: formData,
|
|
54
|
+
});
|
|
55
|
+
const data = await res.json();
|
|
56
|
+
if (!res.ok)
|
|
57
|
+
throw new ApiError(res.status, data);
|
|
58
|
+
return data;
|
|
59
|
+
}
|
|
60
|
+
async getStream(path) {
|
|
61
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
62
|
+
headers: this.headers(false),
|
|
63
|
+
});
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const data = await res.json();
|
|
66
|
+
throw new ApiError(res.status, data);
|
|
67
|
+
}
|
|
68
|
+
if (!res.body)
|
|
69
|
+
throw new Error("Empty response body");
|
|
70
|
+
return {
|
|
71
|
+
body: res.body,
|
|
72
|
+
contentType: res.headers.get("content-type") || "application/octet-stream",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const DEFAULT_API_URL = "https://pixcli.shellbot.sh";
|
|
2
|
+
export function resolveApiKey(opts) {
|
|
3
|
+
const key = opts.key || process.env.PIXCLI_API_KEY;
|
|
4
|
+
if (!key) {
|
|
5
|
+
throw new Error("No API key provided. Use --key <key> or set PIXCLI_API_KEY environment variable.");
|
|
6
|
+
}
|
|
7
|
+
return key;
|
|
8
|
+
}
|
|
9
|
+
export function resolveBaseUrl(opts) {
|
|
10
|
+
return opts.apiUrl || process.env.PIXCLI_API_URL || DEFAULT_API_URL;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,4BAA4B,CAAC;AAOrD,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACnD,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACd,kFAAkF,CAClF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAgB;IAC9C,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PixClient } from "./client.js";
|
|
2
|
+
export interface DownloadedFile {
|
|
3
|
+
path: string;
|
|
4
|
+
mime_type: string;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function downloadAssets(client: PixClient, assets: Array<{
|
|
9
|
+
url: string;
|
|
10
|
+
mime_type: string;
|
|
11
|
+
width?: number;
|
|
12
|
+
height?: number;
|
|
13
|
+
}>, prompt: string, outputPath?: string): Promise<DownloadedFile[]>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
3
|
+
const MIME_TO_EXT = {
|
|
4
|
+
"image/png": ".png",
|
|
5
|
+
"image/jpeg": ".jpg",
|
|
6
|
+
"image/webp": ".webp",
|
|
7
|
+
"image/gif": ".gif",
|
|
8
|
+
"image/svg+xml": ".svg",
|
|
9
|
+
"video/mp4": ".mp4",
|
|
10
|
+
"video/webm": ".webm",
|
|
11
|
+
};
|
|
12
|
+
function slugify(text) {
|
|
13
|
+
return text
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
16
|
+
.replace(/^-|-$/g, "")
|
|
17
|
+
.slice(0, 48);
|
|
18
|
+
}
|
|
19
|
+
function extFromMime(mime) {
|
|
20
|
+
return MIME_TO_EXT[mime] || ".bin";
|
|
21
|
+
}
|
|
22
|
+
export async function downloadAssets(client, assets, prompt, outputPath) {
|
|
23
|
+
const slug = slugify(prompt);
|
|
24
|
+
const results = [];
|
|
25
|
+
for (let i = 0; i < assets.length; i++) {
|
|
26
|
+
const asset = assets[i];
|
|
27
|
+
const ext = extFromMime(asset.mime_type);
|
|
28
|
+
let filePath;
|
|
29
|
+
if (outputPath) {
|
|
30
|
+
const resolved = resolve(outputPath);
|
|
31
|
+
if (assets.length === 1 && extname(resolved)) {
|
|
32
|
+
filePath = resolved;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const suffix = assets.length > 1 ? `_${i + 1}` : "";
|
|
36
|
+
filePath = join(resolved, `${slug}${suffix}${ext}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const suffix = assets.length > 1 ? `_${i + 1}` : "";
|
|
41
|
+
filePath = join(process.cwd(), `${slug}${suffix}${ext}`);
|
|
42
|
+
}
|
|
43
|
+
await mkdir(dirname(filePath), { recursive: true });
|
|
44
|
+
const urlPath = new URL(asset.url).pathname;
|
|
45
|
+
const stream = await client.getStream(urlPath);
|
|
46
|
+
const chunks = [];
|
|
47
|
+
const reader = stream.body.getReader();
|
|
48
|
+
while (true) {
|
|
49
|
+
const { done, value } = await reader.read();
|
|
50
|
+
if (done)
|
|
51
|
+
break;
|
|
52
|
+
chunks.push(value);
|
|
53
|
+
}
|
|
54
|
+
const buffer = Buffer.concat(chunks);
|
|
55
|
+
await writeFile(filePath, buffer);
|
|
56
|
+
results.push({
|
|
57
|
+
path: filePath,
|
|
58
|
+
mime_type: asset.mime_type,
|
|
59
|
+
width: asset.width,
|
|
60
|
+
height: asset.height,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return results;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/lib/download.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function setJsonMode(enabled: boolean): void;
|
|
2
|
+
export declare function isJsonMode(): boolean;
|
|
3
|
+
export declare function startSpinner(text: string): void;
|
|
4
|
+
export declare function updateSpinner(text: string): void;
|
|
5
|
+
export declare function succeedSpinner(text: string): void;
|
|
6
|
+
export declare function failSpinner(text: string): void;
|
|
7
|
+
export declare function stopSpinner(): void;
|
|
8
|
+
export declare function printSuccess(message: string): void;
|
|
9
|
+
export declare function printError(message: string): void;
|
|
10
|
+
export declare function printInfo(message: string): void;
|
|
11
|
+
export declare function printJson(data: unknown): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
let jsonMode = false;
|
|
4
|
+
let spinner = null;
|
|
5
|
+
export function setJsonMode(enabled) {
|
|
6
|
+
jsonMode = enabled;
|
|
7
|
+
}
|
|
8
|
+
export function isJsonMode() {
|
|
9
|
+
return jsonMode;
|
|
10
|
+
}
|
|
11
|
+
export function startSpinner(text) {
|
|
12
|
+
if (jsonMode)
|
|
13
|
+
return;
|
|
14
|
+
spinner = ora({ text, color: "cyan" }).start();
|
|
15
|
+
}
|
|
16
|
+
export function updateSpinner(text) {
|
|
17
|
+
if (spinner)
|
|
18
|
+
spinner.text = text;
|
|
19
|
+
}
|
|
20
|
+
export function succeedSpinner(text) {
|
|
21
|
+
if (spinner) {
|
|
22
|
+
spinner.succeed(text);
|
|
23
|
+
spinner = null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function failSpinner(text) {
|
|
27
|
+
if (spinner) {
|
|
28
|
+
spinner.fail(text);
|
|
29
|
+
spinner = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function stopSpinner() {
|
|
33
|
+
if (spinner) {
|
|
34
|
+
spinner.stop();
|
|
35
|
+
spinner = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function printSuccess(message) {
|
|
39
|
+
if (jsonMode)
|
|
40
|
+
return;
|
|
41
|
+
console.log(chalk.green("✓"), message);
|
|
42
|
+
}
|
|
43
|
+
export function printError(message) {
|
|
44
|
+
if (jsonMode)
|
|
45
|
+
return;
|
|
46
|
+
console.error(chalk.red("✗"), message);
|
|
47
|
+
}
|
|
48
|
+
export function printInfo(message) {
|
|
49
|
+
if (jsonMode)
|
|
50
|
+
return;
|
|
51
|
+
console.log(chalk.dim(message));
|
|
52
|
+
}
|
|
53
|
+
export function printJson(data) {
|
|
54
|
+
console.log(JSON.stringify(data, null, 2));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAiB,MAAM,KAAK,CAAC;AAEpC,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB,IAAI,OAAO,GAAe,IAAI,CAAC;AAE/B,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC3C,QAAQ,GAAG,OAAO,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,UAAU;IACzB,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACxC,IAAI,QAAQ;QAAE,OAAO;IACrB,OAAO,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACzC,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IAC1C,IAAI,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,IAAI,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,WAAW;IAC1B,IAAI,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,GAAG,IAAI,CAAC;IAChB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC3C,IAAI,QAAQ;QAAE,OAAO;IACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACzC,IAAI,QAAQ;QAAE,OAAO;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe;IACxC,IAAI,QAAQ;QAAE,OAAO;IACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAa;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PixClient } from "./client.js";
|
|
2
|
+
export interface JobStatus {
|
|
3
|
+
job_id: string;
|
|
4
|
+
status: "pending" | "processing" | "completed" | "failed" | "cancelled";
|
|
5
|
+
type: string;
|
|
6
|
+
mode: string;
|
|
7
|
+
current_step: number;
|
|
8
|
+
total_steps: number;
|
|
9
|
+
cost?: number;
|
|
10
|
+
error?: string;
|
|
11
|
+
created_at: string;
|
|
12
|
+
completed_at?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface JobResult extends JobStatus {
|
|
15
|
+
assets: Array<{
|
|
16
|
+
url: string;
|
|
17
|
+
mime_type: string;
|
|
18
|
+
width?: number;
|
|
19
|
+
height?: number;
|
|
20
|
+
}>;
|
|
21
|
+
classification?: unknown;
|
|
22
|
+
pipeline_summary?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PollOptions {
|
|
25
|
+
intervalMs?: number;
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
onStatus?: (status: JobStatus) => void;
|
|
28
|
+
}
|
|
29
|
+
export declare function pollJob(client: PixClient, jobId: string, opts?: PollOptions): Promise<JobStatus>;
|
|
30
|
+
export declare function getJobResult(client: PixClient, jobId: string): Promise<JobResult>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const TERMINAL_STATES = new Set(["completed", "failed", "cancelled"]);
|
|
2
|
+
export async function pollJob(client, jobId, opts = {}) {
|
|
3
|
+
const interval = opts.intervalMs ?? 2000;
|
|
4
|
+
const timeout = opts.timeoutMs ?? 120_000;
|
|
5
|
+
const start = Date.now();
|
|
6
|
+
while (Date.now() - start < timeout) {
|
|
7
|
+
const status = await client.get(`/api/v1/jobs/${jobId}`);
|
|
8
|
+
opts.onStatus?.(status);
|
|
9
|
+
if (TERMINAL_STATES.has(status.status))
|
|
10
|
+
return status;
|
|
11
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
12
|
+
}
|
|
13
|
+
throw new Error(`Job ${jobId} timed out after ${timeout / 1000}s`);
|
|
14
|
+
}
|
|
15
|
+
export async function getJobResult(client, jobId) {
|
|
16
|
+
return client.get(`/api/v1/jobs/${jobId}/result`);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=poller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poller.js","sourceRoot":"","sources":["../../src/lib/poller.ts"],"names":[],"mappings":"AA0BA,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAQtE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC5B,MAAiB,EACjB,KAAa,EACb,OAAoB,EAAE;IAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,OAAO,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAY,gBAAgB,KAAK,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;QAExB,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;QAEtD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,oBAAoB,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,MAAiB,EACjB,KAAa;IAEb,OAAO,MAAM,CAAC,GAAG,CAAY,gBAAgB,KAAK,SAAS,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PixClient } from "./client.js";
|
|
2
|
+
/**
|
|
3
|
+
* If the value is a local file path, uploads it and returns the remote URL.
|
|
4
|
+
* If it's already a URL, returns it as-is.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveImageArg(client: PixClient, value: string, onUploadStart?: () => void): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve an array of image arguments (local files or URLs) to remote URLs.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveImageArgs(client: PixClient, values: string[], onUploadStart?: (index: number, total: number) => void): Promise<string[]>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { basename, resolve } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
const EXT_TO_MIME = {
|
|
5
|
+
".png": "image/png",
|
|
6
|
+
".jpg": "image/jpeg",
|
|
7
|
+
".jpeg": "image/jpeg",
|
|
8
|
+
".webp": "image/webp",
|
|
9
|
+
".gif": "image/gif",
|
|
10
|
+
".avif": "image/avif",
|
|
11
|
+
};
|
|
12
|
+
function isLocalPath(value) {
|
|
13
|
+
if (value.startsWith("http://") || value.startsWith("https://"))
|
|
14
|
+
return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
function mimeFromPath(filePath) {
|
|
18
|
+
const ext = filePath.toLowerCase().match(/\.\w+$/)?.[0] || "";
|
|
19
|
+
return EXT_TO_MIME[ext] || "image/png";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* If the value is a local file path, uploads it and returns the remote URL.
|
|
23
|
+
* If it's already a URL, returns it as-is.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolveImageArg(client, value, onUploadStart) {
|
|
26
|
+
if (!isLocalPath(value))
|
|
27
|
+
return value;
|
|
28
|
+
const abs = resolve(value);
|
|
29
|
+
if (!existsSync(abs)) {
|
|
30
|
+
throw new Error(`File not found: ${abs}`);
|
|
31
|
+
}
|
|
32
|
+
onUploadStart?.();
|
|
33
|
+
const buffer = await readFile(abs);
|
|
34
|
+
const mime = mimeFromPath(abs);
|
|
35
|
+
const blob = new Blob([buffer], { type: mime });
|
|
36
|
+
const formData = new FormData();
|
|
37
|
+
formData.append("file", blob, basename(abs));
|
|
38
|
+
const result = await client.upload("/api/v1/uploads", formData);
|
|
39
|
+
return result.url;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve an array of image arguments (local files or URLs) to remote URLs.
|
|
43
|
+
*/
|
|
44
|
+
export async function resolveImageArgs(client, values, onUploadStart) {
|
|
45
|
+
const results = [];
|
|
46
|
+
for (let i = 0; i < values.length; i++) {
|
|
47
|
+
const url = await resolveImageArg(client, values[i], () => onUploadStart?.(i + 1, values.length));
|
|
48
|
+
results.push(url);
|
|
49
|
+
}
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/lib/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,MAAM,WAAW,GAA2B;IAC3C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;CACrB,CAAC;AAEF,SAAS,WAAW,CAAC,KAAa;IACjC,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB;IACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,MAAiB,EACjB,KAAa,EACb,aAA0B;IAE1B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,aAAa,EAAE,EAAE,CAAC;IAElB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAChE,OAAO,MAAM,CAAC,GAAG,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,MAAiB,EACjB,MAAgB,EAChB,aAAsD;IAEtD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,eAAe,CAChC,MAAM,EACN,MAAM,CAAC,CAAC,CAAC,EACT,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAC3C,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pixcli",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "The creative toolkit for AI agents — generate images, edit visuals, and more from the command line.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pixcli": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
16
|
+
"release": "npm version patch && npm publish",
|
|
17
|
+
"release:minor": "npm version minor && npm publish",
|
|
18
|
+
"release:major": "npm version major && npm publish"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ai",
|
|
22
|
+
"image-generation",
|
|
23
|
+
"cli",
|
|
24
|
+
"creative",
|
|
25
|
+
"agents",
|
|
26
|
+
"image-editing",
|
|
27
|
+
"nano-banana",
|
|
28
|
+
"flux",
|
|
29
|
+
"seedream",
|
|
30
|
+
"openrouter"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/shellbot-ai/pixcli"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://pixcli.shellbot.sh",
|
|
37
|
+
"author": "ShellBot",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"chalk": "^5.4.1",
|
|
40
|
+
"commander": "^13.1.0",
|
|
41
|
+
"ora": "^8.2.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.15.0",
|
|
45
|
+
"typescript": "^5.9.3"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"license": "MIT"
|
|
51
|
+
}
|