@socialseal/cli 0.1.10 → 0.1.12
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/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/src/index.js +656 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.12 - 2026-06-23
|
|
6
|
+
|
|
7
|
+
- Expose Asset Studio and video production tool surfaces through CLI discovery/schema output.
|
|
8
|
+
- Add category-filtered tool discovery for users and agents.
|
|
9
|
+
|
|
10
|
+
## 0.1.11 - 2026-06-12
|
|
11
|
+
|
|
12
|
+
- Add ad hoc public video URL analysis parity for queue and extract workflows, including `--url` and `--allow-untracked` support.
|
|
13
|
+
|
|
5
14
|
## 0.1.10 - 2026-06-10
|
|
6
15
|
|
|
7
16
|
- Clarify ranked search exports now include publish/observed dates and scoped tracked-search resurfacing history fields when the backend export template is deployed.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -144,7 +144,95 @@ const KNOWN_TOOLS = [
|
|
|
144
144
|
transport: 'post_edge_function',
|
|
145
145
|
workspaceScoped: true,
|
|
146
146
|
knownLocalDevState: 'enabled',
|
|
147
|
-
notes: 'Accepts videoId/videoUid/platformVideoId/searchResultId items; videoId means video_uid or platform-native video id, not a tracking item id.',
|
|
147
|
+
notes: 'Accepts videoId/videoUid/platformVideoId/searchResultId items and public URL items with allowUntracked=true; videoId means video_uid or platform-native video id, not a tracking item id.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'vnext-clips-read',
|
|
151
|
+
category: 'asset-studio',
|
|
152
|
+
description: 'List workspace clip-library items and optionally sign selected source videos.',
|
|
153
|
+
objectType: 'workspace_clip',
|
|
154
|
+
transport: 'post_edge_function',
|
|
155
|
+
workspaceScoped: true,
|
|
156
|
+
knownLocalDevState: 'enabled',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'vnext-clips-create',
|
|
160
|
+
category: 'asset-studio',
|
|
161
|
+
description: 'Create signed clip upload targets and finalize uploaded clip metadata.',
|
|
162
|
+
objectType: 'workspace_clip',
|
|
163
|
+
transport: 'post_edge_function',
|
|
164
|
+
workspaceScoped: true,
|
|
165
|
+
knownLocalDevState: 'enabled',
|
|
166
|
+
actionAliases: ['create', 'finalize'],
|
|
167
|
+
notes: 'The create action returns signed upload URLs; upload bytes to storage before calling finalize.',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'vnext-clip-shot-mappings-read',
|
|
171
|
+
category: 'asset-studio',
|
|
172
|
+
description: 'Read clip-to-blueprint shot mappings for Asset Studio.',
|
|
173
|
+
objectType: 'clip_shot_mapping',
|
|
174
|
+
transport: 'post_edge_function',
|
|
175
|
+
workspaceScoped: true,
|
|
176
|
+
knownLocalDevState: 'enabled',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'vnext-clip-shot-mappings-write',
|
|
180
|
+
category: 'asset-studio',
|
|
181
|
+
description: 'Upsert or delete clip-to-blueprint shot mappings for Asset Studio.',
|
|
182
|
+
objectType: 'clip_shot_mapping',
|
|
183
|
+
transport: 'post_edge_function',
|
|
184
|
+
workspaceScoped: true,
|
|
185
|
+
knownLocalDevState: 'enabled',
|
|
186
|
+
actionAliases: ['upsert', 'delete'],
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'vnext-generated-assets-read',
|
|
190
|
+
category: 'asset-studio',
|
|
191
|
+
description: 'List generated rough cuts for a blueprint or read one generated asset.',
|
|
192
|
+
objectType: 'generated_asset',
|
|
193
|
+
transport: 'post_edge_function',
|
|
194
|
+
workspaceScoped: true,
|
|
195
|
+
knownLocalDevState: 'enabled',
|
|
196
|
+
actionAliases: ['list', 'detail'],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'vnext-generated-asset-create',
|
|
200
|
+
category: 'asset-studio',
|
|
201
|
+
description: 'Create a generated rough-cut asset from an edit spec.',
|
|
202
|
+
objectType: 'generated_asset',
|
|
203
|
+
transport: 'post_edge_function',
|
|
204
|
+
workspaceScoped: true,
|
|
205
|
+
knownLocalDevState: 'enabled',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'vnext-generated-asset-optimize',
|
|
209
|
+
category: 'asset-studio',
|
|
210
|
+
description: 'Optimize a generated asset or create a new revision.',
|
|
211
|
+
objectType: 'generated_asset_revision',
|
|
212
|
+
transport: 'post_edge_function',
|
|
213
|
+
workspaceScoped: true,
|
|
214
|
+
knownLocalDevState: 'enabled',
|
|
215
|
+
actionAliases: ['optimize', 'create-revision'],
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'vnext-generated-asset-export',
|
|
219
|
+
category: 'asset-studio',
|
|
220
|
+
description: 'Export a generated rough cut as FCPXML.',
|
|
221
|
+
objectType: 'generated_asset_export',
|
|
222
|
+
transport: 'post_edge_function',
|
|
223
|
+
workspaceScoped: true,
|
|
224
|
+
knownLocalDevState: 'enabled',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'vnext-generated-asset-share',
|
|
228
|
+
category: 'asset-studio',
|
|
229
|
+
description: 'Create, read, or revoke generated-asset share links.',
|
|
230
|
+
objectType: 'generated_asset_share',
|
|
231
|
+
transport: 'post_edge_function',
|
|
232
|
+
workspaceScoped: false,
|
|
233
|
+
knownLocalDevState: 'enabled',
|
|
234
|
+
actionAliases: ['create', 'read', 'revoke'],
|
|
235
|
+
notes: 'create/revoke require workspaceId in the body; read uses shareToken and does not require workspace scope.',
|
|
148
236
|
},
|
|
149
237
|
{ name: 'douyin-geo-api', category: 'search', description: 'Query Douyin search and geo data.' },
|
|
150
238
|
{
|
|
@@ -218,7 +306,34 @@ const KNOWN_TOOLS = [
|
|
|
218
306
|
{ name: 'vnext-blueprints-create', category: 'vnext', description: 'Create a vNext blueprint from grounded evidence.' },
|
|
219
307
|
{ name: 'vnext-blueprints-generate', category: 'vnext', description: 'Generate a vNext blueprint from workspace opportunity data.' },
|
|
220
308
|
{ name: 'vnext-blueprints-read', category: 'vnext', description: 'Read vNext blueprint history and specific versions.' },
|
|
309
|
+
{
|
|
310
|
+
name: 'vnext-blueprints-shots-read',
|
|
311
|
+
category: 'video-production',
|
|
312
|
+
description: 'Read shot-lift and pinned shot assets for a blueprint.',
|
|
313
|
+
objectType: 'blueprint_shot_asset',
|
|
314
|
+
transport: 'post_edge_function',
|
|
315
|
+
workspaceScoped: true,
|
|
316
|
+
knownLocalDevState: 'enabled',
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: 'vnext-blueprints-shots-refresh',
|
|
320
|
+
category: 'video-production',
|
|
321
|
+
description: 'Queue a refresh for blueprint shot assets.',
|
|
322
|
+
objectType: 'blueprint_shots_job',
|
|
323
|
+
transport: 'post_edge_function',
|
|
324
|
+
workspaceScoped: true,
|
|
325
|
+
knownLocalDevState: 'enabled',
|
|
326
|
+
},
|
|
221
327
|
{ name: 'vnext-briefs-create', category: 'vnext', description: 'Create a vNext brief record.' },
|
|
328
|
+
{
|
|
329
|
+
name: 'vnext-briefs-export',
|
|
330
|
+
category: 'video-production',
|
|
331
|
+
description: 'Export a generated vNext brief as markdown.',
|
|
332
|
+
objectType: 'vnext_brief_export',
|
|
333
|
+
transport: 'post_edge_function',
|
|
334
|
+
workspaceScoped: true,
|
|
335
|
+
knownLocalDevState: 'enabled',
|
|
336
|
+
},
|
|
222
337
|
{ name: 'vnext-briefs-generate', category: 'vnext', description: 'Generate a vNext brief from a blueprint or opportunity.' },
|
|
223
338
|
{ name: 'vnext-briefs-read', category: 'vnext', description: 'Read generated vNext briefs and version history.' },
|
|
224
339
|
{ name: 'vnext-intents', category: 'vnext', description: 'List, create, update, or delete vNext intents.' },
|
|
@@ -258,6 +373,23 @@ const TOOL_SCHEMA_HINTS = {
|
|
|
258
373
|
jobId: '11111111-1111-4111-8111-111111111111',
|
|
259
374
|
},
|
|
260
375
|
},
|
|
376
|
+
{
|
|
377
|
+
action: 'status',
|
|
378
|
+
required: ['action=status', 'workspaceId or --workspace-id', 'items[] with videoUid or platformVideoId'],
|
|
379
|
+
optional: ['includeRawAnalysis'],
|
|
380
|
+
notes: 'Status polling is read-only and does not accept URL items; use videoUid or platformVideoId returned by the initial URL extraction response.',
|
|
381
|
+
example: {
|
|
382
|
+
action: 'status',
|
|
383
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
384
|
+
items: [
|
|
385
|
+
{
|
|
386
|
+
videoUid: '11111111-1111-4111-8111-111111111111',
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
includeAssets: false,
|
|
390
|
+
includeSourceVideo: false,
|
|
391
|
+
},
|
|
392
|
+
},
|
|
261
393
|
],
|
|
262
394
|
cliExamples: [
|
|
263
395
|
'socialseal tools call --function agent-tool-jobs --body \'{"action":"start","toolName":"search_videos","payload":{"query":"best africa safari itinerary","platform":"tiktok","region":"IN"}}\'',
|
|
@@ -376,6 +508,369 @@ const TOOL_SCHEMA_HINTS = {
|
|
|
376
508
|
'socialseal tools call --function get-google-ai-search-results --body \'{"runId":6809,"includeCitations":true,"limit":10}\'',
|
|
377
509
|
],
|
|
378
510
|
},
|
|
511
|
+
'tracked-video-extract': {
|
|
512
|
+
summary: 'Extract assets and queue/read analysis for tracked identifiers or ad hoc public video URLs.',
|
|
513
|
+
operations: [
|
|
514
|
+
{
|
|
515
|
+
action: 'extract',
|
|
516
|
+
required: ['workspaceId or --workspace-id', 'items[] with exactly one selector'],
|
|
517
|
+
optional: [
|
|
518
|
+
'items[].searchResultId',
|
|
519
|
+
'items[].videoId',
|
|
520
|
+
'items[].videoUid',
|
|
521
|
+
'items[].platformVideoId',
|
|
522
|
+
'items[].url',
|
|
523
|
+
'allowUntracked',
|
|
524
|
+
'ensureAnalysis',
|
|
525
|
+
'includeAssets',
|
|
526
|
+
'includeSourceVideo',
|
|
527
|
+
'frameStrategy',
|
|
528
|
+
'frameCount',
|
|
529
|
+
'signedUrlSeconds',
|
|
530
|
+
],
|
|
531
|
+
notes: 'URL items require request-level allowUntracked:true. Supported selectors are url, searchResultId, videoId, videoUid, or platformVideoId.',
|
|
532
|
+
example: {
|
|
533
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
534
|
+
allowUntracked: true,
|
|
535
|
+
ensureAnalysis: true,
|
|
536
|
+
items: [
|
|
537
|
+
{
|
|
538
|
+
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
action: 'queue-analysis',
|
|
545
|
+
required: ['workspaceId or --workspace-id', 'items[] with exactly one selector'],
|
|
546
|
+
optional: ['allowUntracked for URL items', 'queueOnly', 'includeRawAnalysis'],
|
|
547
|
+
notes: 'Set ensureAnalysis:true and queueOnly:true to enqueue analysis without asset URL generation.',
|
|
548
|
+
example: {
|
|
549
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
550
|
+
allowUntracked: true,
|
|
551
|
+
ensureAnalysis: true,
|
|
552
|
+
queueOnly: true,
|
|
553
|
+
includeAssets: false,
|
|
554
|
+
items: [
|
|
555
|
+
{
|
|
556
|
+
url: 'https://www.tiktok.com/@creator/video/7348293840000000000',
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
],
|
|
562
|
+
cliExamples: [
|
|
563
|
+
'socialseal video extract --url https://www.youtube.com/watch?v=dQw4w9WgXcQ --allow-untracked --wait --out-dir ./video-assets --workspace-id <workspace-uuid>',
|
|
564
|
+
'socialseal video queue-analysis --url https://www.tiktok.com/@creator/video/7348293840000000000 --allow-untracked --wait --workspace-id <workspace-uuid>',
|
|
565
|
+
'socialseal video extract --video-uid <video-uuid> --wait --workspace-id <workspace-uuid>',
|
|
566
|
+
'socialseal tools call --function tracked-video-extract --workspace-id <workspace-uuid> --body \'{"allowUntracked":true,"items":[{"url":"https://www.instagram.com/reel/SHORTCODE/"}]}\'',
|
|
567
|
+
],
|
|
568
|
+
},
|
|
569
|
+
'vnext-clips-read': {
|
|
570
|
+
summary: 'List Asset Studio clip-library items and optionally sign selected video URLs.',
|
|
571
|
+
operations: [
|
|
572
|
+
{
|
|
573
|
+
action: 'list',
|
|
574
|
+
required: ['workspaceId or --workspace-id'],
|
|
575
|
+
optional: ['videoClipIds[] to include signed source video URLs'],
|
|
576
|
+
example: {
|
|
577
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
578
|
+
videoClipIds: ['11111111-1111-4111-8111-111111111111'],
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
cliExamples: [
|
|
583
|
+
'socialseal tools call --function vnext-clips-read --workspace-id <workspace-uuid> --body \'{"videoClipIds":["<clip-uuid>"]}\'',
|
|
584
|
+
],
|
|
585
|
+
},
|
|
586
|
+
'vnext-clips-create': {
|
|
587
|
+
summary: 'Create signed upload targets for clips and finalize uploaded clip metadata.',
|
|
588
|
+
operations: [
|
|
589
|
+
{
|
|
590
|
+
action: 'create',
|
|
591
|
+
required: ['action=create', 'workspaceId or --workspace-id', 'fileName', 'mimeType'],
|
|
592
|
+
optional: [],
|
|
593
|
+
example: {
|
|
594
|
+
action: 'create',
|
|
595
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
596
|
+
fileName: 'hero-shot.mp4',
|
|
597
|
+
mimeType: 'video/mp4',
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
action: 'finalize',
|
|
602
|
+
required: ['action=finalize', 'workspaceId or --workspace-id', 'clipId', 'fileName', 'storagePath', 'mimeType', 'sizeBytes', 'rightsAttested=true'],
|
|
603
|
+
optional: ['durationSeconds', 'width', 'height', 'posterPath'],
|
|
604
|
+
example: {
|
|
605
|
+
action: 'finalize',
|
|
606
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
607
|
+
clipId: '11111111-1111-4111-8111-111111111111',
|
|
608
|
+
fileName: 'hero-shot.mp4',
|
|
609
|
+
storagePath: 'workspace-00000000-0000-4000-8000-000000000000/11111111-1111-4111-8111-111111111111.mp4',
|
|
610
|
+
mimeType: 'video/mp4',
|
|
611
|
+
sizeBytes: 1048576,
|
|
612
|
+
rightsAttested: true,
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
],
|
|
616
|
+
cliExamples: [
|
|
617
|
+
'socialseal tools call --function vnext-clips-create --workspace-id <workspace-uuid> --body \'{"action":"create","fileName":"hero-shot.mp4","mimeType":"video/mp4"}\'',
|
|
618
|
+
'socialseal tools call --function vnext-clips-create --workspace-id <workspace-uuid> --body @clip-finalize.json',
|
|
619
|
+
],
|
|
620
|
+
},
|
|
621
|
+
'vnext-clip-shot-mappings-read': {
|
|
622
|
+
summary: 'Read Asset Studio clip-to-shot mappings for a blueprint.',
|
|
623
|
+
operations: [
|
|
624
|
+
{
|
|
625
|
+
action: 'read',
|
|
626
|
+
required: ['workspaceId or --workspace-id', 'blueprintId'],
|
|
627
|
+
optional: [],
|
|
628
|
+
example: {
|
|
629
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
630
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
631
|
+
},
|
|
632
|
+
},
|
|
633
|
+
],
|
|
634
|
+
cliExamples: [
|
|
635
|
+
'socialseal tools call --function vnext-clip-shot-mappings-read --workspace-id <workspace-uuid> --body \'{"blueprintId":"<blueprint-uuid>"}\'',
|
|
636
|
+
],
|
|
637
|
+
},
|
|
638
|
+
'vnext-clip-shot-mappings-write': {
|
|
639
|
+
summary: 'Upsert or delete Asset Studio clip-to-shot mappings.',
|
|
640
|
+
operations: [
|
|
641
|
+
{
|
|
642
|
+
action: 'upsert',
|
|
643
|
+
required: ['action=upsert', 'workspaceId or --workspace-id', 'blueprintId', 'panelId', 'clipId'],
|
|
644
|
+
optional: ['source (suggested|override)', 'score'],
|
|
645
|
+
example: {
|
|
646
|
+
action: 'upsert',
|
|
647
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
648
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
649
|
+
panelId: 'panel-1',
|
|
650
|
+
clipId: '11111111-1111-4111-8111-111111111111',
|
|
651
|
+
source: 'override',
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
action: 'delete',
|
|
656
|
+
required: ['action=delete', 'workspaceId or --workspace-id', 'blueprintId', 'panelId'],
|
|
657
|
+
optional: [],
|
|
658
|
+
example: {
|
|
659
|
+
action: 'delete',
|
|
660
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
661
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
662
|
+
panelId: 'panel-1',
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
],
|
|
666
|
+
cliExamples: [
|
|
667
|
+
'socialseal tools call --function vnext-clip-shot-mappings-write --workspace-id <workspace-uuid> --body \'{"action":"upsert","blueprintId":"<blueprint-uuid>","panelId":"panel-1","clipId":"<clip-uuid>"}\'',
|
|
668
|
+
],
|
|
669
|
+
},
|
|
670
|
+
'vnext-generated-assets-read': {
|
|
671
|
+
summary: 'List generated rough cuts for a blueprint or read one generated asset.',
|
|
672
|
+
operations: [
|
|
673
|
+
{
|
|
674
|
+
action: 'list',
|
|
675
|
+
required: ['action=list', 'workspaceId or --workspace-id', 'blueprintId'],
|
|
676
|
+
optional: [],
|
|
677
|
+
example: {
|
|
678
|
+
action: 'list',
|
|
679
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
680
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
action: 'detail',
|
|
685
|
+
required: ['action=detail', 'workspaceId or --workspace-id', 'assetId'],
|
|
686
|
+
optional: [],
|
|
687
|
+
example: {
|
|
688
|
+
action: 'detail',
|
|
689
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
690
|
+
assetId: '33333333-3333-4333-8333-333333333333',
|
|
691
|
+
},
|
|
692
|
+
},
|
|
693
|
+
],
|
|
694
|
+
cliExamples: [
|
|
695
|
+
'socialseal tools call --function vnext-generated-assets-read --workspace-id <workspace-uuid> --body \'{"action":"list","blueprintId":"<blueprint-uuid>"}\'',
|
|
696
|
+
'socialseal tools call --function vnext-generated-assets-read --workspace-id <workspace-uuid> --body \'{"action":"detail","assetId":"<asset-uuid>"}\'',
|
|
697
|
+
],
|
|
698
|
+
},
|
|
699
|
+
'vnext-generated-asset-create': {
|
|
700
|
+
summary: 'Create a generated rough cut from an Asset Studio edit spec.',
|
|
701
|
+
operations: [
|
|
702
|
+
{
|
|
703
|
+
action: 'create',
|
|
704
|
+
required: ['workspaceId or --workspace-id', 'blueprintId', 'title', 'editSpec'],
|
|
705
|
+
optional: [],
|
|
706
|
+
example: {
|
|
707
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
708
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
709
|
+
title: 'Homepage rough cut',
|
|
710
|
+
editSpec: {
|
|
711
|
+
version: 1,
|
|
712
|
+
fps: 30,
|
|
713
|
+
width: 1080,
|
|
714
|
+
height: 1920,
|
|
715
|
+
totalDurationSeconds: 3,
|
|
716
|
+
shots: [
|
|
717
|
+
{
|
|
718
|
+
panelId: 'panel-1',
|
|
719
|
+
clipId: '11111111-1111-4111-8111-111111111111',
|
|
720
|
+
title: 'Opening hook',
|
|
721
|
+
kind: 'hook',
|
|
722
|
+
shotLabel: 'Hero exterior',
|
|
723
|
+
sourceStartSeconds: 0,
|
|
724
|
+
durationSeconds: 3,
|
|
725
|
+
evidenceIds: [],
|
|
726
|
+
},
|
|
727
|
+
],
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
],
|
|
732
|
+
cliExamples: [
|
|
733
|
+
'socialseal tools call --function vnext-generated-asset-create --workspace-id <workspace-uuid> --body @edit-spec.json',
|
|
734
|
+
],
|
|
735
|
+
},
|
|
736
|
+
'vnext-generated-asset-optimize': {
|
|
737
|
+
summary: 'Optimize a generated asset or create a new revision.',
|
|
738
|
+
operations: [
|
|
739
|
+
{
|
|
740
|
+
action: 'optimize',
|
|
741
|
+
required: ['action=optimize', 'workspaceId or --workspace-id', 'assetId'],
|
|
742
|
+
optional: [],
|
|
743
|
+
example: {
|
|
744
|
+
action: 'optimize',
|
|
745
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
746
|
+
assetId: '33333333-3333-4333-8333-333333333333',
|
|
747
|
+
},
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
action: 'create-revision',
|
|
751
|
+
required: ['action=create-revision', 'workspaceId or --workspace-id', 'assetId'],
|
|
752
|
+
optional: [],
|
|
753
|
+
example: {
|
|
754
|
+
action: 'create-revision',
|
|
755
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
756
|
+
assetId: '33333333-3333-4333-8333-333333333333',
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
],
|
|
760
|
+
cliExamples: [
|
|
761
|
+
'socialseal tools call --function vnext-generated-asset-optimize --workspace-id <workspace-uuid> --body \'{"action":"optimize","assetId":"<asset-uuid>"}\'',
|
|
762
|
+
],
|
|
763
|
+
},
|
|
764
|
+
'vnext-generated-asset-export': {
|
|
765
|
+
summary: 'Export a generated rough cut as FCPXML.',
|
|
766
|
+
operations: [
|
|
767
|
+
{
|
|
768
|
+
action: 'export',
|
|
769
|
+
required: ['workspaceId or --workspace-id', 'assetId'],
|
|
770
|
+
optional: ['format=fcpxml'],
|
|
771
|
+
example: {
|
|
772
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
773
|
+
assetId: '33333333-3333-4333-8333-333333333333',
|
|
774
|
+
format: 'fcpxml',
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
],
|
|
778
|
+
cliExamples: [
|
|
779
|
+
'socialseal tools call --function vnext-generated-asset-export --workspace-id <workspace-uuid> --body \'{"assetId":"<asset-uuid>","format":"fcpxml"}\'',
|
|
780
|
+
],
|
|
781
|
+
},
|
|
782
|
+
'vnext-generated-asset-share': {
|
|
783
|
+
summary: 'Create, read, or revoke generated rough-cut share links.',
|
|
784
|
+
operations: [
|
|
785
|
+
{
|
|
786
|
+
action: 'create',
|
|
787
|
+
required: ['action=create', 'workspaceId', 'assetId'],
|
|
788
|
+
optional: ['ttlSeconds', 'shareBaseUrl'],
|
|
789
|
+
example: {
|
|
790
|
+
action: 'create',
|
|
791
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
792
|
+
assetId: '33333333-3333-4333-8333-333333333333',
|
|
793
|
+
ttlSeconds: 604800,
|
|
794
|
+
},
|
|
795
|
+
},
|
|
796
|
+
{
|
|
797
|
+
action: 'read',
|
|
798
|
+
required: ['action=read', 'shareToken'],
|
|
799
|
+
optional: [],
|
|
800
|
+
example: {
|
|
801
|
+
action: 'read',
|
|
802
|
+
shareToken: '0123456789abcdef0123456789abcdef',
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
action: 'revoke',
|
|
807
|
+
required: ['action=revoke', 'workspaceId', 'shareLinkId'],
|
|
808
|
+
optional: [],
|
|
809
|
+
example: {
|
|
810
|
+
action: 'revoke',
|
|
811
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
812
|
+
shareLinkId: '44444444-4444-4444-8444-444444444444',
|
|
813
|
+
},
|
|
814
|
+
},
|
|
815
|
+
],
|
|
816
|
+
cliExamples: [
|
|
817
|
+
'socialseal tools call --function vnext-generated-asset-share --body \'{"action":"create","workspaceId":"<workspace-uuid>","assetId":"<asset-uuid>"}\'',
|
|
818
|
+
'socialseal tools call --function vnext-generated-asset-share --body \'{"action":"read","shareToken":"<share-token>"}\'',
|
|
819
|
+
],
|
|
820
|
+
},
|
|
821
|
+
'vnext-blueprints-shots-read': {
|
|
822
|
+
summary: 'Read blueprint shot-lift rows and pinned shot assets with signed URLs.',
|
|
823
|
+
operations: [
|
|
824
|
+
{
|
|
825
|
+
action: 'read',
|
|
826
|
+
required: ['workspaceId or --workspace-id', 'blueprintId'],
|
|
827
|
+
optional: ['signedUrlSeconds'],
|
|
828
|
+
example: {
|
|
829
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
830
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
831
|
+
signedUrlSeconds: 3600,
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
],
|
|
835
|
+
cliExamples: [
|
|
836
|
+
'socialseal tools call --function vnext-blueprints-shots-read --workspace-id <workspace-uuid> --body \'{"blueprintId":"<blueprint-uuid>"}\'',
|
|
837
|
+
],
|
|
838
|
+
},
|
|
839
|
+
'vnext-blueprints-shots-refresh': {
|
|
840
|
+
summary: 'Queue a refresh for blueprint shot assets.',
|
|
841
|
+
operations: [
|
|
842
|
+
{
|
|
843
|
+
action: 'refresh',
|
|
844
|
+
required: ['workspaceId or --workspace-id', 'blueprintId'],
|
|
845
|
+
optional: [],
|
|
846
|
+
example: {
|
|
847
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
848
|
+
blueprintId: '22222222-2222-4222-8222-222222222222',
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
],
|
|
852
|
+
cliExamples: [
|
|
853
|
+
'socialseal tools call --function vnext-blueprints-shots-refresh --workspace-id <workspace-uuid> --body \'{"blueprintId":"<blueprint-uuid>"}\'',
|
|
854
|
+
],
|
|
855
|
+
},
|
|
856
|
+
'vnext-briefs-export': {
|
|
857
|
+
summary: 'Export the latest or selected generated vNext brief as markdown.',
|
|
858
|
+
operations: [
|
|
859
|
+
{
|
|
860
|
+
action: 'export',
|
|
861
|
+
required: ['workspaceId or --workspace-id', 'opportunityKey'],
|
|
862
|
+
optional: ['version'],
|
|
863
|
+
example: {
|
|
864
|
+
workspaceId: '00000000-0000-4000-8000-000000000000',
|
|
865
|
+
opportunityKey: 'opportunity-key',
|
|
866
|
+
version: 1,
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
],
|
|
870
|
+
cliExamples: [
|
|
871
|
+
'socialseal tools call --function vnext-briefs-export --workspace-id <workspace-uuid> --body \'{"opportunityKey":"<opportunity-key>"}\'',
|
|
872
|
+
],
|
|
873
|
+
},
|
|
379
874
|
'group-management': {
|
|
380
875
|
summary: 'Manage single-platform tracking groups and memberships.',
|
|
381
876
|
operations: [
|
|
@@ -469,6 +964,18 @@ function buildToolRegistry() {
|
|
|
469
964
|
});
|
|
470
965
|
}
|
|
471
966
|
|
|
967
|
+
function filterToolRegistry(tools, category) {
|
|
968
|
+
const normalizedCategory = trimString(category).toLowerCase();
|
|
969
|
+
const filtered = normalizedCategory
|
|
970
|
+
? tools.filter((tool) => trimString(tool.category).toLowerCase() === normalizedCategory)
|
|
971
|
+
: tools;
|
|
972
|
+
return [...filtered].sort((a, b) => {
|
|
973
|
+
const categoryCompare = trimString(a.category).localeCompare(trimString(b.category));
|
|
974
|
+
if (categoryCompare !== 0) return categoryCompare;
|
|
975
|
+
return trimString(a.name).localeCompare(trimString(b.name));
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
|
|
472
979
|
function getConfigPath() {
|
|
473
980
|
return process.env.SOCIALSEAL_CONFIG || DEFAULT_CONFIG_PATH;
|
|
474
981
|
}
|
|
@@ -751,6 +1258,7 @@ function inferExtension(urlValue, contentType, fallback = '.bin') {
|
|
|
751
1258
|
function normalizeVideoExtractBody(body) {
|
|
752
1259
|
const normalized = { ...body };
|
|
753
1260
|
const hasInlineIdentifier =
|
|
1261
|
+
normalized.url !== undefined ||
|
|
754
1262
|
normalized.videoId !== undefined ||
|
|
755
1263
|
normalized.searchResultId !== undefined ||
|
|
756
1264
|
normalized.videoUid !== undefined ||
|
|
@@ -758,12 +1266,14 @@ function normalizeVideoExtractBody(body) {
|
|
|
758
1266
|
|
|
759
1267
|
if (!Array.isArray(normalized.items) && hasInlineIdentifier) {
|
|
760
1268
|
normalized.items = [{
|
|
1269
|
+
url: normalized.url,
|
|
761
1270
|
videoId: normalized.videoId,
|
|
762
1271
|
searchResultId: normalized.searchResultId,
|
|
763
1272
|
videoUid: normalized.videoUid,
|
|
764
1273
|
platformVideoId: normalized.platformVideoId,
|
|
765
1274
|
platformId: normalized.platformId,
|
|
766
1275
|
}];
|
|
1276
|
+
delete normalized.url;
|
|
767
1277
|
delete normalized.videoId;
|
|
768
1278
|
delete normalized.searchResultId;
|
|
769
1279
|
delete normalized.videoUid;
|
|
@@ -774,6 +1284,11 @@ function normalizeVideoExtractBody(body) {
|
|
|
774
1284
|
return normalized;
|
|
775
1285
|
}
|
|
776
1286
|
|
|
1287
|
+
function hasUrlVideoItems(body) {
|
|
1288
|
+
const items = Array.isArray(body?.items) ? body.items : [];
|
|
1289
|
+
return items.some((item) => typeof item?.url === 'string' && item.url.trim().length > 0);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
777
1292
|
function buildVideoExtractBody(opts, workspaceId) {
|
|
778
1293
|
const parsed = opts.body
|
|
779
1294
|
? ensureJsonObject(parseJsonInput(opts.body, { label: 'body' }), 'body')
|
|
@@ -782,6 +1297,7 @@ function buildVideoExtractBody(opts, workspaceId) {
|
|
|
782
1297
|
|
|
783
1298
|
if (!Array.isArray(normalized.items) || normalized.items.length === 0) {
|
|
784
1299
|
const inlineItem = stripUndefinedEntries({
|
|
1300
|
+
url: trimString(opts.url) || undefined,
|
|
785
1301
|
videoId: trimString(opts.videoId) || undefined,
|
|
786
1302
|
searchResultId: opts.searchResultId !== undefined
|
|
787
1303
|
? coercePositiveInteger(opts.searchResultId, 'searchResultId')
|
|
@@ -791,10 +1307,10 @@ function buildVideoExtractBody(opts, workspaceId) {
|
|
|
791
1307
|
});
|
|
792
1308
|
|
|
793
1309
|
if (Object.keys(inlineItem).length === 0) {
|
|
794
|
-
throw new CliError('Provide --body or one of --video-id, --video-uid, --platform-video-id, or --search-result-id.', {
|
|
1310
|
+
throw new CliError('Provide --body or one of --url, --video-id, --video-uid, --platform-video-id, or --search-result-id.', {
|
|
795
1311
|
code: 'MISSING_ARGUMENT',
|
|
796
1312
|
exitCode: EXIT_CODES.USAGE,
|
|
797
|
-
hint: '--video-id accepts a video_uid or platform video id
|
|
1313
|
+
hint: '--url requires --allow-untracked. --video-id accepts a video_uid or platform video id; it does not accept tracking item ids.',
|
|
798
1314
|
});
|
|
799
1315
|
}
|
|
800
1316
|
|
|
@@ -811,6 +1327,17 @@ function buildVideoExtractBody(opts, workspaceId) {
|
|
|
811
1327
|
}
|
|
812
1328
|
|
|
813
1329
|
const nextBody = { ...bodyWithWorkspace };
|
|
1330
|
+
if (opts.allowUntracked === true) {
|
|
1331
|
+
nextBody.allowUntracked = true;
|
|
1332
|
+
}
|
|
1333
|
+
if (hasUrlVideoItems(nextBody) && nextBody.allowUntracked !== true) {
|
|
1334
|
+
throw new CliError('URL video analysis requires --allow-untracked or allowUntracked:true in --body.', {
|
|
1335
|
+
code: 'ALLOW_UNTRACKED_REQUIRED',
|
|
1336
|
+
exitCode: EXIT_CODES.USAGE,
|
|
1337
|
+
hint: 'Pass --allow-untracked for ad hoc public URL analysis. Existing tracked identifier flows do not need this flag.',
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
|
|
814
1341
|
if (opts.wait) {
|
|
815
1342
|
nextBody.ensureAnalysis = true;
|
|
816
1343
|
} else if (opts.ensureAnalysis === true) {
|
|
@@ -868,11 +1395,60 @@ function buildVideoQueueBody(opts, workspaceId) {
|
|
|
868
1395
|
function hasPendingVideoExtractResults(payload) {
|
|
869
1396
|
const results = Array.isArray(payload?.results) ? payload.results : [];
|
|
870
1397
|
return results.some((result) => {
|
|
871
|
-
const
|
|
872
|
-
|
|
1398
|
+
const itemStatus = String(result?.status || '').trim().toLowerCase();
|
|
1399
|
+
const analysisStatus = String(
|
|
1400
|
+
result?.analysis?.normalizedStatus || result?.analysis?.status || '',
|
|
1401
|
+
).trim().toLowerCase();
|
|
1402
|
+
const status = itemStatus || analysisStatus;
|
|
1403
|
+
return ACTIVE_STATUS_VALUES.has(status);
|
|
873
1404
|
});
|
|
874
1405
|
}
|
|
875
1406
|
|
|
1407
|
+
function buildVideoExtractStatusPollBody(originalBody, payload) {
|
|
1408
|
+
const results = Array.isArray(payload?.results) ? payload.results : [];
|
|
1409
|
+
const items = results
|
|
1410
|
+
.map((result) => {
|
|
1411
|
+
const resolved = isJsonObject(result?.resolvedVideo)
|
|
1412
|
+
? result.resolvedVideo
|
|
1413
|
+
: (isJsonObject(result?.resolved) ? result.resolved : {});
|
|
1414
|
+
const videoUid = trimString(resolved.videoUid || resolved.video_uid);
|
|
1415
|
+
if (videoUid) return { videoUid };
|
|
1416
|
+
const platformVideoId = trimString(
|
|
1417
|
+
resolved.platformVideoId || resolved.platform_video_id,
|
|
1418
|
+
);
|
|
1419
|
+
if (platformVideoId) {
|
|
1420
|
+
const item = { platformVideoId };
|
|
1421
|
+
if (Number.isInteger(resolved.platformId)) {
|
|
1422
|
+
item.platformId = resolved.platformId;
|
|
1423
|
+
} else if (Number.isInteger(resolved.platform_id)) {
|
|
1424
|
+
item.platformId = resolved.platform_id;
|
|
1425
|
+
}
|
|
1426
|
+
return item;
|
|
1427
|
+
}
|
|
1428
|
+
const request = isJsonObject(result?.request) ? result.request : null;
|
|
1429
|
+
if (!request || request.url) return null;
|
|
1430
|
+
return request;
|
|
1431
|
+
})
|
|
1432
|
+
.filter(Boolean);
|
|
1433
|
+
|
|
1434
|
+
if (items.length === 0) {
|
|
1435
|
+
const originalHasUrl = Array.isArray(originalBody.items) &&
|
|
1436
|
+
originalBody.items.some((item) => Boolean(item?.url));
|
|
1437
|
+
if (originalHasUrl) return null;
|
|
1438
|
+
return originalBody;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
return {
|
|
1442
|
+
workspaceId: originalBody.workspaceId,
|
|
1443
|
+
action: 'status',
|
|
1444
|
+
items,
|
|
1445
|
+
includeRawAnalysis: originalBody.includeRawAnalysis === true,
|
|
1446
|
+
includeAssets: false,
|
|
1447
|
+
includeSourceVideo: false,
|
|
1448
|
+
ensureAnalysis: false,
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
|
|
876
1452
|
async function downloadAssetToFile({ url, outDir, stem, timeoutMs }) {
|
|
877
1453
|
const response = await fetchWithTimeout(url, {
|
|
878
1454
|
method: 'GET',
|
|
@@ -1020,6 +1596,23 @@ function resolvePayloadWorkspaceId(payload, fallbackWorkspaceId) {
|
|
|
1020
1596
|
return fallbackWorkspaceId || null;
|
|
1021
1597
|
}
|
|
1022
1598
|
|
|
1599
|
+
function isGeneratedAssetShareScopedAction(functionName, payload) {
|
|
1600
|
+
if (functionName !== 'vnext-generated-asset-share' || !isJsonObject(payload)) {
|
|
1601
|
+
return false;
|
|
1602
|
+
}
|
|
1603
|
+
const action = trimString(payload.action).toLowerCase();
|
|
1604
|
+
return action === 'create' || action === 'revoke';
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
function shouldRequireToolWorkspace(functionName, payload) {
|
|
1608
|
+
const tool = getKnownTool(functionName);
|
|
1609
|
+
const category = trimString(tool?.category).toLowerCase();
|
|
1610
|
+
return (
|
|
1611
|
+
Boolean(tool?.workspaceScoped) &&
|
|
1612
|
+
(category === 'asset-studio' || category === 'video-production')
|
|
1613
|
+
) || isGeneratedAssetShareScopedAction(functionName, payload);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1023
1616
|
function isUuidLike(value) {
|
|
1024
1617
|
return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(value.trim());
|
|
1025
1618
|
}
|
|
@@ -3612,6 +4205,26 @@ async function handleToolsCall(opts) {
|
|
|
3612
4205
|
});
|
|
3613
4206
|
}
|
|
3614
4207
|
|
|
4208
|
+
const scopedPayload = isJsonObject(translated.normalizedPayload)
|
|
4209
|
+
? translated.normalizedPayload
|
|
4210
|
+
: (isJsonObject(translated.body) ? translated.body : payload);
|
|
4211
|
+
const hasSpecialWorkspaceHandling = new Set([
|
|
4212
|
+
'group-management',
|
|
4213
|
+
'export_tracking_data',
|
|
4214
|
+
'tracked-video-extract',
|
|
4215
|
+
]).has(opts.function);
|
|
4216
|
+
if (!hasSpecialWorkspaceHandling && shouldRequireToolWorkspace(opts.function, scopedPayload)) {
|
|
4217
|
+
requireWorkspaceSelection(effectiveWorkspaceId, {
|
|
4218
|
+
label: opts.function,
|
|
4219
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, include workspaceId in the body, or configure a default workspace.',
|
|
4220
|
+
});
|
|
4221
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
4222
|
+
workspaceId: effectiveWorkspaceId,
|
|
4223
|
+
source: effectiveWorkspaceSource,
|
|
4224
|
+
label: opts.function,
|
|
4225
|
+
});
|
|
4226
|
+
}
|
|
4227
|
+
|
|
3615
4228
|
emitTrackingCreateScopeWarning(
|
|
3616
4229
|
isJsonObject(translated.normalizedPayload) ? trimString(translated.normalizedPayload.action).toLowerCase() : '',
|
|
3617
4230
|
effectiveWorkspaceId,
|
|
@@ -3710,9 +4323,10 @@ async function handleToolsCall(opts) {
|
|
|
3710
4323
|
}
|
|
3711
4324
|
|
|
3712
4325
|
function handleToolsList(opts) {
|
|
3713
|
-
const tools = buildToolRegistry();
|
|
4326
|
+
const tools = filterToolRegistry(buildToolRegistry(), opts.category);
|
|
3714
4327
|
const payload = {
|
|
3715
4328
|
discovery: 'built_in_registry',
|
|
4329
|
+
category: trimString(opts.category) || null,
|
|
3716
4330
|
tools,
|
|
3717
4331
|
note: STATIC_TOOL_REGISTRY_NOTE,
|
|
3718
4332
|
schemaNote: STATIC_TOOL_SCHEMA_NOTE,
|
|
@@ -3724,6 +4338,9 @@ function handleToolsList(opts) {
|
|
|
3724
4338
|
}
|
|
3725
4339
|
|
|
3726
4340
|
process.stdout.write('[socialseal] Built-in tool registry\n');
|
|
4341
|
+
if (payload.category) {
|
|
4342
|
+
process.stdout.write(`[socialseal] Category filter: ${payload.category}\n`);
|
|
4343
|
+
}
|
|
3727
4344
|
process.stdout.write(`[socialseal] ${payload.note}\n`);
|
|
3728
4345
|
process.stdout.write(`[socialseal] ${payload.schemaNote}\n`);
|
|
3729
4346
|
|
|
@@ -4448,13 +5065,13 @@ async function handleVideoExtract(opts) {
|
|
|
4448
5065
|
method: 'POST',
|
|
4449
5066
|
});
|
|
4450
5067
|
|
|
4451
|
-
const requestOnce = async (remainingTimeoutMs) => {
|
|
5068
|
+
const requestOnce = async (remainingTimeoutMs, requestBody = body) => {
|
|
4452
5069
|
const res = await callApi({
|
|
4453
5070
|
apiBase: useGateway ? resolvedApiBase : legacyUrl,
|
|
4454
5071
|
apiKey,
|
|
4455
5072
|
path,
|
|
4456
5073
|
method: 'POST',
|
|
4457
|
-
body,
|
|
5074
|
+
body: requestBody,
|
|
4458
5075
|
workspaceId: effectiveWorkspaceId,
|
|
4459
5076
|
timeoutMs: remainingTimeoutMs,
|
|
4460
5077
|
});
|
|
@@ -4479,6 +5096,7 @@ async function handleVideoExtract(opts) {
|
|
|
4479
5096
|
};
|
|
4480
5097
|
|
|
4481
5098
|
let payload = await requestOnce(timeoutMs);
|
|
5099
|
+
let pollBody = buildVideoExtractStatusPollBody(body, payload);
|
|
4482
5100
|
|
|
4483
5101
|
if (opts.wait) {
|
|
4484
5102
|
const pollIntervalMs = resolvePollIntervalMs(opts);
|
|
@@ -4497,7 +5115,16 @@ async function handleVideoExtract(opts) {
|
|
|
4497
5115
|
|
|
4498
5116
|
emitInfo(opts, 'tracked-video-extract pending; polling for completion.');
|
|
4499
5117
|
await sleep(Math.min(pollIntervalMs, remainingMs));
|
|
4500
|
-
|
|
5118
|
+
if (!pollBody) {
|
|
5119
|
+
throw new CliError('Cannot poll URL analysis without a resolved video identifier.', {
|
|
5120
|
+
code: 'MISSING_RESOLVED_VIDEO_ID',
|
|
5121
|
+
exitCode: EXIT_CODES.SERVER,
|
|
5122
|
+
hint: 'Retry without --wait, then poll with the returned videoUid or platformVideoId.',
|
|
5123
|
+
details: truncateDetails(payload),
|
|
5124
|
+
});
|
|
5125
|
+
}
|
|
5126
|
+
payload = await requestOnce(Math.max(1000, deadline - Date.now()), pollBody);
|
|
5127
|
+
pollBody = buildVideoExtractStatusPollBody(body, payload);
|
|
4501
5128
|
}
|
|
4502
5129
|
}
|
|
4503
5130
|
|
|
@@ -4536,13 +5163,13 @@ async function handleVideoQueueAnalysis(opts) {
|
|
|
4536
5163
|
method: 'POST',
|
|
4537
5164
|
});
|
|
4538
5165
|
|
|
4539
|
-
const requestOnce = async (remainingTimeoutMs) => {
|
|
5166
|
+
const requestOnce = async (remainingTimeoutMs, requestBody = body) => {
|
|
4540
5167
|
const res = await callApi({
|
|
4541
5168
|
apiBase: useGateway ? resolvedApiBase : legacyUrl,
|
|
4542
5169
|
apiKey,
|
|
4543
5170
|
path,
|
|
4544
5171
|
method: 'POST',
|
|
4545
|
-
body,
|
|
5172
|
+
body: requestBody,
|
|
4546
5173
|
workspaceId: effectiveWorkspaceId,
|
|
4547
5174
|
timeoutMs: remainingTimeoutMs,
|
|
4548
5175
|
});
|
|
@@ -4567,6 +5194,7 @@ async function handleVideoQueueAnalysis(opts) {
|
|
|
4567
5194
|
};
|
|
4568
5195
|
|
|
4569
5196
|
let payload = await requestOnce(timeoutMs);
|
|
5197
|
+
let pollBody = buildVideoExtractStatusPollBody(body, payload);
|
|
4570
5198
|
|
|
4571
5199
|
if (opts.wait) {
|
|
4572
5200
|
const pollIntervalMs = resolvePollIntervalMs(opts);
|
|
@@ -4585,7 +5213,16 @@ async function handleVideoQueueAnalysis(opts) {
|
|
|
4585
5213
|
|
|
4586
5214
|
emitInfo(opts, 'tracked-video queue-analysis pending; polling for completion.');
|
|
4587
5215
|
await sleep(Math.min(pollIntervalMs, remainingMs));
|
|
4588
|
-
|
|
5216
|
+
if (!pollBody) {
|
|
5217
|
+
throw new CliError('Cannot poll URL analysis without a resolved video identifier.', {
|
|
5218
|
+
code: 'MISSING_RESOLVED_VIDEO_ID',
|
|
5219
|
+
exitCode: EXIT_CODES.SERVER,
|
|
5220
|
+
hint: 'Retry without --wait, then poll with the returned videoUid or platformVideoId.',
|
|
5221
|
+
details: truncateDetails(payload),
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5224
|
+
payload = await requestOnce(Math.max(1000, deadline - Date.now()), pollBody);
|
|
5225
|
+
pollBody = buildVideoExtractStatusPollBody(body, payload);
|
|
4589
5226
|
}
|
|
4590
5227
|
}
|
|
4591
5228
|
|
|
@@ -4819,6 +5456,7 @@ const tools = program.command('tools').description('Call edge functions directly
|
|
|
4819
5456
|
tools
|
|
4820
5457
|
.command('list')
|
|
4821
5458
|
.description('List built-in tool registry entries')
|
|
5459
|
+
.option('--category <name>', 'Filter tools by category')
|
|
4822
5460
|
.option('--json', 'Emit machine-readable output')
|
|
4823
5461
|
.option('--pretty', 'Pretty-print JSON')
|
|
4824
5462
|
.option('--verbose', 'Show error details')
|
|
@@ -4967,12 +5605,14 @@ const video = program.command('video').description('Tracked video extraction wor
|
|
|
4967
5605
|
|
|
4968
5606
|
video
|
|
4969
5607
|
.command('queue-analysis')
|
|
4970
|
-
.description('Queue video analysis for tracked videos
|
|
5608
|
+
.description('Queue video analysis for tracked videos, tracked search results, or ad hoc public URLs')
|
|
5609
|
+
.option('--url <url>', 'Public TikTok, Instagram, or YouTube video URL (requires --allow-untracked)')
|
|
4971
5610
|
.option('--video-id <id>', 'Tracked video identifier (video_uid first, then platform video id; not a tracking item id)')
|
|
4972
5611
|
.option('--search-result-id <id>', 'Tracked search result id for a ranked result row')
|
|
4973
5612
|
.option('--video-uid <id>', 'Canonical tracked video_uid')
|
|
4974
5613
|
.option('--platform-video-id <id>', 'Platform-native video id')
|
|
4975
5614
|
.option('--body <jsonOrFile>', 'JSON body or @payload.json for batch queueing')
|
|
5615
|
+
.option('--allow-untracked', 'Allow ad hoc public URL analysis for videos not already tracked')
|
|
4976
5616
|
.option('--wait', 'Poll until queued/completing analyses settle')
|
|
4977
5617
|
.option('--poll-interval <ms>', 'Polling interval in milliseconds when --wait is enabled')
|
|
4978
5618
|
.option('--api-base <url>', 'API base URL (default https://api.socialseal.co)')
|
|
@@ -4986,12 +5626,14 @@ video
|
|
|
4986
5626
|
|
|
4987
5627
|
video
|
|
4988
5628
|
.command('extract')
|
|
4989
|
-
.description('Resolve tracked videos/results into structured analysis plus reference assets')
|
|
5629
|
+
.description('Resolve tracked videos/results or ad hoc public URLs into structured analysis plus reference assets')
|
|
5630
|
+
.option('--url <url>', 'Public TikTok, Instagram, or YouTube video URL (requires --allow-untracked)')
|
|
4990
5631
|
.option('--video-id <id>', 'Tracked video identifier (video_uid first, then platform video id; not a tracking item id)')
|
|
4991
5632
|
.option('--search-result-id <id>', 'Tracked search result id for a ranked result row')
|
|
4992
5633
|
.option('--video-uid <id>', 'Canonical tracked video_uid')
|
|
4993
5634
|
.option('--platform-video-id <id>', 'Platform-native video id')
|
|
4994
5635
|
.option('--body <jsonOrFile>', 'JSON body or @payload.json for batch extraction')
|
|
5636
|
+
.option('--allow-untracked', 'Allow ad hoc public URL analysis for videos not already tracked')
|
|
4995
5637
|
.option('--ensure-analysis', 'Queue analysis when it is missing')
|
|
4996
5638
|
.option('--wait', 'Poll until queued/completing analyses settle')
|
|
4997
5639
|
.option('--poll-interval <ms>', 'Polling interval in milliseconds when --wait is enabled')
|