@postplus/cli 0.1.40 → 0.1.42

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/build/doctor.js CHANGED
@@ -389,8 +389,15 @@ function collectHostedRequirementKeys(requirements) {
389
389
  ...requirements.sourceKeys,
390
390
  ]);
391
391
  }
392
+ // Capability families whose sub-keys are intentionally NOT expressible as catalog
393
+ // requirement keys: a skill requires the bare family capability, and any released
394
+ // sub-key readiness row satisfies it. social-publishing operations and
395
+ // public-content-discovery tools (e.g. web-search) both have no requirement-key
396
+ // binding, so requiring the family must match the whole family. Without this,
397
+ // `public-content-discovery:web-search` readiness is filtered out for skills that
398
+ // require `public-content-discovery`, producing a false "readiness check missing".
392
399
  function isWholeFamilyHostedCapability(prefix) {
393
- return prefix === 'social-publishing';
400
+ return prefix === 'public-content-discovery' || prefix === 'social-publishing';
394
401
  }
395
402
  function requiresSocialPublishingPlan(requirements) {
396
403
  return requirements.hostedCapabilities.includes('social-publishing');
@@ -441,6 +441,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
441
441
  "class": "default",
442
442
  "flag": "--output-format",
443
443
  "type": "string",
444
+ "enumValues": [
445
+ "png",
446
+ "jpeg"
447
+ ],
444
448
  "default": "png",
445
449
  "required": false
446
450
  },
@@ -518,6 +522,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
518
522
  "class": "default",
519
523
  "flag": "--output-format",
520
524
  "type": "string",
525
+ "enumValues": [
526
+ "png",
527
+ "jpeg"
528
+ ],
521
529
  "default": "png",
522
530
  "required": false
523
531
  },
@@ -576,6 +584,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
576
584
  "class": "default",
577
585
  "flag": "--output-format",
578
586
  "type": "string",
587
+ "enumValues": [
588
+ "png",
589
+ "jpeg"
590
+ ],
579
591
  "default": "png",
580
592
  "required": false
581
593
  },
@@ -634,6 +646,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
634
646
  "class": "default",
635
647
  "flag": "--output-format",
636
648
  "type": "string",
649
+ "enumValues": [
650
+ "png",
651
+ "jpeg"
652
+ ],
637
653
  "default": "png",
638
654
  "required": false
639
655
  },
@@ -692,6 +708,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
692
708
  "class": "default",
693
709
  "flag": "--output-format",
694
710
  "type": "string",
711
+ "enumValues": [
712
+ "png",
713
+ "jpeg"
714
+ ],
695
715
  "default": "png",
696
716
  "required": false
697
717
  },
@@ -758,6 +778,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
758
778
  "class": "default",
759
779
  "flag": "--output-format",
760
780
  "type": "string",
781
+ "enumValues": [
782
+ "png",
783
+ "jpeg"
784
+ ],
761
785
  "default": "png",
762
786
  "required": false
763
787
  },
@@ -824,6 +848,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
824
848
  "class": "default",
825
849
  "flag": "--output-format",
826
850
  "type": "string",
851
+ "enumValues": [
852
+ "png",
853
+ "jpeg"
854
+ ],
827
855
  "default": "png",
828
856
  "required": false
829
857
  },
@@ -890,6 +918,10 @@ export const HOSTED_EXECUTION_MANIFESTS = {
890
918
  "class": "default",
891
919
  "flag": "--output-format",
892
920
  "type": "string",
921
+ "enumValues": [
922
+ "png",
923
+ "jpeg"
924
+ ],
893
925
  "default": "png",
894
926
  "required": false
895
927
  },
@@ -1308,7 +1340,6 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1308
1340
  "flag": null,
1309
1341
  "type": "string",
1310
1342
  "enumValues": [
1311
- "480p",
1312
1343
  "720p",
1313
1344
  "1080p"
1314
1345
  ],
