@ai-agent-tools/picgen 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +6 -2
- package/dist/cli.js +111 -12
- package/docs/release-alpha.md +3 -1
- package/package.json +1 -1
- package/skills/picgen/SKILL.md +48 -7
package/README.md
CHANGED
|
@@ -54,14 +54,16 @@ npx -y skills add ai-agent-tools/picgen --skill picgen -g -y --copy
|
|
|
54
54
|
picgen skill install codex
|
|
55
55
|
picgen update check
|
|
56
56
|
picgen doctor --json
|
|
57
|
-
picgen create --dry-run "
|
|
58
|
-
picgen create --yes "
|
|
57
|
+
picgen create --dry-run --preset fast-draft "一张简洁的 PicGen 测试图"
|
|
58
|
+
picgen create --yes --preset fast-draft "一张简洁的 PicGen 测试图"
|
|
59
59
|
picgen create --dry-run --provider gemini_official --reference ./reference.png "基于参考图生成一张品牌海报"
|
|
60
60
|
picgen create --yes --provider gemini_official --reference ./reference.png "基于参考图生成一张品牌海报"
|
|
61
61
|
picgen provider list
|
|
62
62
|
picgen provider add
|
|
63
63
|
picgen provider quick-add gemini-proxy --host https://www.pandai.vip --prefer
|
|
64
|
+
picgen key set PICGEN_GEMINI_PROXY_KEY --clipboard
|
|
64
65
|
picgen key set PICGEN_GEMINI_PROXY_KEY --stdin
|
|
66
|
+
picgen key list --json
|
|
65
67
|
picgen provider test openai_official --json
|
|
66
68
|
picgen provider prefer gemini_official
|
|
67
69
|
picgen provider disable gemini_proxy
|
|
@@ -109,6 +111,8 @@ For non-technical users, `picgen setup` can save API keys for you in:
|
|
|
109
111
|
|
|
110
112
|
PicGen loads this managed env file automatically. Shell environment variables take priority, and a project `.env` can override the managed file for local testing.
|
|
111
113
|
|
|
114
|
+
When agents inspect key configuration, they should use `picgen key list/show` so chat output only contains masked key status. To inspect or edit the full saved key directly, open `~/.picgen/.env`; a project `.env` in the current directory may override it, and shell environment variables take highest priority.
|
|
115
|
+
|
|
112
116
|
You can start from the included example:
|
|
113
117
|
|
|
114
118
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -217,12 +217,12 @@ function padMilliseconds(value) {
|
|
|
217
217
|
function slug(value) {
|
|
218
218
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
219
219
|
}
|
|
220
|
-
function redactProviderImageData(value,
|
|
220
|
+
function redactProviderImageData(value, key2) {
|
|
221
221
|
if (Array.isArray(value)) {
|
|
222
222
|
return value.map((item) => redactProviderImageData(item));
|
|
223
223
|
}
|
|
224
224
|
if (!value || typeof value !== "object") {
|
|
225
|
-
return shouldRedactImageDataKey(
|
|
225
|
+
return shouldRedactImageDataKey(key2) && typeof value === "string" ? redactedProviderDataPlaceholder(value) : value;
|
|
226
226
|
}
|
|
227
227
|
return Object.fromEntries(
|
|
228
228
|
Object.entries(value).map(([entryKey, entryValue]) => [
|
|
@@ -231,8 +231,8 @@ function redactProviderImageData(value, key) {
|
|
|
231
231
|
])
|
|
232
232
|
);
|
|
233
233
|
}
|
|
234
|
-
function shouldRedactImageDataKey(
|
|
235
|
-
return
|
|
234
|
+
function shouldRedactImageDataKey(key2) {
|
|
235
|
+
return key2 === "b64_json" || key2 === "data" || key2 === "thoughtSignature" || key2 === "thought_signature";
|
|
236
236
|
}
|
|
237
237
|
function redactedProviderDataPlaceholder(value) {
|
|
238
238
|
return `[redacted provider data: ${value.length} chars]`;
|
|
@@ -1054,7 +1054,7 @@ import { homedir as homedir2 } from "os";
|
|
|
1054
1054
|
|
|
1055
1055
|
// src/version.ts
|
|
1056
1056
|
var PACKAGE_NAME = "@ai-agent-tools/picgen";
|
|
1057
|
-
var VERSION = "0.1.0-alpha.
|
|
1057
|
+
var VERSION = "0.1.0-alpha.9";
|
|
1058
1058
|
|
|
1059
1059
|
// src/commands/update.ts
|
|
1060
1060
|
var UPDATE_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -1226,21 +1226,25 @@ async function runDoctor(options) {
|
|
|
1226
1226
|
}
|
|
1227
1227
|
|
|
1228
1228
|
// src/commands/key.ts
|
|
1229
|
+
import { execFile } from "child_process";
|
|
1230
|
+
import { promisify } from "util";
|
|
1229
1231
|
import { password } from "@inquirer/prompts";
|
|
1230
1232
|
|
|
1231
1233
|
// src/config/env.ts
|
|
1232
1234
|
import { chmod, mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
1233
1235
|
import { existsSync } from "fs";
|
|
1236
|
+
import { createHash } from "crypto";
|
|
1234
1237
|
import { dirname as dirname3, join as join5, resolve as resolve2 } from "path";
|
|
1235
1238
|
import { homedir as homedir3 } from "os";
|
|
1236
1239
|
import { parse } from "dotenv";
|
|
1240
|
+
var loadedEnvSources = /* @__PURE__ */ new Map();
|
|
1237
1241
|
function getManagedEnvPath() {
|
|
1238
1242
|
return process.env.PICGEN_ENV_PATH ?? join5(homedir3(), ".picgen", ".env");
|
|
1239
1243
|
}
|
|
1240
1244
|
async function loadPicgenEnv() {
|
|
1241
1245
|
const shellEnv = new Set(Object.keys(process.env));
|
|
1242
|
-
await loadEnvFile(getManagedEnvPath(), shellEnv, false);
|
|
1243
|
-
await loadEnvFile(resolve2(process.cwd(), ".env"), shellEnv, true);
|
|
1246
|
+
await loadEnvFile(getManagedEnvPath(), shellEnv, false, "managed");
|
|
1247
|
+
await loadEnvFile(resolve2(process.cwd(), ".env"), shellEnv, true, "project");
|
|
1244
1248
|
}
|
|
1245
1249
|
async function saveManagedEnvVar(name, value) {
|
|
1246
1250
|
const path = getManagedEnvPath();
|
|
@@ -1253,18 +1257,53 @@ async function saveManagedEnvVar(name, value) {
|
|
|
1253
1257
|
await writeFile4(path, stringifyEnv(next), "utf8");
|
|
1254
1258
|
await chmod(path, 384);
|
|
1255
1259
|
process.env[name] = value;
|
|
1260
|
+
loadedEnvSources.set(name, { source: "managed", path });
|
|
1256
1261
|
return path;
|
|
1257
1262
|
}
|
|
1258
|
-
async function
|
|
1263
|
+
async function inspectEnvVar(name) {
|
|
1264
|
+
const shellValue = process.env[name];
|
|
1265
|
+
if (shellValue !== void 0) {
|
|
1266
|
+
const loadedSource = loadedEnvSources.get(name);
|
|
1267
|
+
return describeEnvValue(
|
|
1268
|
+
name,
|
|
1269
|
+
shellValue,
|
|
1270
|
+
loadedSource?.source ?? "shell",
|
|
1271
|
+
loadedSource?.path
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
const projectPath = resolve2(process.cwd(), ".env");
|
|
1275
|
+
const project = await readEnvFile(projectPath);
|
|
1276
|
+
if (project[name] !== void 0) {
|
|
1277
|
+
return describeEnvValue(name, project[name], "project", projectPath);
|
|
1278
|
+
}
|
|
1279
|
+
const managedPath = getManagedEnvPath();
|
|
1280
|
+
const managed = await readEnvFile(managedPath);
|
|
1281
|
+
if (managed[name] !== void 0) {
|
|
1282
|
+
return describeEnvValue(name, managed[name], "managed", managedPath);
|
|
1283
|
+
}
|
|
1284
|
+
return {
|
|
1285
|
+
name,
|
|
1286
|
+
set: false
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
async function inspectEnvVars(names) {
|
|
1290
|
+
const uniqueNames = [...new Set(names)];
|
|
1291
|
+
return Promise.all(uniqueNames.map((name) => inspectEnvVar(name)));
|
|
1292
|
+
}
|
|
1293
|
+
async function loadEnvFile(path, shellEnv, overrideManagedValues, source) {
|
|
1259
1294
|
if (!existsSync(path)) return;
|
|
1260
1295
|
const parsed = parse(await readFile4(path, "utf8"));
|
|
1261
1296
|
for (const [name, value] of Object.entries(parsed)) {
|
|
1262
1297
|
if (shellEnv.has(name)) continue;
|
|
1263
1298
|
if (!overrideManagedValues && process.env[name] !== void 0) continue;
|
|
1264
1299
|
process.env[name] = value;
|
|
1300
|
+
loadedEnvSources.set(name, { source, path });
|
|
1265
1301
|
}
|
|
1266
1302
|
}
|
|
1267
1303
|
async function readManagedEnvFile(path) {
|
|
1304
|
+
return readEnvFile(path);
|
|
1305
|
+
}
|
|
1306
|
+
async function readEnvFile(path) {
|
|
1268
1307
|
try {
|
|
1269
1308
|
return parse(await readFile4(path, "utf8"));
|
|
1270
1309
|
} catch (error) {
|
|
@@ -1280,11 +1319,27 @@ function quoteEnvValue(value) {
|
|
|
1280
1319
|
if (/^[A-Za-z0-9_./:@+-]+$/.test(value)) return value;
|
|
1281
1320
|
return JSON.stringify(value);
|
|
1282
1321
|
}
|
|
1322
|
+
function describeEnvValue(name, value, source, path) {
|
|
1323
|
+
return {
|
|
1324
|
+
name,
|
|
1325
|
+
set: true,
|
|
1326
|
+
source,
|
|
1327
|
+
path,
|
|
1328
|
+
length: value.length,
|
|
1329
|
+
preview: maskSecret(value),
|
|
1330
|
+
fingerprint: createHash("sha256").update(value).digest("hex").slice(0, 12)
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
function maskSecret(value) {
|
|
1334
|
+
if (value.length <= 11) return "*".repeat(value.length);
|
|
1335
|
+
return `${value.slice(0, 7)}...${value.slice(-4)}`;
|
|
1336
|
+
}
|
|
1283
1337
|
|
|
1284
1338
|
// src/commands/key.ts
|
|
1339
|
+
var execFileAsync = promisify(execFile);
|
|
1285
1340
|
async function setApiKey(name, options) {
|
|
1286
1341
|
validateEnvName(name);
|
|
1287
|
-
const value = options.stdin ? await readStdin() : options.value ? options.value : await password({
|
|
1342
|
+
const value = options.clipboard ? await readClipboard() : options.stdin ? await readStdin() : options.value ? options.value : await password({
|
|
1288
1343
|
message: `Paste API key for ${name}`,
|
|
1289
1344
|
mask: "*"
|
|
1290
1345
|
});
|
|
@@ -1294,6 +1349,27 @@ async function setApiKey(name, options) {
|
|
|
1294
1349
|
const path = await saveManagedEnvVar(name, value.trim());
|
|
1295
1350
|
console.log(`Saved ${name} to ${path}`);
|
|
1296
1351
|
}
|
|
1352
|
+
async function listApiKeys(options) {
|
|
1353
|
+
const config = await loadConfig();
|
|
1354
|
+
const names = Object.values(config.providers).map((provider2) => provider2.api_key_env);
|
|
1355
|
+
const inspections = await inspectEnvVars(names);
|
|
1356
|
+
if (options.json) {
|
|
1357
|
+
console.log(JSON.stringify(inspections, null, 2));
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
for (const inspection of inspections) {
|
|
1361
|
+
printInspection(inspection);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
async function showApiKey(name, options) {
|
|
1365
|
+
validateEnvName(name);
|
|
1366
|
+
const inspection = await inspectEnvVar(name);
|
|
1367
|
+
if (options.json) {
|
|
1368
|
+
console.log(JSON.stringify(inspection, null, 2));
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
printInspection(inspection);
|
|
1372
|
+
}
|
|
1297
1373
|
function validateEnvName(name) {
|
|
1298
1374
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
1299
1375
|
throw new Error(`Invalid environment variable name: ${name}`);
|
|
@@ -1306,6 +1382,24 @@ async function readStdin() {
|
|
|
1306
1382
|
}
|
|
1307
1383
|
return Buffer.concat(chunks).toString("utf8");
|
|
1308
1384
|
}
|
|
1385
|
+
async function readClipboard() {
|
|
1386
|
+
try {
|
|
1387
|
+
const { stdout } = await execFileAsync("pbpaste");
|
|
1388
|
+
return stdout;
|
|
1389
|
+
} catch {
|
|
1390
|
+
throw new Error("Could not read clipboard. Use --stdin or run picgen key set without flags.");
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
function printInspection(inspection) {
|
|
1394
|
+
if (!inspection.set) {
|
|
1395
|
+
console.log(`${inspection.name}: missing`);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
const location = inspection.path ? ` ${inspection.path}` : "";
|
|
1399
|
+
console.log(
|
|
1400
|
+
`${inspection.name}: set source=${inspection.source}${location} length=${inspection.length} preview=${inspection.preview} fingerprint=${inspection.fingerprint}`
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1309
1403
|
|
|
1310
1404
|
// src/commands/provider.ts
|
|
1311
1405
|
import { input, select } from "@inquirer/prompts";
|
|
@@ -1684,14 +1778,16 @@ function formatQuickstart() {
|
|
|
1684
1778
|
"Configure:",
|
|
1685
1779
|
" picgen setup # can save provider API keys for you",
|
|
1686
1780
|
" picgen provider quick-add gemini-proxy --host https://www.pandai.vip --prefer",
|
|
1781
|
+
" picgen key set PICGEN_GEMINI_PROXY_KEY --clipboard",
|
|
1687
1782
|
" picgen key set PICGEN_GEMINI_PROXY_KEY --stdin",
|
|
1783
|
+
" picgen key list --json",
|
|
1688
1784
|
" picgen doctor --json",
|
|
1689
1785
|
"",
|
|
1690
1786
|
"Preview before spending quota:",
|
|
1691
|
-
' picgen create --dry-run "\u4E00\u5F20\
|
|
1787
|
+
' picgen create --dry-run --preset fast-draft "\u4E00\u5F20\u7B80\u6D01\u7684 PicGen \u6D4B\u8BD5\u56FE"',
|
|
1692
1788
|
"",
|
|
1693
1789
|
"Generate after confirmation:",
|
|
1694
|
-
' picgen create --yes "\u4E00\u5F20\
|
|
1790
|
+
' picgen create --yes --preset fast-draft "\u4E00\u5F20\u7B80\u6D01\u7684 PicGen \u6D4B\u8BD5\u56FE"',
|
|
1695
1791
|
"",
|
|
1696
1792
|
"Use a reference image:",
|
|
1697
1793
|
' picgen create --dry-run --reference ./reference.png "\u57FA\u4E8E\u53C2\u8003\u56FE\u751F\u6210\u4E00\u5F20\u54C1\u724C\u6D77\u62A5"',
|
|
@@ -2023,7 +2119,10 @@ provider.command("prefer").argument("<name>").description("Set the default provi
|
|
|
2023
2119
|
provider.command("enable").argument("<name>").description("Enable a provider.").action((name) => setProviderEnabled(name, true));
|
|
2024
2120
|
provider.command("disable").argument("<name>").description("Disable a provider.").action((name) => setProviderEnabled(name, false));
|
|
2025
2121
|
provider.command("remove").argument("<name>").description("Remove a provider.").action(removeProvider);
|
|
2026
|
-
program.command("key").description("Manage PicGen API keys.")
|
|
2122
|
+
var key = program.command("key").description("Manage PicGen API keys.");
|
|
2123
|
+
key.command("set").argument("<env-name>", "Environment variable name, such as PICGEN_GEMINI_PROXY_KEY.").description("Save an API key to PicGen's managed env file.").option("--stdin", "Read the key value from stdin.").option("--clipboard", "Read the key value from the macOS clipboard.").option("--value <value>", "Set the key value directly. Prefer --stdin for agent workflows.").action(setApiKey);
|
|
2124
|
+
key.command("list").description("List configured provider keys without revealing secret values.").option("--json", "Print machine-readable JSON.").action(listApiKeys);
|
|
2125
|
+
key.command("show").argument("<env-name>", "Environment variable name.").description("Show one configured key without revealing the secret value.").option("--json", "Print machine-readable JSON.").action(showApiKey);
|
|
2027
2126
|
program.command("skill").description("Install PicGen agent skills.").command("install").argument("<target>", "Skill target. Currently supported: codex.").description("Install the bundled PicGen skill into an agent skill directory.").option("--force", "Overwrite an existing installed skill.").action(installSkill);
|
|
2028
2127
|
program.command("mode").description("Manage generation mode preferences.").command("prefer").argument("<name>").description("Set the default mode preference.").action(preferMode);
|
|
2029
2128
|
program.command("preset").description("Manage generation preset preferences.").command("prefer").argument("<name>").description("Set the default preset preference.").action(preferPreset);
|
package/docs/release-alpha.md
CHANGED
|
@@ -56,6 +56,8 @@ For non-technical users, prefer `picgen setup`. It can save provider API keys in
|
|
|
56
56
|
|
|
57
57
|
PicGen loads this file automatically.
|
|
58
58
|
|
|
59
|
+
Agents should inspect keys with `picgen key list/show`, which only prints masked status. If a technical user needs the complete saved value, point them to `~/.picgen/.env`; a project `.env` may override it, and shell environment variables have highest priority.
|
|
60
|
+
|
|
59
61
|
In agent environments where interactive terminal prompts are not visible, ask the user for provider type, host, and API key in chat, then use non-interactive commands. Example for a Gemini-compatible third-party channel:
|
|
60
62
|
|
|
61
63
|
```bash
|
|
@@ -92,7 +94,7 @@ picgen update check
|
|
|
92
94
|
Always start with dry-run:
|
|
93
95
|
|
|
94
96
|
```bash
|
|
95
|
-
picgen create --dry-run "
|
|
97
|
+
picgen create --dry-run --preset fast-draft "一张简洁的 PicGen 测试图"
|
|
96
98
|
```
|
|
97
99
|
|
|
98
100
|
Dry-run does not call providers and does not spend quota.
|
package/package.json
CHANGED
package/skills/picgen/SKILL.md
CHANGED
|
@@ -59,7 +59,7 @@ When running inside an agent environment where interactive terminal prompts are
|
|
|
59
59
|
|
|
60
60
|
- Provider type: Gemini or OpenAI-compatible.
|
|
61
61
|
- Provider host: host only, such as `https://www.pandai.vip`; do not include `/v1` or `/v1beta`.
|
|
62
|
-
- API key.
|
|
62
|
+
- API key. Prefer asking the user to copy the key to their clipboard and reply "copied"; avoid asking them to paste secrets into chat.
|
|
63
63
|
|
|
64
64
|
Then use non-interactive commands.
|
|
65
65
|
|
|
@@ -67,7 +67,7 @@ Gemini-compatible third-party channel:
|
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
69
|
picgen provider quick-add gemini-proxy --host https://www.pandai.vip --prefer
|
|
70
|
-
picgen key set PICGEN_GEMINI_PROXY_KEY --
|
|
70
|
+
picgen key set PICGEN_GEMINI_PROXY_KEY --clipboard
|
|
71
71
|
picgen provider test gemini_proxy --json
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -75,11 +75,22 @@ OpenAI-compatible third-party channel:
|
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
77
|
picgen provider quick-add openai-proxy --host https://www.pandai.vip --prefer
|
|
78
|
-
picgen key set PICGEN_OPENAI_PROXY_KEY --
|
|
78
|
+
picgen key set PICGEN_OPENAI_PROXY_KEY --clipboard
|
|
79
79
|
picgen provider test openai_proxy --json
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
If clipboard access is unavailable, pass the API key through stdin for `picgen key set`; do not put secrets directly in shell history unless the user explicitly accepts that tradeoff. If the agent runtime cannot pass stdin safely, ask the user to run `picgen key set <ENV_NAME>` in their terminal and paste the key into the hidden prompt.
|
|
83
|
+
|
|
84
|
+
To inspect configured keys without revealing secret values:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
picgen key list --json
|
|
88
|
+
picgen key show PICGEN_GEMINI_PROXY_KEY --json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
These commands show source, length, masked preview, and fingerprint only. Never ask the user to paste a key into chat just to verify it.
|
|
92
|
+
|
|
93
|
+
When explaining key inspection to users, say: "In this conversation I only read masked key status, not the full secret. If you need to inspect or edit the complete saved key yourself, PicGen's managed key file is `~/.picgen/.env`; a project-level `.env` in the current directory may override it; shell environment variables take highest priority."
|
|
83
94
|
|
|
84
95
|
For reference-image generation, pass local images with repeated `--reference <path>` flags:
|
|
85
96
|
|
|
@@ -92,6 +103,36 @@ Use Gemini providers for reference-image generation in Alpha. The OpenAI-compati
|
|
|
92
103
|
|
|
93
104
|
PicGen routes by provider capabilities. When reference images are provided, agents may omit `--provider` and let PicGen select a provider that supports `reference-image`, unless the user explicitly requested a provider.
|
|
94
105
|
|
|
106
|
+
## First Smoke Test
|
|
107
|
+
|
|
108
|
+
After configuring a provider, run the first test generation with a low-cost, fast, one-image plan. Do not use `poster`, `product-shot`, `social-cover`, premium modes, large sizes, or multi-image presets for initial verification.
|
|
109
|
+
|
|
110
|
+
For Gemini providers, prefer the flash image model for the first test:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
picgen create --dry-run --provider gemini_proxy --preset fast-draft --model gemini-3.1-flash-image-preview "一张简洁的 PicGen 测试图,白色背景,少量蓝绿色科技感点缀"
|
|
114
|
+
picgen create --yes --provider gemini_proxy --preset fast-draft --model gemini-3.1-flash-image-preview "一张简洁的 PicGen 测试图,白色背景,少量蓝绿色科技感点缀"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For OpenAI-compatible providers:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
picgen create --dry-run --provider openai_proxy --preset fast-draft "一张简洁的 PicGen 测试图,白色背景,少量蓝绿色科技感点缀"
|
|
121
|
+
picgen create --yes --provider openai_proxy --preset fast-draft "一张简洁的 PicGen 测试图,白色背景,少量蓝绿色科技感点缀"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Present the dry-run preview and ask for confirmation before the real generation unless the user explicitly asked to generate immediately. The first smoke test should generate one image.
|
|
125
|
+
|
|
126
|
+
## After Provider Success
|
|
127
|
+
|
|
128
|
+
After one provider is configured and the first smoke test succeeds, tell the user the provider is ready and ask whether they want to add another channel as a fallback. Example:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
Gemini 渠道已经配置并测试成功。你还可以继续添加另一个渠道作为备用,例如 OpenAI-compatible。要继续添加吗?
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
If the user says yes, repeat provider setup and smoke testing for the next channel. If the user says no, stop setup and tell them PicGen is ready to use.
|
|
135
|
+
|
|
95
136
|
## Preferences and Overrides
|
|
96
137
|
|
|
97
138
|
Treat `picgen create` flags as one-off overrides. They must not change user preferences:
|
|
@@ -127,7 +168,7 @@ PicGen redacts generated image payloads and Gemini thought signatures from metad
|
|
|
127
168
|
|
|
128
169
|
If `doctor` reports no usable provider, configure a provider. Prefer non-interactive setup in agent environments.
|
|
129
170
|
|
|
130
|
-
If an API key is missing, save it with `picgen key set <ENV_NAME> --stdin
|
|
171
|
+
If an API key is missing, save it with `picgen key set <ENV_NAME> --clipboard`, `--stdin`, or guide the user to run `picgen setup` when interactive prompts are visible. Name the required environment variable only when useful for debugging.
|
|
131
172
|
|
|
132
173
|
If a provider is disabled, suggest enabling it or using a one-off provider override.
|
|
133
174
|
|
|
@@ -146,14 +187,14 @@ Explicit:
|
|
|
146
187
|
Confirmation:
|
|
147
188
|
|
|
148
189
|
```text
|
|
149
|
-
|
|
190
|
+
我可以先用 PicGen 做一次轻量测试生成,默认只出 1 张,确认工具和渠道都可用。要我现在开始吗?
|
|
150
191
|
```
|
|
151
192
|
|
|
152
193
|
Generation preview:
|
|
153
194
|
|
|
154
195
|
```text
|
|
155
196
|
生成预览:
|
|
156
|
-
|
|
197
|
+
我将使用当前渠道生成 1 张轻量测试图,保存到本地。
|
|
157
198
|
|
|
158
199
|
确认后开始生成。
|
|
159
200
|
```
|