@socialseal/cli 0.1.6 → 0.1.7
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 +6 -0
- package/README.md +8 -1
- package/package.json +1 -1
- package/src/index.js +329 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.7 - 2026-03-20
|
|
6
|
+
- Add `socialseal data export-search-results` for CLI-first enriched ranked-search exports, including direct CSV download handling.
|
|
7
|
+
- Add `search_results_enriched` as an alias on `socialseal data export-report` to map to the ranked-search export template.
|
|
8
|
+
- Add `socialseal data export-options` to make available export workflows discoverable from the CLI.
|
|
9
|
+
- Improve export ergonomics with local report-type validation and instructive failure guidance for processing, failed, and expired-download states.
|
|
10
|
+
|
|
5
11
|
## 0.1.6 - 2026-03-19
|
|
6
12
|
- Fix runtime version reporting so `socialseal --version` reads from package metadata instead of a hardcoded source string.
|
|
7
13
|
- Fix `tracking` create request translation so `--workspace-id` is sent on the REST query path the backend uses for workspace binding.
|
package/README.md
CHANGED
|
@@ -56,12 +56,19 @@ Optional config file:
|
|
|
56
56
|
- `socialseal video extract --body @payload.json --out-dir ./video-assets`
|
|
57
57
|
|
|
58
58
|
- Data exports (provisional):
|
|
59
|
+
- `socialseal data export-options`
|
|
59
60
|
- `socialseal data export-tracking --group-id 123 --time-period 30d --workspace-id <uuid> --out out.csv`
|
|
61
|
+
- `socialseal data export-search-results --group-ids 123,124 --workspace-id <uuid> --out ranked.csv`
|
|
62
|
+
- `socialseal data export-report --report-type search_results_enriched --format csv --payload @payload.json --workspace-id <uuid> --out ranked.csv`
|
|
60
63
|
- `socialseal data export-report --report-type keyword_universe --format csv --payload @payload.json --out out.csv`
|
|
61
64
|
|
|
62
65
|
## Notes
|
|
63
|
-
- `export-report` and `
|
|
66
|
+
- `export-report`, `export_tracking_data`, and `export-data`-backed exports are provisional until CLI export specs are finalized.
|
|
64
67
|
- `tools list` ships a stable built-in registry of supported direct-call function targets. It is not live backend enumeration.
|
|
68
|
+
- `data export-search-results` maps to `export-data` template `tracking_ranked_videos_raw` and returns enriched ranked-search rows (search fields + video metadata + latest metrics + analysis). It downloads the signed CSV artifact when available.
|
|
69
|
+
- `data export-report --report-type search_results_enriched` is a compatibility alias to the same `export-data` template flow.
|
|
70
|
+
- `data export-report` now validates report types locally and shows the allowed list immediately; run `socialseal data export-options` when choosing between export flows.
|
|
71
|
+
- If an export returns metadata without a file URL (for example status `processing`), the CLI prints an explicit retry hint and returns the metadata JSON so automation can branch on status.
|
|
65
72
|
- `--timeout <ms>` controls HTTP request timeouts. Agent runs default to a 5-minute WebSocket inactivity timeout unless you set `--idle-timeout <ms>` (or the matching env/config value).
|
|
66
73
|
- `search-journey-run` supports CLI-managed async polling: `--async` starts backend async mode, polling is on by default, `--no-poll` returns the initial `runId`, and `--poll-interval <ms>` controls the status polling cadence.
|
|
67
74
|
- `video queue-analysis` wraps the tracked-video extraction backend in queue-only mode so you can queue one or many tracked videos without downloading assets first.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -27,6 +27,44 @@ const EXIT_CODES = {
|
|
|
27
27
|
SERVER: 5,
|
|
28
28
|
};
|
|
29
29
|
const HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']);
|
|
30
|
+
const REPORT_TYPE_SEARCH_RESULTS_ENRICHED = 'search_results_enriched';
|
|
31
|
+
const EXPORT_DATA_TEMPLATE_TRACKING_RANKED_VIDEOS_RAW = 'tracking_ranked_videos_raw';
|
|
32
|
+
const SUPPORTED_EXPORT_REPORT_TYPES = [
|
|
33
|
+
'keyword_universe',
|
|
34
|
+
'cluster_insights',
|
|
35
|
+
'creator_signatures',
|
|
36
|
+
'post_publish',
|
|
37
|
+
'quick_audit',
|
|
38
|
+
REPORT_TYPE_SEARCH_RESULTS_ENRICHED,
|
|
39
|
+
];
|
|
40
|
+
const EXPORT_OPTIONS = [
|
|
41
|
+
{
|
|
42
|
+
id: 'tracking_csv',
|
|
43
|
+
command: 'socialseal data export-tracking --group-id <id> --time-period <window>',
|
|
44
|
+
summary: 'Legacy tracking CSV export for a group or tracking item.',
|
|
45
|
+
formats: ['csv'],
|
|
46
|
+
required: ['workspace id', '--group-id or --item-id', '--time-period'],
|
|
47
|
+
bestFor: 'Quick tracking-table exports and backwards-compatible pipelines.',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'search_results_enriched',
|
|
51
|
+
command: 'socialseal data export-search-results --group-ids <id,id,...>',
|
|
52
|
+
summary: 'Enriched ranked search rows (search results + video + latest metrics + analysis).',
|
|
53
|
+
formats: ['csv'],
|
|
54
|
+
required: ['workspace id', '--group-ids'],
|
|
55
|
+
bestFor: 'SQL-like ranked-search datasets without using psql.',
|
|
56
|
+
alias: 'socialseal data export-report --report-type search_results_enriched --format csv --payload @payload.json',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'report_templates',
|
|
60
|
+
command: 'socialseal data export-report --report-type <type> --format <format> --payload @payload.json',
|
|
61
|
+
summary: 'Report-template exports via export-report.',
|
|
62
|
+
formats: ['csv', 'json', 'markdown', 'html', 'excel_data'],
|
|
63
|
+
required: ['payload JSON'],
|
|
64
|
+
bestFor: 'Keyword universe, clusters, creators, post-publish timeline, and quick-audit exports.',
|
|
65
|
+
reportTypes: SUPPORTED_EXPORT_REPORT_TYPES,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
30
68
|
const KNOWN_TOOLS = [
|
|
31
69
|
{ name: 'agent-tool-jobs', category: 'agent', description: 'Poll queued agent-backed tool jobs and fetch their results.' },
|
|
32
70
|
{ name: 'deep-exploration-runs', category: 'agent', description: 'Read or persist deep exploration render runs.' },
|
|
@@ -54,6 +92,16 @@ const KNOWN_TOOLS = [
|
|
|
54
92
|
notes: 'Refreshes brand metrics for brands/workspaces. It does not refresh a tracking group by UUID.',
|
|
55
93
|
},
|
|
56
94
|
{ name: 'export-report', category: 'export', description: 'Generate report exports (csv/json/markdown/html/excel_data).' },
|
|
95
|
+
{
|
|
96
|
+
name: 'export-data',
|
|
97
|
+
category: 'export',
|
|
98
|
+
description: 'Run raw workspace-scoped export templates with signed-URL artifacts.',
|
|
99
|
+
objectType: 'workspace_export',
|
|
100
|
+
transport: 'post_edge_function',
|
|
101
|
+
workspaceScoped: true,
|
|
102
|
+
knownLocalDevState: 'disabled_by_default',
|
|
103
|
+
notes: 'Includes template `tracking_ranked_videos_raw` for ranked search results with video + metrics + analysis enrichment.',
|
|
104
|
+
},
|
|
57
105
|
{
|
|
58
106
|
name: 'export_tracking_data',
|
|
59
107
|
category: 'export',
|
|
@@ -691,6 +739,88 @@ function coercePositiveInteger(value, label) {
|
|
|
691
739
|
});
|
|
692
740
|
}
|
|
693
741
|
|
|
742
|
+
function normalizePositiveIntegerList(value, label, { max } = {}) {
|
|
743
|
+
if (value === undefined || value === null || value === '') return [];
|
|
744
|
+
const entries = Array.isArray(value)
|
|
745
|
+
? value
|
|
746
|
+
: String(value)
|
|
747
|
+
.split(',')
|
|
748
|
+
.map((entry) => entry.trim())
|
|
749
|
+
.filter(Boolean);
|
|
750
|
+
const parsed = entries.map((entry, index) => {
|
|
751
|
+
const normalized = coercePositiveInteger(entry, `${label}[${index}]`);
|
|
752
|
+
if (!normalized) {
|
|
753
|
+
throw new CliError(`Invalid ${label}[${index}] value.`, {
|
|
754
|
+
code: 'INVALID_ARGUMENT',
|
|
755
|
+
exitCode: EXIT_CODES.USAGE,
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
return normalized;
|
|
759
|
+
});
|
|
760
|
+
const deduped = Array.from(new Set(parsed));
|
|
761
|
+
if (max && deduped.length > max) {
|
|
762
|
+
throw new CliError(`Too many ${label} values: received ${deduped.length}, max is ${max}.`, {
|
|
763
|
+
code: 'INVALID_ARGUMENT',
|
|
764
|
+
exitCode: EXIT_CODES.USAGE,
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
return deduped;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function normalizeIsoDateTime(value, label) {
|
|
771
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
772
|
+
if (typeof value !== 'string') {
|
|
773
|
+
throw new CliError(`Invalid ${label}: expected an ISO datetime string.`, {
|
|
774
|
+
code: 'INVALID_ARGUMENT',
|
|
775
|
+
exitCode: EXIT_CODES.USAGE,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
const trimmed = value.trim();
|
|
779
|
+
const epoch = Date.parse(trimmed);
|
|
780
|
+
if (Number.isNaN(epoch)) {
|
|
781
|
+
throw new CliError(`Invalid ${label}: expected an ISO datetime string.`, {
|
|
782
|
+
code: 'INVALID_ARGUMENT',
|
|
783
|
+
exitCode: EXIT_CODES.USAGE,
|
|
784
|
+
details: value,
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
return new Date(epoch).toISOString();
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function buildSearchResultsEnrichedExportPayload(rawPayload, workspaceId) {
|
|
791
|
+
const payload = isJsonObject(rawPayload) ? rawPayload : {};
|
|
792
|
+
const groupIds = normalizePositiveIntegerList(
|
|
793
|
+
firstDefined(payload, ['groupIds', 'group_ids']),
|
|
794
|
+
'groupIds',
|
|
795
|
+
{ max: 100 },
|
|
796
|
+
);
|
|
797
|
+
if (groupIds.length === 0) {
|
|
798
|
+
throw new CliError('search_results_enriched export requires at least one group id.', {
|
|
799
|
+
code: 'MISSING_ARGUMENT',
|
|
800
|
+
exitCode: EXIT_CODES.USAGE,
|
|
801
|
+
hint: 'Provide --group-ids for `data export-search-results`, or include groupIds in --payload for `data export-report`.',
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const trackingItemIds = normalizePositiveIntegerList(
|
|
806
|
+
firstDefined(payload, ['trackingItemIds', 'tracking_item_ids']),
|
|
807
|
+
'trackingItemIds',
|
|
808
|
+
{ max: 1000 },
|
|
809
|
+
);
|
|
810
|
+
const dateFrom = normalizeIsoDateTime(firstDefined(payload, ['dateFrom', 'date_from']), 'dateFrom');
|
|
811
|
+
const dateTo = normalizeIsoDateTime(firstDefined(payload, ['dateTo', 'date_to']), 'dateTo');
|
|
812
|
+
const filename = trimString(firstDefined(payload, ['filename'])) || undefined;
|
|
813
|
+
|
|
814
|
+
return stripUndefinedEntries({
|
|
815
|
+
workspaceId,
|
|
816
|
+
groupIds,
|
|
817
|
+
trackingItemIds: trackingItemIds.length > 0 ? trackingItemIds : undefined,
|
|
818
|
+
dateFrom,
|
|
819
|
+
dateTo,
|
|
820
|
+
filename,
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
694
824
|
function buildPathWithQuery(basePath, query) {
|
|
695
825
|
const params = new URLSearchParams();
|
|
696
826
|
for (const [key, rawValue] of Object.entries(query || {})) {
|
|
@@ -1695,7 +1825,9 @@ function mapStatusToExitCode(status) {
|
|
|
1695
1825
|
}
|
|
1696
1826
|
|
|
1697
1827
|
function isLocallyDisabledByDefaultFunction(functionName) {
|
|
1698
|
-
return functionName === 'group-management'
|
|
1828
|
+
return functionName === 'group-management'
|
|
1829
|
+
|| functionName === 'export_tracking_data'
|
|
1830
|
+
|| functionName === 'export-data';
|
|
1699
1831
|
}
|
|
1700
1832
|
|
|
1701
1833
|
function buildStatusHint(status, context = {}) {
|
|
@@ -1812,6 +1944,18 @@ function requireApiKey(opts, config) {
|
|
|
1812
1944
|
return apiKey;
|
|
1813
1945
|
}
|
|
1814
1946
|
|
|
1947
|
+
function assertSupportedReportType(reportType) {
|
|
1948
|
+
const normalized = trimString(reportType);
|
|
1949
|
+
if (SUPPORTED_EXPORT_REPORT_TYPES.includes(normalized)) {
|
|
1950
|
+
return normalized;
|
|
1951
|
+
}
|
|
1952
|
+
throw new CliError(`Unsupported report type: ${reportType}`, {
|
|
1953
|
+
code: 'INVALID_ARGUMENT',
|
|
1954
|
+
exitCode: EXIT_CODES.USAGE,
|
|
1955
|
+
hint: `Use one of: ${SUPPORTED_EXPORT_REPORT_TYPES.join(', ')}. Run \`socialseal data export-options\` to choose the right export flow.`,
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1815
1959
|
function resolveApiTarget({ apiBase, legacyUrl }) {
|
|
1816
1960
|
const resolvedApiBase = apiBase || (!legacyUrl ? DEFAULT_API_BASE : null);
|
|
1817
1961
|
if (!resolvedApiBase && !legacyUrl) {
|
|
@@ -2509,6 +2653,24 @@ async function handleDataExportTracking(opts) {
|
|
|
2509
2653
|
}
|
|
2510
2654
|
|
|
2511
2655
|
async function handleDataExportReport(opts) {
|
|
2656
|
+
const reportType = assertSupportedReportType(opts.reportType);
|
|
2657
|
+
|
|
2658
|
+
if (reportType === REPORT_TYPE_SEARCH_RESULTS_ENRICHED) {
|
|
2659
|
+
if (opts.format !== 'csv') {
|
|
2660
|
+
throw new CliError('search_results_enriched supports only csv format.', {
|
|
2661
|
+
code: 'INVALID_ARGUMENT',
|
|
2662
|
+
exitCode: EXIT_CODES.USAGE,
|
|
2663
|
+
hint: 'Use --format csv.',
|
|
2664
|
+
});
|
|
2665
|
+
}
|
|
2666
|
+
const payload = ensureJsonObject(parseJsonInput(opts.payload, { label: 'payload' }), 'payload');
|
|
2667
|
+
await handleDataExportSearchResults({
|
|
2668
|
+
...opts,
|
|
2669
|
+
__rawPayload: payload,
|
|
2670
|
+
});
|
|
2671
|
+
return;
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2512
2674
|
const config = loadConfig();
|
|
2513
2675
|
const apiKey = requireApiKey(opts, config);
|
|
2514
2676
|
const apiBase = resolveApiBase(opts, config);
|
|
@@ -2525,7 +2687,7 @@ async function handleDataExportReport(opts) {
|
|
|
2525
2687
|
path: useGateway ? '/cli/tools/export-report' : '/functions/v1/export-report',
|
|
2526
2688
|
method: 'POST',
|
|
2527
2689
|
body: {
|
|
2528
|
-
reportType
|
|
2690
|
+
reportType,
|
|
2529
2691
|
format: opts.format,
|
|
2530
2692
|
payload,
|
|
2531
2693
|
},
|
|
@@ -2571,6 +2733,142 @@ async function handleDataExportReport(opts) {
|
|
|
2571
2733
|
process.stdout.write(JSON.stringify(json, null, opts.pretty ? 2 : 0) + '\n');
|
|
2572
2734
|
}
|
|
2573
2735
|
|
|
2736
|
+
async function handleDataExportSearchResults(opts) {
|
|
2737
|
+
const config = loadConfig();
|
|
2738
|
+
const apiKey = requireApiKey(opts, config);
|
|
2739
|
+
const apiBase = resolveApiBase(opts, config);
|
|
2740
|
+
const supabaseUrl = resolveLegacyUrl(resolveSupabaseUrl(opts, config), 'SOCIALSEAL_SUPABASE_URL');
|
|
2741
|
+
const { resolvedApiBase, legacyUrl, useGateway } = resolveApiTarget({ apiBase, legacyUrl: supabaseUrl });
|
|
2742
|
+
const timeoutMs = resolveTimeoutMs(opts, config);
|
|
2743
|
+
const { workspaceId: resolvedWorkspaceId, source: workspaceSource } = resolveWorkspaceSelection(opts, config);
|
|
2744
|
+
|
|
2745
|
+
const rawPayload = opts.__rawPayload ?? stripUndefinedEntries({
|
|
2746
|
+
groupIds: normalizePositiveIntegerList(opts.groupIds, 'groupIds', { max: 100 }),
|
|
2747
|
+
trackingItemIds: normalizePositiveIntegerList(opts.trackingItemIds, 'trackingItemIds', { max: 1000 }),
|
|
2748
|
+
dateFrom: opts.dateFrom,
|
|
2749
|
+
dateTo: opts.dateTo,
|
|
2750
|
+
filename: opts.filename,
|
|
2751
|
+
});
|
|
2752
|
+
|
|
2753
|
+
const payloadWorkspaceId = resolvePayloadWorkspaceId(rawPayload, null);
|
|
2754
|
+
const effectiveWorkspaceId = requireWorkspaceSelection(payloadWorkspaceId || resolvedWorkspaceId, {
|
|
2755
|
+
label: 'Search results enriched export',
|
|
2756
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, or configure a default workspace before exporting.',
|
|
2757
|
+
});
|
|
2758
|
+
const effectiveWorkspaceSource = payloadWorkspaceId ? 'body' : workspaceSource;
|
|
2759
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2760
|
+
workspaceId: effectiveWorkspaceId,
|
|
2761
|
+
source: effectiveWorkspaceSource,
|
|
2762
|
+
label: 'search_results_enriched export',
|
|
2763
|
+
});
|
|
2764
|
+
|
|
2765
|
+
const normalizedPayload = buildSearchResultsEnrichedExportPayload(rawPayload, effectiveWorkspaceId);
|
|
2766
|
+
const requestedFilename = trimString(normalizedPayload.filename) || undefined;
|
|
2767
|
+
delete normalizedPayload.filename;
|
|
2768
|
+
|
|
2769
|
+
const exportResponse = await callApi({
|
|
2770
|
+
apiBase: useGateway ? resolvedApiBase : legacyUrl,
|
|
2771
|
+
apiKey,
|
|
2772
|
+
path: useGateway ? '/cli/tools/export-data' : '/functions/v1/export-data',
|
|
2773
|
+
method: 'POST',
|
|
2774
|
+
body: {
|
|
2775
|
+
template: EXPORT_DATA_TEMPLATE_TRACKING_RANKED_VIDEOS_RAW,
|
|
2776
|
+
format: 'csv',
|
|
2777
|
+
payload: normalizedPayload,
|
|
2778
|
+
filename: requestedFilename,
|
|
2779
|
+
},
|
|
2780
|
+
workspaceId: effectiveWorkspaceId,
|
|
2781
|
+
timeoutMs,
|
|
2782
|
+
});
|
|
2783
|
+
|
|
2784
|
+
if (!exportResponse.ok) {
|
|
2785
|
+
throw await buildHttpError(exportResponse, {
|
|
2786
|
+
label: 'Search results enriched export',
|
|
2787
|
+
functionName: 'export-data',
|
|
2788
|
+
method: 'POST',
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
const responseJson = await exportResponse.json();
|
|
2793
|
+
const metadata = isJsonObject(responseJson) && isJsonObject(responseJson.metadata)
|
|
2794
|
+
? responseJson.metadata
|
|
2795
|
+
: null;
|
|
2796
|
+
const fileUrl = trimString(metadata?.file_url || '');
|
|
2797
|
+
const status = trimString(metadata?.status || '').toLowerCase();
|
|
2798
|
+
|
|
2799
|
+
if (!fileUrl) {
|
|
2800
|
+
if (status === 'processing') {
|
|
2801
|
+
process.stderr.write('[socialseal] Export is still processing. Re-run the same command shortly; the backend dedupes and returns the finished artifact when ready.\n');
|
|
2802
|
+
} else if (status === 'failed') {
|
|
2803
|
+
process.stderr.write('[socialseal] Export status is failed. Inspect the JSON metadata for details, then retry with corrected filters.\n');
|
|
2804
|
+
} else {
|
|
2805
|
+
process.stderr.write('[socialseal] Export did not include a file URL yet. Inspect the JSON metadata and retry if needed.\n');
|
|
2806
|
+
}
|
|
2807
|
+
emitJsonOutput(responseJson, opts.pretty);
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
const artifactResponse = await fetchWithTimeout(fileUrl, {
|
|
2812
|
+
method: 'GET',
|
|
2813
|
+
headers: { Accept: '*/*' },
|
|
2814
|
+
}, timeoutMs);
|
|
2815
|
+
|
|
2816
|
+
if (!artifactResponse.ok) {
|
|
2817
|
+
throw await buildHttpError(artifactResponse, {
|
|
2818
|
+
label: 'Search results enriched artifact download',
|
|
2819
|
+
method: 'GET',
|
|
2820
|
+
hint: 'The signed file URL may be expired or inaccessible. Re-run the export command to mint a fresh URL.',
|
|
2821
|
+
});
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
if (!artifactResponse.body) {
|
|
2825
|
+
throw new CliError('Export artifact response contained no body.', {
|
|
2826
|
+
code: 'EMPTY_RESPONSE',
|
|
2827
|
+
exitCode: EXIT_CODES.SERVER,
|
|
2828
|
+
});
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
const outPath = opts.stdout
|
|
2832
|
+
? null
|
|
2833
|
+
: (opts.out || trimString(metadata?.filename || '') || 'tracking-ranked-videos.csv');
|
|
2834
|
+
if (outPath) {
|
|
2835
|
+
await pipeline(artifactResponse.body, fs.createWriteStream(outPath));
|
|
2836
|
+
process.stderr.write(`[socialseal] Export written to ${outPath}\n`);
|
|
2837
|
+
} else {
|
|
2838
|
+
await pipeline(artifactResponse.body, process.stdout);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
function handleDataExportOptions(opts) {
|
|
2843
|
+
const payload = {
|
|
2844
|
+
exports: EXPORT_OPTIONS,
|
|
2845
|
+
supportedReportTypes: SUPPORTED_EXPORT_REPORT_TYPES,
|
|
2846
|
+
note: 'Use this list to choose the right export surface before running data export commands.',
|
|
2847
|
+
};
|
|
2848
|
+
|
|
2849
|
+
if (opts.json) {
|
|
2850
|
+
emitJsonOutput(payload, opts.pretty);
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
process.stdout.write('[socialseal] Available export options\n');
|
|
2855
|
+
process.stdout.write('[socialseal] Choose a flow based on dataset shape, not endpoint name.\n\n');
|
|
2856
|
+
for (const option of EXPORT_OPTIONS) {
|
|
2857
|
+
process.stdout.write(`- ${option.id}: ${option.summary}\n`);
|
|
2858
|
+
process.stdout.write(` command: ${option.command}\n`);
|
|
2859
|
+
process.stdout.write(` formats: ${option.formats.join(', ')}\n`);
|
|
2860
|
+
process.stdout.write(` required: ${option.required.join(', ')}\n`);
|
|
2861
|
+
process.stdout.write(` best for: ${option.bestFor}\n`);
|
|
2862
|
+
if (option.alias) {
|
|
2863
|
+
process.stdout.write(` alias: ${option.alias}\n`);
|
|
2864
|
+
}
|
|
2865
|
+
if (Array.isArray(option.reportTypes)) {
|
|
2866
|
+
process.stdout.write(` report types: ${option.reportTypes.join(', ')}\n`);
|
|
2867
|
+
}
|
|
2868
|
+
process.stdout.write('\n');
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2574
2872
|
async function handleVideoExtract(opts) {
|
|
2575
2873
|
const config = loadConfig();
|
|
2576
2874
|
const apiKey = requireApiKey(opts, config);
|
|
@@ -2902,7 +3200,7 @@ if (typeof program.showHelpAfterError === 'function') {
|
|
|
2902
3200
|
if (typeof program.showSuggestionAfterError === 'function') {
|
|
2903
3201
|
program.showSuggestionAfterError(true);
|
|
2904
3202
|
}
|
|
2905
|
-
program.addHelpText('after', `\nExamples:\n socialseal workspace list\n socialseal workspace use <workspace-id>\n socialseal agent run --message \"ping\"\n socialseal tools list\n socialseal tools call --function <tool> --body @payload.json\n socialseal tools call --function search-journey-run --body @payload.json --async --workspace-id <uuid>\n socialseal video queue-analysis --video-id 734829384 --workspace-id <uuid>\n socialseal video extract --video-id 734829384 --wait --out-dir ./video-assets\n socialseal data export-tracking --group-id 123 --time-period 30d\n`);
|
|
3203
|
+
program.addHelpText('after', `\nExamples:\n socialseal workspace list\n socialseal workspace use <workspace-id>\n socialseal agent run --message \"ping\"\n socialseal tools list\n socialseal tools call --function <tool> --body @payload.json\n socialseal tools call --function search-journey-run --body @payload.json --async --workspace-id <uuid>\n socialseal video queue-analysis --video-id 734829384 --workspace-id <uuid>\n socialseal video extract --video-id 734829384 --wait --out-dir ./video-assets\n socialseal data export-options\n socialseal data export-tracking --group-id 123 --time-period 30d\n socialseal data export-search-results --group-ids 123,124 --workspace-id <uuid> --out ranked.csv\n`);
|
|
2906
3204
|
|
|
2907
3205
|
program
|
|
2908
3206
|
.command('agent')
|
|
@@ -2994,6 +3292,14 @@ tools
|
|
|
2994
3292
|
|
|
2995
3293
|
const data = program.command('data').description('Data exports (provisional)');
|
|
2996
3294
|
|
|
3295
|
+
data
|
|
3296
|
+
.command('export-options')
|
|
3297
|
+
.description('List export flows, when to use each, and required inputs')
|
|
3298
|
+
.option('--json', 'Emit machine-readable output')
|
|
3299
|
+
.option('--pretty', 'Pretty-print JSON')
|
|
3300
|
+
.option('--verbose', 'Show error details')
|
|
3301
|
+
.action((opts) => runCommand(handleDataExportOptions, opts));
|
|
3302
|
+
|
|
2997
3303
|
data
|
|
2998
3304
|
.command('export-tracking')
|
|
2999
3305
|
.description('Export tracking data as CSV')
|
|
@@ -3010,10 +3316,29 @@ data
|
|
|
3010
3316
|
.option('--verbose', 'Show error details')
|
|
3011
3317
|
.action((opts) => runCommand(handleDataExportTracking, opts));
|
|
3012
3318
|
|
|
3319
|
+
data
|
|
3320
|
+
.command('export-search-results')
|
|
3321
|
+
.description('Export enriched ranked search results (search_results + videos + latest metrics + analysis) as CSV')
|
|
3322
|
+
.requiredOption('--group-ids <ids>', 'Comma-separated tracking group ids (for example: 123,124,125)')
|
|
3323
|
+
.option('--tracking-item-ids <ids>', 'Optional comma-separated tracking item ids')
|
|
3324
|
+
.option('--date-from <iso>', 'Optional ISO datetime lower bound (inclusive)')
|
|
3325
|
+
.option('--date-to <iso>', 'Optional ISO datetime upper bound (inclusive)')
|
|
3326
|
+
.option('--filename <name>', 'Optional export filename stem (without extension)')
|
|
3327
|
+
.option('--out <path>', 'Output file path')
|
|
3328
|
+
.option('--stdout', 'Write to stdout')
|
|
3329
|
+
.option('--api-base <url>', 'API base URL (default https://api.socialseal.co)')
|
|
3330
|
+
.option('--api-key <key>', 'CLI API key')
|
|
3331
|
+
.option('--workspace-id <id>', 'Workspace id (for scoped keys)')
|
|
3332
|
+
.option('--pretty', 'Pretty-print JSON metadata when no file is ready')
|
|
3333
|
+
.option('--json', 'Emit machine-readable errors')
|
|
3334
|
+
.option('--timeout <ms>', 'Request timeout in milliseconds')
|
|
3335
|
+
.option('--verbose', 'Show error details')
|
|
3336
|
+
.action((opts) => runCommand(handleDataExportSearchResults, opts));
|
|
3337
|
+
|
|
3013
3338
|
data
|
|
3014
3339
|
.command('export-report')
|
|
3015
3340
|
.description('Export report data via export-report (provisional)')
|
|
3016
|
-
.requiredOption('--report-type <type>', 'keyword_universe|cluster_insights|creator_signatures|post_publish|quick_audit')
|
|
3341
|
+
.requiredOption('--report-type <type>', 'keyword_universe|cluster_insights|creator_signatures|post_publish|quick_audit|search_results_enriched')
|
|
3017
3342
|
.option('--format <format>', 'csv|json|markdown|html|excel_data', 'csv')
|
|
3018
3343
|
.requiredOption('--payload <jsonOrFile>', 'Payload JSON or @file.json')
|
|
3019
3344
|
.option('--out <path>', 'Output file path')
|