@@ -1467,7 +1498,6 @@ export const HOSTED_EXECUTION_MANIFESTS = {
1467
1498
  "flag": null,
1468
1499
  "type": "string",
1469
1500
  "enumValues": [
1470
- "480p",
1471
1501
  "720p",
1472
1502
  "1080p"
1473
1503
  ],
@@ -2388,6 +2418,19 @@ export const HOSTED_EXECUTION_MANIFESTS = {
2388
2418
  "class": "default",
2389
2419
  "flag": null,
2390
2420
  "type": "string",
2421
+ "enumValues": [
2422
+ "auto",
2423
+ "Chinese",
2424
+ "English",
2425
+ "German",
2426
+ "Italian",
2427
+ "Portuguese",
2428
+ "Spanish",
2429
+ "Japanese",
2430
+ "Korean",
2431
+ "French",
2432
+ "Russian"
2433
+ ],
2391
2434
  "default": "auto",
2392
2435
  "required": false
2393
2436
  },
@@ -2448,6 +2491,19 @@ export const HOSTED_EXECUTION_MANIFESTS = {
2448
2491
  "class": "default",
2449
2492
  "flag": null,
2450
2493
  "type": "string",
2494
+ "enumValues": [
2495
+ "auto",
2496
+ "Chinese",
2497
+ "English",
2498
+ "German",
2499
+ "Italian",
2500
+ "Portuguese",
2501
+ "Spanish",
2502
+ "Japanese",
2503
+ "Korean",
2504
+ "French",
2505
+ "Russian"
2506
+ ],
2451
2507
  "default": "auto",
2452
2508
  "required": false
2453
2509
  },
@@ -59,6 +59,13 @@ export async function runHostedDomainCommand(domain, args) {
59
59
  if (subcommand === 'schema') {
60
60
  return runHostedSchema(domain, rest);
61
61
  }
62
+ // Poll a pending async media-generation run by handle. This is a hand-coded
63
+ // branch (not a manifest verb) because a status poll has no endpointKey/field
64
+ // contract to project — exactly like the `research collect --run-handle`
65
+ // polling branch. It must be checked before the manifest verb dispatch.
66
+ if (domain === 'media' && subcommand === 'poll') {
67
+ return runMediaPoll(rest);
68
+ }
62
69
  if (domain === 'media' && subcommand && MEDIA_VERB_ENDPOINTS.has(subcommand)) {
63
70
  return runMediaVerb(subcommand, rest);
64
71
  }
@@ -237,8 +244,11 @@ function requireResolvedEndpoint(resolved, verb, endpointKey) {
237
244
  // video-analysis verb (request-json surface). The agent authors an opaque Gemini
238
245
  // request object (contents + generationConfig) in `--request <file>`; capability,
239
246
  // operation, and modelKey come from the verb + positional, so the body posts
240
- // EXACTLY the locked Web contract. There is no field classification and no
241
- // estimatedUsage — the payload is forwarded verbatim as the Gemini request.
247
+ // EXACTLY the locked Web contract. There is no field classification; the payload
248
+ // is forwarded verbatim as the Gemini request. The optional `--video-seconds`
249
+ // flag is the one runner-supplied hint: when provided it is sent as
250
+ // `estimatedUsage.videoSeconds` so the Web boundary can route eligible short
251
+ // videos through its preflight/routing path (omit it to use the default route).
242
252
  async function runVideoAnalysisVerb(args) {
243
253
  const { modelKey, resolved, verb } = args;
244
254
  const flags = parseFlags(args.args, new Set(['json']));
@@ -249,6 +259,7 @@ async function runVideoAnalysisVerb(args) {
249
259
  'quote-confirmation-token',
250
260
  'request',
251
261
  'skill',
262
+ 'video-seconds',
252
263
  ]);
253
264
  for (const key of [...flags.values.keys(), ...flags.booleans]) {
254
265
  if (!allowedKeys.has(key)) {
@@ -262,11 +273,26 @@ async function runVideoAnalysisVerb(args) {
262
273
  throw new Error(`media ${verb} ${modelKey} --request must be a JSON object of Gemini request payload.`);
263
274
  }
264
275
  const payload = raw;
276
+ // Optional runner-supplied hint: the source video duration. When provided it is
277
+ // forwarded as estimatedUsage.videoSeconds so the Web boundary's video-analysis
278
+ // routing/preflight can consider eligible short videos; omitting it leaves the
279
+ // request on the default route. The CLI does not probe the media itself (no
280
+ // ffprobe in the open-source runner) — it only passes a value the caller knows.
281
+ const videoSecondsFlag = flags.values.get('video-seconds') ?? null;
282
+ let estimatedUsage;
283
+ if (videoSecondsFlag !== null) {
284
+ const parsed = Number(videoSecondsFlag);
285
+ if (!Number.isFinite(parsed) || parsed <= 0) {
286
+ throw new Error(`media ${verb} --video-seconds must be a positive number of seconds.`);
287
+ }
288
+ estimatedUsage = { videoSeconds: parsed };
289
+ }
265
290
  const body = {
266
291
  capability: 'video-analysis',
267
292
  operation: 'analyze',
268
293
  modelKey,
269
294
  payload,
295
+ ...(estimatedUsage ? { estimatedUsage } : {}),
270
296
  operationId: flags.values.get('hosted-operation-id') ??
271
297
  `postplus-cli:media:video-analysis:analyze:${randomUUID()}`,
272
298
  quoteConfirmationToken: flags.values.get('quote-confirmation-token') ?? undefined,
@@ -456,6 +482,36 @@ function submitMediaGenerationRequest(params) {
456
482
  outputPath: params.outputPath,
457
483
  });
458
484
  }
485
+ // Poll a pending media-generation run: `postplus media poll --handle <run-id>`.
486
+ // A media `create`/`transcribe`/`analyze` submit returns an async run handle
487
+ // (`output.data.id`, also surfaced as `output.data.urls.get`) while the provider
488
+ // job is still processing. This resumes that run by handle against the
489
+ // media-generation `operation: 'status'` boundary. It is read-only and
490
+ // billing-idempotent: the Web boundary finds the run by handle and settlement
491
+ // reuses the submit's operationId, so polling never re-reserves or re-charges.
492
+ // The body carries only the status quadruple; submit-only fields (input,
493
+ // requestDimensions, quoteConfirmationToken) are never sent. Mirrors the
494
+ // `research collect --run-handle` polling branch.
495
+ async function runMediaPoll(args) {
496
+ const flags = parseFlags(args, new Set(['json']));
497
+ const handle = requireFlag(flags, 'handle');
498
+ const outputPath = flags.values.get('output') ?? null;
499
+ return runHostedCommand({
500
+ request: () => postHostedJson({
501
+ body: {
502
+ capability: 'media-generation',
503
+ handle,
504
+ operation: 'status',
505
+ operationId: `postplus-cli:media:media-generation:status:${randomUUID()}`,
506
+ },
507
+ pathName: '/api/postplus-cli/hosted/capability',
508
+ skillName: null,
509
+ }),
510
+ errorInputLabel: 'media-poll-handle',
511
+ json: flags.booleans.has('json'),
512
+ outputPath,
513
+ });
514
+ }
459
515
  function buildMediaVerbInput(input) {
460
516
  const record = {};
461
517
  for (const field of input.fields) {
@@ -970,7 +1026,8 @@ function printDomainVerbHelp(domain) {
970
1026
  const verbUsage = domain === 'media'
971
1027
  ? [...MEDIA_VERB_ENDPOINTS.keys()]
972
1028
  .map((verb) => ` postplus media ${verb} <endpoint-key> --<intent/default flags> [--json] [--output <result.json>]\n`)
973
- .join('')
1029
+ .join('') +
1030
+ ' postplus media poll --handle <run-id> [--json] [--output <result.json>]\n'
974
1031
  : ' postplus publish <operation> --request <input.json> [--json] [--output <result.json>]\n';
975
1032
  process.stdout.write(`PostPlus CLI - ${domain} commands
976
1033
 
@@ -990,10 +1047,13 @@ function printMediaEndpointHelp(domain, verb, targetKey, resolved) {
990
1047
 
991
1048
  Surface: request-json (opaque Gemini request payload)
992
1049
  Usage:
993
- postplus ${domain} ${verb} ${targetKey} --request <input.json> [--json] [--output <result.json>]
1050
+ postplus ${domain} ${verb} ${targetKey} --request <input.json> [--video-seconds <n>] [--json] [--output <result.json>]
994
1051
 
995
1052
  --request <file> A JSON object authored verbatim as the Gemini request
996
1053
  (contents + optional generationConfig) under "payload".
1054
+ --video-seconds <n> Optional source video duration in seconds. Supplying it
1055
+ lets the hosted boundary route eligible short videos through
1056
+ its preflight path; omit it to use the default route.
997
1057
  Runner-managed (minted by the CLI; never in the body): operationId, quoteConfirmationToken
998
1058
  `);
999
1059
  return;
package/build/index.js CHANGED
@@ -48,6 +48,7 @@ Usage:
48
48
  postplus research scrape <source-key> --request <input-array.json> [--skill <skill-id>] [--output <result.json>]
49
49
  postplus media schema [--endpoint <endpoint-key>] [--json]
50
50
  postplus media <verb> <endpoint-key> --request <input.json> | --<flags> [--output <result.json>]
51
+ postplus media poll --handle <run-id> [--json] [--output <result.json>]
51
52
  postplus media-file upload --input-file <path> [--mime <type>] [--skill <skill-id>] [--output <result.json>]
52
53
  postplus publish schema [--json]
53
54
  postplus publish <operation> --request <input.json> [--output <result.json>]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postplus/cli",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017",
5
5
  "type": "module",
6
6
  "description": "PostPlus CLI for PostPlus Cloud auth, status, and diagnostics.",