@socialseal/cli 0.1.5 → 0.1.6
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 +8 -0
- package/README.md +7 -4
- package/package.json +1 -1
- package/src/index.js +182 -24
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.6 - 2026-03-19
|
|
6
|
+
- Fix runtime version reporting so `socialseal --version` reads from package metadata instead of a hardcoded source string.
|
|
7
|
+
- Fix `tracking` create request translation so `--workspace-id` is sent on the REST query path the backend uses for workspace binding.
|
|
8
|
+
- Improve tracked-video extraction failure messages by avoiding `[object Object]` item errors and returning explicit guidance when `videoId` is actually a search-result id or tracking item id.
|
|
9
|
+
- Fail fast for `group-management` and `export_tracking_data` when no workspace is selected, instead of silently relying on backend personal-workspace fallback.
|
|
10
|
+
- Warn when `tracking create` runs without a workspace and when short numeric `--video-id` values look like internal row ids.
|
|
11
|
+
- Clarify in workspace discovery output and docs that `workspace_id` and `brand_id` are different identifiers.
|
|
12
|
+
|
|
5
13
|
## 0.1.5 - 2026-03-19
|
|
6
14
|
- Add first-class tracked-video workflows with `video queue-analysis` and `video extract`.
|
|
7
15
|
- Make `--video-id` the primary ergonomic selector for tracked-video analysis and asset extraction, while keeping `--search-result-id` as a fallback selector.
|
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ 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-tracking --group-id 123 --time-period 30d --out out.csv`
|
|
59
|
+
- `socialseal data export-tracking --group-id 123 --time-period 30d --workspace-id <uuid> --out out.csv`
|
|
60
60
|
- `socialseal data export-report --report-type keyword_universe --format csv --payload @payload.json --out out.csv`
|
|
61
61
|
|
|
62
62
|
## Notes
|
|
@@ -66,11 +66,14 @@ Optional config file:
|
|
|
66
66
|
- `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
67
|
- `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.
|
|
68
68
|
- `video extract` wraps the same backend in extraction mode and returns a normalized JSON payload with resolved tracking context, structured analysis, thumbnail/frame assets, and optional local downloads under `--out-dir`.
|
|
69
|
-
- `--video-id` is the primary ergonomic selector for video workflows. The backend tries it as `video_uid` first, then as platform video id. `--search-result-id` remains available when you are starting from a specific tracked rank row.
|
|
69
|
+
- `--video-id` is the primary ergonomic selector for video workflows. The backend tries it as `video_uid` first, then as platform video id. It does not accept tracking item ids. `--search-result-id` remains available when you are starting from a specific tracked rank row.
|
|
70
|
+
- `group-management` and `export_tracking_data` now fail fast when no workspace is selected, instead of letting the backend silently fall back to the personal workspace.
|
|
71
|
+
- `tracking create` without a workspace now prints a warning that the backend may create a personal/null-scope item.
|
|
72
|
+
- Short numeric `--video-id` inputs now print a warning that they may be internal row ids and that `--search-result-id` is often the intended selector.
|
|
70
73
|
- `socialseal agent run` now defaults to a fresh conversation. The CLI prints a continuation token to `stderr`; pass it back with `--continue <token>` to resume the same agent conversation explicitly.
|
|
71
|
-
- Effective workspace precedence is: `--workspace-id` → `SOCIALSEAL_WORKSPACE_ID` → config `workspaceId`
|
|
74
|
+
- Effective workspace precedence is: `--workspace-id` → `SOCIALSEAL_WORKSPACE_ID` → config `workspaceId`. For commands that are easy to misuse (`group-management`, `export_tracking_data`, tracked-video workflows), the CLI now requires an explicit or preconfigured workspace instead of relying on backend fallback.
|
|
72
75
|
- `socialseal workspace use ...` writes a local default workspace into `~/.config/socialseal/config.json`, which the CLI reuses for `agent`, `tools`, and `data` commands.
|
|
73
|
-
- `socialseal workspace list` discovers the workspaces accessible to the current CLI key
|
|
76
|
+
- `socialseal workspace list` discovers the workspaces accessible to the current CLI key, marks the active/suggested default, and reminds you that `workspace_id` and `brand_id` are different identifiers.
|
|
74
77
|
- If a scoped CLI key cannot safely infer a workspace, `agent run` now fails closed and tells you to set `--workspace-id` or configure a local default first.
|
|
75
78
|
|
|
76
79
|
## Errors and exit codes
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -16,6 +16,7 @@ const DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
|
16
16
|
const DEFAULT_FRAME_COUNT = 3;
|
|
17
17
|
const MAX_TIMEOUT_MS = 900000;
|
|
18
18
|
const LEGACY_ENABLED = process.env.SOCIALSEAL_ENABLE_LEGACY === '1';
|
|
19
|
+
const CLI_VERSION = loadRuntimeVersion();
|
|
19
20
|
const STATIC_TOOL_REGISTRY_NOTE = 'This registry is shipped with the CLI for stable discovery. It is not live backend enumeration, so environment-specific availability can drift.';
|
|
20
21
|
const EXIT_CODES = {
|
|
21
22
|
OK: 0,
|
|
@@ -61,7 +62,7 @@ const KNOWN_TOOLS = [
|
|
|
61
62
|
transport: 'post_edge_function',
|
|
62
63
|
workspaceScoped: true,
|
|
63
64
|
knownLocalDevState: 'disabled_by_default',
|
|
64
|
-
notes: 'group_id expects a numeric tracking_group id, not a brand_group UUID.',
|
|
65
|
+
notes: 'group_id expects a numeric tracking_group id, not a brand_group UUID. Always pass a workspace id or configure a default workspace so the export does not silently target the personal workspace.',
|
|
65
66
|
},
|
|
66
67
|
{
|
|
67
68
|
name: 'tracked-video-extract',
|
|
@@ -71,7 +72,7 @@ const KNOWN_TOOLS = [
|
|
|
71
72
|
transport: 'post_edge_function',
|
|
72
73
|
workspaceScoped: true,
|
|
73
74
|
knownLocalDevState: 'enabled',
|
|
74
|
-
notes: 'Accepts videoId/videoUid/platformVideoId/searchResultId items;
|
|
75
|
+
notes: 'Accepts videoId/videoUid/platformVideoId/searchResultId items; videoId means video_uid or platform-native video id, not a tracking item id.',
|
|
75
76
|
},
|
|
76
77
|
{ name: 'douyin-geo-api', category: 'search', description: 'Query Douyin search and geo data.' },
|
|
77
78
|
{ name: 'google-ai-search', category: 'search', description: 'Run Google AI search queries and fetch result snapshots.' },
|
|
@@ -88,7 +89,7 @@ const KNOWN_TOOLS = [
|
|
|
88
89
|
workspaceScoped: true,
|
|
89
90
|
knownLocalDevState: 'disabled_by_default',
|
|
90
91
|
actionAliases: ['list', 'get', 'create', 'update', 'delete', 'refresh', 'list_items', 'add_item', 'group_add_item', 'add_items', 'group_add_items', 'remove_item', 'group_remove_item'],
|
|
91
|
-
notes: 'REST-style surface under /groups. `add_item`/`group_add_item` accepts an existing `item_id`; `add_items`/`group_add_items` accepts `item_ids` or item payloads for bulk membership adds.',
|
|
92
|
+
notes: 'REST-style surface under /groups. `add_item`/`group_add_item` accepts an existing `item_id`; `add_items`/`group_add_items` accepts `item_ids` or item payloads for bulk membership adds. Always pass a workspace id or configure a default workspace so the backend does not fall back to the personal workspace.',
|
|
92
93
|
},
|
|
93
94
|
{
|
|
94
95
|
name: 'tracking',
|
|
@@ -123,6 +124,26 @@ function getConfigPath() {
|
|
|
123
124
|
return process.env.SOCIALSEAL_CONFIG || DEFAULT_CONFIG_PATH;
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
function loadRuntimeVersion() {
|
|
128
|
+
const envVersion = typeof process.env.npm_package_version === 'string'
|
|
129
|
+
? process.env.npm_package_version.trim()
|
|
130
|
+
: '';
|
|
131
|
+
if (envVersion) return envVersion;
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const packageJsonPath = new URL('../package.json', import.meta.url);
|
|
135
|
+
const raw = fs.readFileSync(packageJsonPath, 'utf8');
|
|
136
|
+
const parsed = JSON.parse(raw);
|
|
137
|
+
if (typeof parsed?.version === 'string' && parsed.version.trim().length > 0) {
|
|
138
|
+
return parsed.version.trim();
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
// fall through to the safe fallback below
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return '0.0.0';
|
|
145
|
+
}
|
|
146
|
+
|
|
126
147
|
function loadConfig() {
|
|
127
148
|
const configPath = getConfigPath();
|
|
128
149
|
try {
|
|
@@ -424,6 +445,7 @@ function buildVideoExtractBody(opts, workspaceId) {
|
|
|
424
445
|
throw new CliError('Provide --body or one of --video-id, --video-uid, --platform-video-id, or --search-result-id.', {
|
|
425
446
|
code: 'MISSING_ARGUMENT',
|
|
426
447
|
exitCode: EXIT_CODES.USAGE,
|
|
448
|
+
hint: '--video-id accepts a video_uid or platform video id. It does not accept tracking item ids.',
|
|
427
449
|
});
|
|
428
450
|
}
|
|
429
451
|
|
|
@@ -933,7 +955,7 @@ function translateTrackingAction(payload, workspaceId) {
|
|
|
933
955
|
if (!action) {
|
|
934
956
|
return {
|
|
935
957
|
method: 'POST',
|
|
936
|
-
pathSuffix: '',
|
|
958
|
+
pathSuffix: buildPathWithQuery('', { workspace_id: workspaceId || undefined }),
|
|
937
959
|
body: stripUndefinedEntries({
|
|
938
960
|
name: payload.name,
|
|
939
961
|
track_type: payload.track_type,
|
|
@@ -1013,7 +1035,7 @@ function translateTrackingAction(payload, workspaceId) {
|
|
|
1013
1035
|
if (action === 'create' || action === 'item_create') {
|
|
1014
1036
|
return {
|
|
1015
1037
|
method: 'POST',
|
|
1016
|
-
pathSuffix: '',
|
|
1038
|
+
pathSuffix: buildPathWithQuery('', { workspace_id: workspaceId || undefined }),
|
|
1017
1039
|
body: stripUndefinedEntries({
|
|
1018
1040
|
name: payload.name,
|
|
1019
1041
|
track_type: payload.track_type,
|
|
@@ -1480,6 +1502,61 @@ function emitWorkspaceContext(opts, { workspaceId, source, functionName, method
|
|
|
1480
1502
|
);
|
|
1481
1503
|
}
|
|
1482
1504
|
|
|
1505
|
+
function describeWorkspaceSource(source) {
|
|
1506
|
+
switch (source) {
|
|
1507
|
+
case 'flag':
|
|
1508
|
+
return '--workspace-id';
|
|
1509
|
+
case 'env':
|
|
1510
|
+
return 'SOCIALSEAL_WORKSPACE_ID';
|
|
1511
|
+
case 'config':
|
|
1512
|
+
return 'the saved default workspace';
|
|
1513
|
+
case 'body':
|
|
1514
|
+
return 'the request body';
|
|
1515
|
+
default:
|
|
1516
|
+
return 'implicit selection';
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
function emitWorkspaceSelectionNotice(opts, { workspaceId, source, label }) {
|
|
1521
|
+
if (!workspaceId || !source || source === 'flag' || source === 'body') return;
|
|
1522
|
+
process.stderr.write(
|
|
1523
|
+
`[socialseal] Using workspace ${workspaceId} from ${describeWorkspaceSource(source)} for ${label}. Pass --workspace-id to override.\n`,
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
function requireWorkspaceSelection(workspaceId, { label, hint }) {
|
|
1528
|
+
if (workspaceId) return workspaceId;
|
|
1529
|
+
throw new CliError(`${label} requires a workspace id.`, {
|
|
1530
|
+
code: 'WORKSPACE_REQUIRED',
|
|
1531
|
+
exitCode: EXIT_CODES.USAGE,
|
|
1532
|
+
hint,
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function emitTrackingCreateScopeWarning(action, workspaceId) {
|
|
1537
|
+
if (action !== 'create' || workspaceId) return;
|
|
1538
|
+
process.stderr.write(
|
|
1539
|
+
'[socialseal] tracking create is running without a workspace id. The backend may create a personal/null-scope item that is not attached to a workspace or group.\n',
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
function looksLikeShortNumericVideoId(value) {
|
|
1544
|
+
return typeof value === 'string' && /^\d{1,7}$/.test(value.trim());
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function emitAmbiguousVideoIdWarnings(items) {
|
|
1548
|
+
const references = Array.isArray(items) ? items : [];
|
|
1549
|
+
for (const item of references) {
|
|
1550
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) continue;
|
|
1551
|
+
if (looksLikeShortNumericVideoId(item.videoId)) {
|
|
1552
|
+
process.stderr.write(
|
|
1553
|
+
`[socialseal] videoId "${item.videoId}" looks like a short internal row id. If you meant a ranked result row, use --search-result-id. If you meant a tracking item id, resolve it first and retry with --video-uid or --platform-video-id.\n`,
|
|
1554
|
+
);
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1483
1560
|
function sleep(ms) {
|
|
1484
1561
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1485
1562
|
}
|
|
@@ -1629,7 +1706,7 @@ function buildStatusHint(status, context = {}) {
|
|
|
1629
1706
|
case 404:
|
|
1630
1707
|
if (context.functionName) {
|
|
1631
1708
|
if (isLocallyDisabledByDefaultFunction(context.functionName)) {
|
|
1632
|
-
return `Unknown function "${context.functionName}".
|
|
1709
|
+
return `Unknown function "${context.functionName}". The CLI ships a static registry, but availability depends on the backend you are calling. Verify the tool is deployed on the current API base; for local direct Supabase calls, enable it in supabase/config.toml.`;
|
|
1633
1710
|
}
|
|
1634
1711
|
return `Unknown function "${context.functionName}". Double-check the name and API base.`;
|
|
1635
1712
|
}
|
|
@@ -2197,14 +2274,64 @@ async function handleToolsCall(opts) {
|
|
|
2197
2274
|
resolvedWorkspaceId,
|
|
2198
2275
|
});
|
|
2199
2276
|
const method = normalizeMethod(translated.method);
|
|
2200
|
-
const
|
|
2277
|
+
const payloadWorkspaceId = isJsonObject(translated.normalizedPayload)
|
|
2278
|
+
? resolvePayloadWorkspaceId(translated.normalizedPayload, resolvedWorkspaceId)
|
|
2279
|
+
: (isJsonObject(translated.body)
|
|
2280
|
+
? resolvePayloadWorkspaceId(translated.body, resolvedWorkspaceId)
|
|
2281
|
+
: (resolvedWorkspaceId ?? null));
|
|
2282
|
+
const effectiveWorkspaceId = translated.workspaceId ?? payloadWorkspaceId ?? null;
|
|
2283
|
+
const effectiveWorkspaceSource =
|
|
2284
|
+
translated.workspaceId && translated.workspaceId !== resolvedWorkspaceId
|
|
2285
|
+
? 'body'
|
|
2286
|
+
: (payloadWorkspaceId && payloadWorkspaceId !== resolvedWorkspaceId ? 'body' : workspaceSource);
|
|
2201
2287
|
const path = useGateway
|
|
2202
2288
|
? `/cli/tools/${opts.function}${translated.pathSuffix || ''}`
|
|
2203
2289
|
: `/functions/v1/${opts.function}${translated.pathSuffix || ''}`;
|
|
2204
2290
|
|
|
2291
|
+
if (opts.function === 'group-management') {
|
|
2292
|
+
requireWorkspaceSelection(effectiveWorkspaceId, {
|
|
2293
|
+
label: 'group-management',
|
|
2294
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, or configure a default workspace. Omitting workspace lets the backend fall back to the personal workspace.',
|
|
2295
|
+
});
|
|
2296
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2297
|
+
workspaceId: effectiveWorkspaceId,
|
|
2298
|
+
source: effectiveWorkspaceSource,
|
|
2299
|
+
label: 'group-management',
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
if (opts.function === 'export_tracking_data') {
|
|
2304
|
+
requireWorkspaceSelection(effectiveWorkspaceId, {
|
|
2305
|
+
label: 'export_tracking_data',
|
|
2306
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, or configure a default workspace before exporting tracking data.',
|
|
2307
|
+
});
|
|
2308
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2309
|
+
workspaceId: effectiveWorkspaceId,
|
|
2310
|
+
source: effectiveWorkspaceSource,
|
|
2311
|
+
label: 'export_tracking_data',
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
if (opts.function === 'tracked-video-extract') {
|
|
2316
|
+
requireWorkspaceSelection(effectiveWorkspaceId, {
|
|
2317
|
+
label: 'tracked-video-extract',
|
|
2318
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, or configure a default workspace.',
|
|
2319
|
+
});
|
|
2320
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2321
|
+
workspaceId: effectiveWorkspaceId,
|
|
2322
|
+
source: effectiveWorkspaceSource,
|
|
2323
|
+
label: 'tracked-video-extract',
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
emitTrackingCreateScopeWarning(
|
|
2328
|
+
isJsonObject(translated.normalizedPayload) ? trimString(translated.normalizedPayload.action).toLowerCase() : '',
|
|
2329
|
+
effectiveWorkspaceId,
|
|
2330
|
+
);
|
|
2331
|
+
|
|
2205
2332
|
emitWorkspaceContext(opts, {
|
|
2206
2333
|
workspaceId: effectiveWorkspaceId,
|
|
2207
|
-
source:
|
|
2334
|
+
source: effectiveWorkspaceSource,
|
|
2208
2335
|
functionName: opts.function,
|
|
2209
2336
|
method,
|
|
2210
2337
|
});
|
|
@@ -2319,7 +2446,7 @@ async function handleDataExportTracking(opts) {
|
|
|
2319
2446
|
const supabaseUrl = resolveLegacyUrl(resolveSupabaseUrl(opts, config), 'SOCIALSEAL_SUPABASE_URL');
|
|
2320
2447
|
const { resolvedApiBase, legacyUrl, useGateway } = resolveApiTarget({ apiBase, legacyUrl: supabaseUrl });
|
|
2321
2448
|
const timeoutMs = resolveTimeoutMs(opts, config);
|
|
2322
|
-
const { workspaceId: resolvedWorkspaceId } = resolveWorkspaceSelection(opts, config);
|
|
2449
|
+
const { workspaceId: resolvedWorkspaceId, source: workspaceSource } = resolveWorkspaceSelection(opts, config);
|
|
2323
2450
|
|
|
2324
2451
|
if (!opts.groupId && !opts.itemId) {
|
|
2325
2452
|
throw new CliError('Provide --group-id or --item-id.', {
|
|
@@ -2341,6 +2468,16 @@ async function handleDataExportTracking(opts) {
|
|
|
2341
2468
|
time_period: opts.timePeriod,
|
|
2342
2469
|
};
|
|
2343
2470
|
|
|
2471
|
+
requireWorkspaceSelection(resolvedWorkspaceId, {
|
|
2472
|
+
label: 'Tracking export',
|
|
2473
|
+
hint: 'Pass --workspace-id, set SOCIALSEAL_WORKSPACE_ID, or configure a default workspace before exporting tracking data.',
|
|
2474
|
+
});
|
|
2475
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2476
|
+
workspaceId: resolvedWorkspaceId,
|
|
2477
|
+
source: workspaceSource,
|
|
2478
|
+
label: 'tracking export',
|
|
2479
|
+
});
|
|
2480
|
+
|
|
2344
2481
|
const res = await callApi({
|
|
2345
2482
|
apiBase: useGateway ? resolvedApiBase : legacyUrl,
|
|
2346
2483
|
apiKey,
|
|
@@ -2445,10 +2582,19 @@ async function handleVideoExtract(opts) {
|
|
|
2445
2582
|
|
|
2446
2583
|
const body = buildVideoExtractBody(opts, resolvedWorkspaceId);
|
|
2447
2584
|
const path = useGateway ? '/cli/tools/tracked-video-extract' : '/functions/v1/tracked-video-extract';
|
|
2585
|
+
const effectiveWorkspaceId = body.workspaceId || resolvedWorkspaceId;
|
|
2586
|
+
const effectiveWorkspaceSource = body.workspaceId && body.workspaceId !== resolvedWorkspaceId ? 'body' : workspaceSource;
|
|
2587
|
+
|
|
2588
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2589
|
+
workspaceId: effectiveWorkspaceId,
|
|
2590
|
+
source: effectiveWorkspaceSource,
|
|
2591
|
+
label: 'tracked-video extract',
|
|
2592
|
+
});
|
|
2593
|
+
emitAmbiguousVideoIdWarnings(body.items);
|
|
2448
2594
|
|
|
2449
2595
|
emitWorkspaceContext(opts, {
|
|
2450
|
-
workspaceId:
|
|
2451
|
-
source:
|
|
2596
|
+
workspaceId: effectiveWorkspaceId,
|
|
2597
|
+
source: effectiveWorkspaceSource,
|
|
2452
2598
|
functionName: 'tracked-video-extract',
|
|
2453
2599
|
method: 'POST',
|
|
2454
2600
|
});
|
|
@@ -2460,7 +2606,7 @@ async function handleVideoExtract(opts) {
|
|
|
2460
2606
|
path,
|
|
2461
2607
|
method: 'POST',
|
|
2462
2608
|
body,
|
|
2463
|
-
workspaceId:
|
|
2609
|
+
workspaceId: effectiveWorkspaceId,
|
|
2464
2610
|
timeoutMs: remainingTimeoutMs,
|
|
2465
2611
|
});
|
|
2466
2612
|
|
|
@@ -2523,11 +2669,20 @@ async function handleVideoQueueAnalysis(opts) {
|
|
|
2523
2669
|
const { workspaceId: resolvedWorkspaceId, source: workspaceSource } = resolveWorkspaceSelection(opts, config);
|
|
2524
2670
|
|
|
2525
2671
|
const body = buildVideoQueueBody(opts, resolvedWorkspaceId);
|
|
2672
|
+
const effectiveWorkspaceId = body.workspaceId || resolvedWorkspaceId;
|
|
2673
|
+
const effectiveWorkspaceSource = body.workspaceId && body.workspaceId !== resolvedWorkspaceId ? 'body' : workspaceSource;
|
|
2674
|
+
|
|
2675
|
+
emitWorkspaceSelectionNotice(opts, {
|
|
2676
|
+
workspaceId: effectiveWorkspaceId,
|
|
2677
|
+
source: effectiveWorkspaceSource,
|
|
2678
|
+
label: 'tracked-video queue-analysis',
|
|
2679
|
+
});
|
|
2680
|
+
emitAmbiguousVideoIdWarnings(body.items);
|
|
2526
2681
|
const path = useGateway ? '/cli/tools/tracked-video-extract' : '/functions/v1/tracked-video-extract';
|
|
2527
2682
|
|
|
2528
2683
|
emitWorkspaceContext(opts, {
|
|
2529
|
-
workspaceId:
|
|
2530
|
-
source:
|
|
2684
|
+
workspaceId: effectiveWorkspaceId,
|
|
2685
|
+
source: effectiveWorkspaceSource,
|
|
2531
2686
|
functionName: 'tracked-video-extract',
|
|
2532
2687
|
method: 'POST',
|
|
2533
2688
|
});
|
|
@@ -2539,7 +2694,7 @@ async function handleVideoQueueAnalysis(opts) {
|
|
|
2539
2694
|
path,
|
|
2540
2695
|
method: 'POST',
|
|
2541
2696
|
body,
|
|
2542
|
-
workspaceId:
|
|
2697
|
+
workspaceId: effectiveWorkspaceId,
|
|
2543
2698
|
timeoutMs: remainingTimeoutMs,
|
|
2544
2699
|
});
|
|
2545
2700
|
|
|
@@ -2624,6 +2779,8 @@ async function handleWorkspaceList(opts) {
|
|
|
2624
2779
|
process.stdout.write(`${formatWorkspaceLine(workspace, { isEffective, source: selection.source, isSuggested })}\n`);
|
|
2625
2780
|
}
|
|
2626
2781
|
|
|
2782
|
+
process.stdout.write('\n[socialseal] Note: workspace ids are not brand ids. When a payload includes both workspace_id and brand_id, pass the workspace id to --workspace-id.\n');
|
|
2783
|
+
|
|
2627
2784
|
if (!selection.workspaceId && directory.defaultWorkspaceId) {
|
|
2628
2785
|
process.stdout.write('\n[socialseal] No local default is configured. Set one with: socialseal workspace use <id>\n');
|
|
2629
2786
|
}
|
|
@@ -2668,6 +2825,7 @@ async function handleWorkspaceCurrent(opts) {
|
|
|
2668
2825
|
|
|
2669
2826
|
if (effectiveWorkspace) {
|
|
2670
2827
|
process.stdout.write(`[socialseal] Effective workspace: ${effectiveWorkspace.name} (${effectiveWorkspace.id}) via ${selection.source}\n`);
|
|
2828
|
+
process.stdout.write('[socialseal] Note: workspace ids are not brand ids. Use the workspace id, not brand_id, with --workspace-id.\n');
|
|
2671
2829
|
return;
|
|
2672
2830
|
}
|
|
2673
2831
|
|
|
@@ -2736,7 +2894,7 @@ const program = new Command();
|
|
|
2736
2894
|
program
|
|
2737
2895
|
.name('socialseal')
|
|
2738
2896
|
.description('SocialSeal CLI (non-interactive)')
|
|
2739
|
-
.version(
|
|
2897
|
+
.version(CLI_VERSION);
|
|
2740
2898
|
|
|
2741
2899
|
if (typeof program.showHelpAfterError === 'function') {
|
|
2742
2900
|
program.showHelpAfterError(true);
|
|
@@ -2874,10 +3032,10 @@ const video = program.command('video').description('Tracked video extraction wor
|
|
|
2874
3032
|
video
|
|
2875
3033
|
.command('queue-analysis')
|
|
2876
3034
|
.description('Queue video analysis for tracked videos or tracked search results')
|
|
2877
|
-
.option('--video-id <id>', 'Tracked video
|
|
2878
|
-
.option('--search-result-id <id>', 'Tracked search result id')
|
|
2879
|
-
.option('--video-uid <id>', '
|
|
2880
|
-
.option('--platform-video-id <id>', '
|
|
3035
|
+
.option('--video-id <id>', 'Tracked video identifier (video_uid first, then platform video id; not a tracking item id)')
|
|
3036
|
+
.option('--search-result-id <id>', 'Tracked search result id for a ranked result row')
|
|
3037
|
+
.option('--video-uid <id>', 'Canonical tracked video_uid')
|
|
3038
|
+
.option('--platform-video-id <id>', 'Platform-native video id')
|
|
2881
3039
|
.option('--body <jsonOrFile>', 'JSON body or @payload.json for batch queueing')
|
|
2882
3040
|
.option('--wait', 'Poll until queued/completing analyses settle')
|
|
2883
3041
|
.option('--poll-interval <ms>', 'Polling interval in milliseconds when --wait is enabled')
|
|
@@ -2893,10 +3051,10 @@ video
|
|
|
2893
3051
|
video
|
|
2894
3052
|
.command('extract')
|
|
2895
3053
|
.description('Resolve tracked videos/results into structured analysis plus reference assets')
|
|
2896
|
-
.option('--video-id <id>', 'Tracked video
|
|
2897
|
-
.option('--search-result-id <id>', 'Tracked search result id')
|
|
2898
|
-
.option('--video-uid <id>', '
|
|
2899
|
-
.option('--platform-video-id <id>', '
|
|
3054
|
+
.option('--video-id <id>', 'Tracked video identifier (video_uid first, then platform video id; not a tracking item id)')
|
|
3055
|
+
.option('--search-result-id <id>', 'Tracked search result id for a ranked result row')
|
|
3056
|
+
.option('--video-uid <id>', 'Canonical tracked video_uid')
|
|
3057
|
+
.option('--platform-video-id <id>', 'Platform-native video id')
|
|
2900
3058
|
.option('--body <jsonOrFile>', 'JSON body or @payload.json for batch extraction')
|
|
2901
3059
|
.option('--ensure-analysis', 'Queue analysis when it is missing')
|
|
2902
3060
|
.option('--wait', 'Poll until queued/completing analyses settle')
|