@postplus/cli 0.1.45 → 0.1.47

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.
@@ -0,0 +1,39 @@
1
+ export type AuthedCloudRequestAuth = {
2
+ apiBaseUrl: string;
3
+ cliSessionToken: string;
4
+ };
5
+ export type AuthedCloudRequestInput = {
6
+ auth: AuthedCloudRequestAuth;
7
+ pathName: string;
8
+ method?: 'GET' | 'POST';
9
+ /**
10
+ * Parsed JSON body. When provided the request sends `content-type:
11
+ * application/json` and the serialized body; when omitted neither is sent.
12
+ */
13
+ body?: unknown;
14
+ skillName?: string | null;
15
+ /**
16
+ * In-process override for the skills release id header. When provided (the
17
+ * hosted-lib path) it is stamped verbatim and the disk config is NOT read for
18
+ * the release id; when omitted (the bin path) the release id comes from
19
+ * `readLocalConfig()` as before.
20
+ */
21
+ skillsReleaseId?: string | null;
22
+ timeoutMs?: number;
23
+ /**
24
+ * Optional once-only 401 refresh. When provided, a `401` response triggers a
25
+ * single retry: `refreshAuth()` returns fresh credentials and the request is
26
+ * re-issued once with them. When omitted, the first response is returned
27
+ * verbatim (the caller keeps its own `!ok` interpretation either way).
28
+ */
29
+ retryOn401?: () => Promise<AuthedCloudRequestAuth>;
30
+ };
31
+ /**
32
+ * Single transport envelope for every authenticated PostPlus Cloud request:
33
+ * canonical header set (`accept` + compatibility headers + `Bearer` token +
34
+ * optional `content-type`), `AbortSignal.timeout`, and an optional once-only
35
+ * 401-refresh-retry. It returns the raw `Response` so each caller keeps its own
36
+ * `!ok` interpretation — this is a narrow transport primitive, not a request
37
+ * framework.
38
+ */
39
+ export declare function sendAuthedCloudRequest(input: AuthedCloudRequestInput): Promise<Response>;
@@ -19,6 +19,9 @@ export async function sendAuthedCloudRequest(input) {
19
19
  async function issueAuthedCloudRequest(auth, input) {
20
20
  const compatibilityHeaders = await buildPostPlusClientCompatibilityHeaders({
21
21
  skillName: input.skillName ?? null,
22
+ ...(input.skillsReleaseId !== undefined
23
+ ? { skillsReleaseId: input.skillsReleaseId }
24
+ : {}),
22
25
  });
23
26
  const hasBody = input.body !== undefined;
24
27
  const headers = {
@@ -2,6 +2,10 @@ import { readFile } from 'node:fs/promises';
2
2
  import { readLocalConfig, updateLocalConfig } from './local-state.js';
3
3
  export const POSTPLUS_CLIENT_CONTRACT_VERSION = 2;
4
4
  export const POSTPLUS_CLIENT_RUNTIME = 'postplus-cli';
5
+ // Single source for the CLI self-update command. Lives here (the upgrade-error
6
+ // formatter's home) so update-check.ts can import it without a cycle —
7
+ // update-check already depends on this module for readCurrentCliVersion.
8
+ export const POSTPLUS_CLI_UPDATE_COMMAND = 'npm install -g @postplus/cli@latest';
5
9
  export const POSTPLUS_CLIENT_COMPATIBILITY_HEADERS = {
6
10
  cliVersion: 'x-postplus-cli-version',
7
11
  contractVersion: 'x-postplus-client-contract-version',
@@ -10,16 +14,19 @@ export const POSTPLUS_CLIENT_COMPATIBILITY_HEADERS = {
10
14
  skillName: 'x-postplus-skill-name',
11
15
  };
12
16
  export async function buildPostPlusClientCompatibilityHeaders(input = {}) {
17
+ const hasReleaseIdOverride = input.skillsReleaseId !== undefined;
13
18
  const [cliVersion, config] = await Promise.all([
14
19
  readCurrentCliVersion(),
15
- readLocalConfig(),
20
+ hasReleaseIdOverride ? Promise.resolve(null) : readLocalConfig(),
16
21
  ]);
17
22
  const headers = {
18
23
  [POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.cliVersion]: cliVersion,
19
24
  [POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.contractVersion]: String(POSTPLUS_CLIENT_CONTRACT_VERSION),
20
25
  [POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.runtime]: POSTPLUS_CLIENT_RUNTIME,
21
26
  };
22
- const skillsReleaseId = config?.managedSkills?.releaseId?.trim();
27
+ const skillsReleaseId = hasReleaseIdOverride
28
+ ? input.skillsReleaseId?.trim()
29
+ : config?.managedSkills?.releaseId?.trim();
23
30
  const skillName = input.skillName?.trim();
24
31
  if (skillsReleaseId) {
25
32
  headers[POSTPLUS_CLIENT_COMPATIBILITY_HEADERS.skillsReleaseId] =
@@ -50,8 +57,7 @@ export function formatPostPlusClientUpgradeError(payload) {
50
57
  const record = payload && typeof payload === 'object' && !Array.isArray(payload)
51
58
  ? payload
52
59
  : {};
53
- const cliCommand = record.compatibility?.upgrade?.cli?.command ??
54
- 'npm install -g @postplus/cli@latest';
60
+ const cliCommand = record.compatibility?.upgrade?.cli?.command ?? POSTPLUS_CLI_UPDATE_COMMAND;
55
61
  const skillsCommand = record.compatibility?.upgrade?.skills?.command ?? 'postplus update';
56
62
  const restart = record.compatibility?.upgrade?.restartAgentSession
57
63
  ? ' Then restart your agent session.'
@@ -169,7 +169,8 @@ export const HOSTED_EXECUTION_MANIFESTS = {
169
169
  "image-seedream-v5-lite-text",
170
170
  "image-seedream-v5-lite-sequential",
171
171
  "image-seedream-v5-lite-edit",
172
- "image-seedream-v5-lite-edit-sequential"
172
+ "image-seedream-v5-lite-edit-sequential",
173
+ "image-higgsfield-soul-text"
173
174
  ],
174
175
  "endpoints": [
175
176
  {
@@ -1123,6 +1124,82 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1123
1124
  "billingDimensions": [
1124
1125
  "billableUnitCount"
1125
1126
  ]
1127
+ },
1128
+ {
1129
+ "endpointKey": "image-higgsfield-soul-text",
1130
+ "provider": "higgsfield",
1131
+ "providerModelPath": "higgsfield-ai/soul/standard",
1132
+ "fields": [
1133
+ {
1134
+ "name": "prompt",
1135
+ "class": "intent",
1136
+ "flag": "--prompt",
1137
+ "type": "string",
1138
+ "required": true
1139
+ },
1140
+ {
1141
+ "name": "aspect_ratio",
1142
+ "class": "default",
1143
+ "flag": "--aspect-ratio",
1144
+ "type": "string",
1145
+ "enumValues": [
1146
+ "9:16",
1147
+ "16:9",
1148
+ "4:3",
1149
+ "3:4",
1150
+ "1:1",
1151
+ "2:3",
1152
+ "3:2"
1153
+ ],
1154
+ "default": "1:1",
1155
+ "required": false
1156
+ },
1157
+ {
1158
+ "name": "style_id",
1159
+ "class": "intent",
1160
+ "flag": "--style-id",
1161
+ "type": "string",
1162
+ "required": false
1163
+ },
1164
+ {
1165
+ "name": "style_strength",
1166
+ "class": "intent",
1167
+ "flag": "--style-strength",
1168
+ "type": "number",
1169
+ "required": false
1170
+ },
1171
+ {
1172
+ "name": "seed",
1173
+ "class": "intent",
1174
+ "flag": "--seed",
1175
+ "type": "number",
1176
+ "required": false
1177
+ },
1178
+ {
1179
+ "name": "enhance_prompt",
1180
+ "class": "intent",
1181
+ "flag": "--enhance-prompt",
1182
+ "type": "boolean",
1183
+ "required": false
1184
+ },
1185
+ {
1186
+ "name": "operationId",
1187
+ "class": "runner-managed",
1188
+ "flag": null,
1189
+ "type": "string",
1190
+ "required": false
1191
+ },
1192
+ {
1193
+ "name": "quoteConfirmationToken",
1194
+ "class": "runner-managed",
1195
+ "flag": null,
1196
+ "type": "string",
1197
+ "required": false
1198
+ }
1199
+ ],
1200
+ "billingDimensions": [
1201
+ "billableUnitCount"
1202
+ ]
1126
1203
  }
1127
1204
  ]
1128
1205
  }
@@ -1181,6 +1258,8 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1181
1258
  "capability": "media-generation",
1182
1259
  "endpointKeys": [
1183
1260
  "video-seedance-2-image",
1261
+ "video-seedance-2-mini-image",
1262
+ "video-seedance-2-mini-text",
1184
1263
  "video-seedance-2-text"
1185
1264
  ],
1186
1265
  "endpoints": [
@@ -1256,6 +1335,200 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1256
1335
  "referenceVideoMode"
1257
1336
  ]
1258
1337
  },
1338
+ {
1339
+ "endpointKey": "video-seedance-2-mini-image",
1340
+ "provider": "wavespeed",
1341
+ "providerModelPath": "bytedance/seedance-2.0-mini/image-to-video",
1342
+ "fields": [
1343
+ {
1344
+ "name": "prompt",
1345
+ "class": "intent",
1346
+ "flag": null,
1347
+ "type": "string",
1348
+ "required": true
1349
+ },
1350
+ {
1351
+ "name": "image",
1352
+ "class": "intent",
1353
+ "flag": null,
1354
+ "type": "media-url",
1355
+ "required": true
1356
+ },
1357
+ {
1358
+ "name": "resolution",
1359
+ "class": "default",
1360
+ "flag": null,
1361
+ "type": "string",
1362
+ "enumValues": [
1363
+ "480p",
1364
+ "720p",
1365
+ "1080p",
1366
+ "4k"
1367
+ ],
1368
+ "canonicalize": "lowercase",
1369
+ "default": "720p",
1370
+ "required": false
1371
+ },
1372
+ {
1373
+ "name": "duration",
1374
+ "class": "default",
1375
+ "flag": null,
1376
+ "type": "number",
1377
+ "default": 5,
1378
+ "required": false,
1379
+ "min": 4,
1380
+ "max": 15
1381
+ },
1382
+ {
1383
+ "name": "operationId",
1384
+ "class": "runner-managed",
1385
+ "flag": null,
1386
+ "type": "string",
1387
+ "required": false
1388
+ },
1389
+ {
1390
+ "name": "quoteConfirmationToken",
1391
+ "class": "runner-managed",
1392
+ "flag": null,
1393
+ "type": "string",
1394
+ "required": false
1395
+ },
1396
+ {
1397
+ "name": "requestDimensions",
1398
+ "class": "runner-managed",
1399
+ "flag": null,
1400
+ "type": "string",
1401
+ "required": false
1402
+ }
1403
+ ],
1404
+ "billingDimensions": [
1405
+ "duration",
1406
+ "resolution",
1407
+ "referenceVideoCount",
1408
+ "referenceVideoMode"
1409
+ ]
1410
+ },
1411
+ {
1412
+ "endpointKey": "video-seedance-2-mini-text",
1413
+ "provider": "wavespeed",
1414
+ "providerModelPath": "bytedance/seedance-2.0-mini/text-to-video",
1415
+ "fields": [
1416
+ {
1417
+ "name": "prompt",
1418
+ "class": "intent",
1419
+ "flag": null,
1420
+ "type": "string",
1421
+ "required": true
1422
+ },
1423
+ {
1424
+ "name": "resolution",
1425
+ "class": "default",
1426
+ "flag": null,
1427
+ "type": "string",
1428
+ "enumValues": [
1429
+ "480p",
1430
+ "720p",
1431
+ "1080p",
1432
+ "4k"
1433
+ ],
1434
+ "canonicalize": "lowercase",
1435
+ "default": "720p",
1436
+ "required": false
1437
+ },
1438
+ {
1439
+ "name": "aspect_ratio",
1440
+ "class": "intent",
1441
+ "flag": null,
1442
+ "type": "string",
1443
+ "enumValues": [
1444
+ "21:9",
1445
+ "16:9",
1446
+ "4:3",
1447
+ "1:1",
1448
+ "3:4",
1449
+ "9:16"
1450
+ ],
1451
+ "required": false
1452
+ },
1453
+ {
1454
+ "name": "duration",
1455
+ "class": "default",
1456
+ "flag": null,
1457
+ "type": "number",
1458
+ "default": 5,
1459
+ "required": false,
1460
+ "min": 4,
1461
+ "max": 15
1462
+ },
1463
+ {
1464
+ "name": "reference_images",
1465
+ "class": "intent",
1466
+ "flag": null,
1467
+ "type": "media-url",
1468
+ "repeatable": true,
1469
+ "required": false
1470
+ },
1471
+ {
1472
+ "name": "reference_videos",
1473
+ "class": "intent",
1474
+ "flag": null,
1475
+ "type": "media-url",
1476
+ "repeatable": true,
1477
+ "required": false
1478
+ },
1479
+ {
1480
+ "name": "reference_audios",
1481
+ "class": "intent",
1482
+ "flag": null,
1483
+ "type": "media-url",
1484
+ "repeatable": true,
1485
+ "required": false
1486
+ },
1487
+ {
1488
+ "name": "enable_web_search",
1489
+ "class": "default",
1490
+ "flag": null,
1491
+ "type": "boolean",
1492
+ "default": false,
1493
+ "required": false
1494
+ },
1495
+ {
1496
+ "name": "generate_audio",
1497
+ "class": "default",
1498
+ "flag": null,
1499
+ "type": "boolean",
1500
+ "default": true,
1501
+ "required": false
1502
+ },
1503
+ {
1504
+ "name": "operationId",
1505
+ "class": "runner-managed",
1506
+ "flag": null,
1507
+ "type": "string",
1508
+ "required": false
1509
+ },
1510
+ {
1511
+ "name": "quoteConfirmationToken",
1512
+ "class": "runner-managed",
1513
+ "flag": null,
1514
+ "type": "string",
1515
+ "required": false
1516
+ },
1517
+ {
1518
+ "name": "requestDimensions",
1519
+ "class": "runner-managed",
1520
+ "flag": null,
1521
+ "type": "string",
1522
+ "required": false
1523
+ }
1524
+ ],
1525
+ "billingDimensions": [
1526
+ "duration",
1527
+ "resolution",
1528
+ "referenceVideoCount",
1529
+ "referenceVideoMode"
1530
+ ]
1531
+ },
1259
1532
  {
1260
1533
  "endpointKey": "video-seedance-2-text",
1261
1534
  "provider": "wavespeed",
@@ -1323,6 +1596,30 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1323
1596
  "repeatable": true,
1324
1597
  "required": false
1325
1598
  },
1599
+ {
1600
+ "name": "reference_audios",
1601
+ "class": "intent",
1602
+ "flag": null,
1603
+ "type": "media-url",
1604
+ "repeatable": true,
1605
+ "required": false
1606
+ },
1607
+ {
1608
+ "name": "enable_web_search",
1609
+ "class": "default",
1610
+ "flag": null,
1611
+ "type": "boolean",
1612
+ "default": false,
1613
+ "required": false
1614
+ },
1615
+ {
1616
+ "name": "generate_audio",
1617
+ "class": "default",
1618
+ "flag": null,
1619
+ "type": "boolean",
1620
+ "default": true,
1621
+ "required": false
1622
+ },
1326
1623
  {
1327
1624
  "name": "operationId",
1328
1625
  "class": "runner-managed",
@@ -0,0 +1,84 @@
1
+ // GENERATED from apps/web/lib/server/postplus-cli/hosted-field-validation-core.ts.
2
+ // Do not edit by hand. Run `pnpm hosted-execution-manifest:sync` to regenerate.
3
+ // Verbatim projection so the canonicalize + enum/range field-validation algorithm stays
4
+ // byte-identical to the Web boundary (the CLI submodule cannot import apps/web TS).
5
+ // k-tier normalization for image resolution ("4K" -> "4k").
6
+ export function canonicalizeImageResolution(value) {
7
+ const trimmed = value.trim();
8
+ const tier = trimmed.match(/^(\d+(?:\.\d+)?)\s*k$/iu);
9
+ return tier ? `${tier[1]}k` : trimmed;
10
+ }
11
+ export function canonicalizeLowercaseToken(value) {
12
+ return value.trim().toLowerCase();
13
+ }
14
+ // Which canonicalization a field uses is decided by the schema `canonicalize` hint —
15
+ // the single source both surfaces read — never re-guessed from the field name.
16
+ export function canonicalizeModelledFieldValue(field, value) {
17
+ switch (field.canonicalize) {
18
+ case 'image-resolution-tier':
19
+ return canonicalizeImageResolution(value);
20
+ case 'lowercase':
21
+ return canonicalizeLowercaseToken(value);
22
+ default:
23
+ return value;
24
+ }
25
+ }
26
+ function formatReceivedValue(raw) {
27
+ return typeof raw === 'string' ? `"${raw}"` : String(raw);
28
+ }
29
+ function assertModelledNumberFieldValue(endpointKey, field, raw, createError) {
30
+ const enumValues = field.enumValues && field.enumValues.length > 0 ? field.enumValues : null;
31
+ const constraint = enumValues
32
+ ? `must be one of ${enumValues.join(', ')}`
33
+ : `must be an integer from ${field.min} to ${field.max}`;
34
+ if (typeof raw !== 'number' || !Number.isFinite(raw)) {
35
+ throw createError(`${endpointKey} ${field.name} ${constraint}; received ${formatReceivedValue(raw)}.`);
36
+ }
37
+ if (enumValues) {
38
+ if (!enumValues.includes(String(raw))) {
39
+ throw createError(`${endpointKey} ${field.name} ${constraint}; received ${raw}.`);
40
+ }
41
+ return;
42
+ }
43
+ if (field.min === undefined || field.max === undefined) {
44
+ return;
45
+ }
46
+ if (!(Number.isInteger(raw) && raw >= field.min && raw <= field.max)) {
47
+ throw createError(`${endpointKey} ${field.name} ${constraint}; received ${raw}.`);
48
+ }
49
+ }
50
+ // Validates every advertised enum / numeric-range field present in the input against
51
+ // the field contract. Skips runner-managed fields (no caller input), fields with
52
+ // neither an enum nor a range, and fields the input omits. The string value is
53
+ // canonicalized with the schema hint before the enum membership check, so a mixed-case
54
+ // "720P"/"4K" still matches the lowercase registry enum while "english" still fails the
55
+ // Title-cased language enum. The error factory is injected: the Web boundary passes its
56
+ // typed invalid_request error, the CLI early validator passes a plain Error.
57
+ export function assertModelledFieldValuesInRange(endpointKey, fields, input, createError) {
58
+ for (const field of fields) {
59
+ if (field.class === 'runner-managed') {
60
+ continue;
61
+ }
62
+ const enumValues = field.enumValues && field.enumValues.length > 0 ? field.enumValues : null;
63
+ const hasRange = field.min !== undefined && field.max !== undefined;
64
+ if (!enumValues && !hasRange) {
65
+ continue;
66
+ }
67
+ if (!Object.hasOwn(input, field.name)) {
68
+ continue;
69
+ }
70
+ if (field.type === 'number') {
71
+ assertModelledNumberFieldValue(endpointKey, field, input[field.name], createError);
72
+ continue;
73
+ }
74
+ const raw = input[field.name];
75
+ if (typeof raw !== 'string' || !raw.trim()) {
76
+ continue;
77
+ }
78
+ const value = raw.trim();
79
+ if (enumValues &&
80
+ !enumValues.includes(canonicalizeModelledFieldValue(field, value))) {
81
+ throw createError(`${endpointKey} ${field.name} must be one of ${enumValues.join(', ')}; received "${value}".`);
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,14 @@
1
+ import { type AuthedCloudRequestAuth } from './authed-cloud-request.js';
2
+ import { type HostedDomain } from './hosted-manifest-index.js';
3
+ export type HostedRequestContext = {
4
+ auth: AuthedCloudRequestAuth;
5
+ skillsReleaseId?: string;
6
+ /**
7
+ * The request-json envelope injected in place of a `--request <file>` read.
8
+ * Surfaces that need a body assert it is present and the right shape (object vs
9
+ * array) exactly as the file-read path validated the parsed file contents.
10
+ */
11
+ requestJson?: Record<string, unknown> | unknown[];
12
+ };
13
+ export declare function runHostedDomainCommand(domain: HostedDomain, args: string[], context?: HostedRequestContext): Promise<number | unknown>;
14
+ export declare function runMediaFileCommand(args: string[], context?: HostedRequestContext): Promise<number | unknown>;