@socialseal/cli 0.1.3 → 0.1.4
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 +5 -0
- package/package.json +1 -1
- package/src/index.js +215 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.4 - 2026-03-19
|
|
6
|
+
- Add explicit `group_add_item` / `group_add_items` CLI aliases for tracking-group membership workflows.
|
|
7
|
+
- Add `tracking resolve` / `get_by_value` so existing tracked searches can be resolved by value using the same duplicate-detection semantics as create.
|
|
8
|
+
- Return operational duplicate metadata for tracking conflicts, including `existing_item_id`, `member_of_group_ids`, platform, region, workspace, and active state.
|
|
9
|
+
|
|
5
10
|
## 0.1.3 - 2026-03-19
|
|
6
11
|
- Republish the current CLI release line after the successful `0.1.2` npm publish, keeping the internal and OSS package versions aligned.
|
|
7
12
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -76,8 +76,8 @@ const KNOWN_TOOLS = [
|
|
|
76
76
|
transport: 'rest_edge_function',
|
|
77
77
|
workspaceScoped: true,
|
|
78
78
|
knownLocalDevState: 'disabled_by_default',
|
|
79
|
-
actionAliases: ['list', 'get', 'create', 'update', 'delete', 'refresh', 'list_items'],
|
|
80
|
-
notes: 'REST-style surface under /groups.
|
|
79
|
+
actionAliases: ['list', 'get', 'create', 'update', 'delete', 'refresh', 'list_items', 'add_item', 'group_add_item', 'add_items', 'group_add_items', 'remove_item', 'group_remove_item'],
|
|
80
|
+
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.',
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
name: 'tracking',
|
|
@@ -87,8 +87,8 @@ const KNOWN_TOOLS = [
|
|
|
87
87
|
transport: 'rest_edge_function',
|
|
88
88
|
workspaceScoped: true,
|
|
89
89
|
knownLocalDevState: 'enabled',
|
|
90
|
-
actionAliases: ['list', 'get', 'create', 'update', 'delete', 'refresh'],
|
|
91
|
-
notes: 'REST-style surface.
|
|
90
|
+
actionAliases: ['list', 'get', 'resolve', 'get_by_value', 'create', 'update', 'delete', 'refresh'],
|
|
91
|
+
notes: 'REST-style surface. `resolve`/`get_by_value` uses the same workspace/platform/region duplicate-detection lookup as create and returns inactive matches too.',
|
|
92
92
|
},
|
|
93
93
|
{ name: 'journey-feedback', category: 'vnext', description: 'Record acceptance or rejection feedback for opportunity bundles.' },
|
|
94
94
|
{ name: 'opportunity-bundle-approve', category: 'vnext', description: 'Approve an opportunity bundle and create tracking coverage.' },
|
|
@@ -458,18 +458,40 @@ function normalizeTrackingPayload(payload, fallbackWorkspaceId) {
|
|
|
458
458
|
|
|
459
459
|
function normalizeGroupManagementPayload(payload, fallbackWorkspaceId) {
|
|
460
460
|
const groupId = firstDefined(payload, ['group_id', 'groupId', 'id']);
|
|
461
|
+
const itemId = firstDefined(payload, ['item_id', 'itemId']);
|
|
462
|
+
const itemIds = firstDefined(payload, ['item_ids', 'itemIds']);
|
|
463
|
+
const items = firstDefined(payload, ['items']);
|
|
461
464
|
const limit = firstDefined(payload, ['limit']);
|
|
462
465
|
const page = firstDefined(payload, ['page']);
|
|
463
466
|
return stripUndefinedEntries({
|
|
464
467
|
action: trimString(firstDefined(payload, ['action'])) || undefined,
|
|
465
468
|
workspaceId: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId),
|
|
466
469
|
group_id: coercePositiveInteger(groupId, 'group_id'),
|
|
470
|
+
item_id: coercePositiveInteger(itemId, 'item_id'),
|
|
471
|
+
item_ids: Array.isArray(itemIds)
|
|
472
|
+
? itemIds.map((value, index) => {
|
|
473
|
+
const parsed = coercePositiveInteger(value, `item_ids[${index}]`);
|
|
474
|
+
if (!parsed) {
|
|
475
|
+
throw new CliError(`Invalid item_ids[${index}]: expected a positive integer.`, {
|
|
476
|
+
code: 'INVALID_ARGUMENT',
|
|
477
|
+
exitCode: EXIT_CODES.USAGE,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
return parsed;
|
|
481
|
+
})
|
|
482
|
+
: undefined,
|
|
483
|
+
items: Array.isArray(items) ? items : undefined,
|
|
467
484
|
name: trimString(firstDefined(payload, ['name'])) || undefined,
|
|
468
485
|
description: firstDefined(payload, ['description']),
|
|
469
486
|
platform: trimString(firstDefined(payload, ['platform', 'groupPlatform'])) || undefined,
|
|
470
487
|
refresh_frequency: trimString(firstDefined(payload, ['refresh_frequency', 'refreshFrequency'])) || undefined,
|
|
471
488
|
next_refresh_at: firstDefined(payload, ['next_refresh_at', 'nextRefreshAt']) ?? undefined,
|
|
472
489
|
brand_id: trimString(firstDefined(payload, ['brand_id', 'brandId'])) || undefined,
|
|
490
|
+
track_type: normalizeTrackingType(firstDefined(payload, ['track_type', 'trackType', 'type'])),
|
|
491
|
+
track_value: trimString(firstDefined(payload, ['track_value', 'trackValue', 'value'])) || undefined,
|
|
492
|
+
region: typeof firstDefined(payload, ['region']) === 'string'
|
|
493
|
+
? trimString(firstDefined(payload, ['region'])) || undefined
|
|
494
|
+
: firstDefined(payload, ['region']),
|
|
473
495
|
limit: limit !== undefined ? Number(limit) : undefined,
|
|
474
496
|
page: page !== undefined ? Number(page) : undefined,
|
|
475
497
|
});
|
|
@@ -512,6 +534,122 @@ function normalizeTrackingExportPayload(payload, fallbackWorkspaceId) {
|
|
|
512
534
|
});
|
|
513
535
|
}
|
|
514
536
|
|
|
537
|
+
function buildGroupAddPayloadFromValue(rawValue, payload, label) {
|
|
538
|
+
const value = trimString(rawValue);
|
|
539
|
+
if (!value) {
|
|
540
|
+
throw new CliError(`Invalid ${label}: expected a non-empty tracking value.`, {
|
|
541
|
+
code: 'INVALID_ARGUMENT',
|
|
542
|
+
exitCode: EXIT_CODES.USAGE,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
if (!payload.track_type) {
|
|
546
|
+
throw new CliError(`${label} requires track_type/type when using raw values.`, {
|
|
547
|
+
code: 'MISSING_ARGUMENT',
|
|
548
|
+
exitCode: EXIT_CODES.USAGE,
|
|
549
|
+
hint: 'Use type=keyword/search, hashtag, or account/creator when adding items by value.',
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
return stripUndefinedEntries({
|
|
553
|
+
name: value,
|
|
554
|
+
track_type: payload.track_type,
|
|
555
|
+
track_value: value,
|
|
556
|
+
refresh_frequency: payload.refresh_frequency,
|
|
557
|
+
next_refresh_at: payload.next_refresh_at,
|
|
558
|
+
region: payload.region,
|
|
559
|
+
platform: payload.platform,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function buildGroupAddPayloadFromItem(rawItem, payload, label) {
|
|
564
|
+
if (typeof rawItem === 'number') {
|
|
565
|
+
return { item_id: coercePositiveInteger(rawItem, label) };
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (typeof rawItem === 'string') {
|
|
569
|
+
const trimmed = rawItem.trim();
|
|
570
|
+
if (/^\d+$/.test(trimmed)) {
|
|
571
|
+
return { item_id: coercePositiveInteger(trimmed, label) };
|
|
572
|
+
}
|
|
573
|
+
return buildGroupAddPayloadFromValue(rawItem, payload, label);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (!rawItem || typeof rawItem !== 'object' || Array.isArray(rawItem)) {
|
|
577
|
+
throw new CliError(`Invalid ${label}: expected an item id, string value, or object payload.`, {
|
|
578
|
+
code: 'INVALID_ARGUMENT',
|
|
579
|
+
exitCode: EXIT_CODES.USAGE,
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const itemId = coercePositiveInteger(firstDefined(rawItem, ['item_id', 'itemId', 'id']), `${label}.item_id`);
|
|
584
|
+
if (itemId) {
|
|
585
|
+
return { item_id: itemId };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const trackValue = trimString(firstDefined(rawItem, ['track_value', 'trackValue', 'value'])) || undefined;
|
|
589
|
+
const name = trimString(firstDefined(rawItem, ['name'])) || trackValue;
|
|
590
|
+
const trackType = normalizeTrackingType(firstDefined(rawItem, ['track_type', 'trackType', 'type'])) || payload.track_type;
|
|
591
|
+
const region = firstDefined(rawItem, ['region']) ?? payload.region;
|
|
592
|
+
const platform = trimString(firstDefined(rawItem, ['platform'])) || payload.platform;
|
|
593
|
+
const refreshFrequency = trimString(firstDefined(rawItem, ['refresh_frequency', 'refreshFrequency'])) || payload.refresh_frequency;
|
|
594
|
+
const nextRefreshAt = firstDefined(rawItem, ['next_refresh_at', 'nextRefreshAt']) ?? payload.next_refresh_at;
|
|
595
|
+
|
|
596
|
+
if (!name || !trackValue || !trackType) {
|
|
597
|
+
throw new CliError(`${label} requires item_id or name/track_value + track_type.`, {
|
|
598
|
+
code: 'MISSING_ARGUMENT',
|
|
599
|
+
exitCode: EXIT_CODES.USAGE,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return stripUndefinedEntries({
|
|
604
|
+
name,
|
|
605
|
+
track_type: trackType,
|
|
606
|
+
track_value: trackValue,
|
|
607
|
+
refresh_frequency: refreshFrequency,
|
|
608
|
+
next_refresh_at: nextRefreshAt,
|
|
609
|
+
region,
|
|
610
|
+
platform,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function buildSingleGroupAddBody(payload) {
|
|
615
|
+
if (payload.item_id) {
|
|
616
|
+
return { item_id: payload.item_id };
|
|
617
|
+
}
|
|
618
|
+
if (payload.track_value || payload.name) {
|
|
619
|
+
return buildGroupAddPayloadFromItem({
|
|
620
|
+
name: payload.name,
|
|
621
|
+
track_type: payload.track_type,
|
|
622
|
+
track_value: payload.track_value,
|
|
623
|
+
refresh_frequency: payload.refresh_frequency,
|
|
624
|
+
next_refresh_at: payload.next_refresh_at,
|
|
625
|
+
region: payload.region,
|
|
626
|
+
platform: payload.platform,
|
|
627
|
+
}, payload, 'group add item payload');
|
|
628
|
+
}
|
|
629
|
+
throw new CliError('group add_item requires item_id or a tracking payload.', {
|
|
630
|
+
code: 'MISSING_ARGUMENT',
|
|
631
|
+
exitCode: EXIT_CODES.USAGE,
|
|
632
|
+
hint: 'Provide item_id to attach an existing tracking item, or provide track_type + track_value to create/link by value.',
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function buildBulkGroupAddBody(payload) {
|
|
637
|
+
if (Array.isArray(payload.item_ids) && payload.item_ids.length > 0) {
|
|
638
|
+
return payload.item_ids.map((item_id) => ({ item_id }));
|
|
639
|
+
}
|
|
640
|
+
if (Array.isArray(payload.items) && payload.items.length > 0) {
|
|
641
|
+
return payload.items.map((item, index) => buildGroupAddPayloadFromItem(item, payload, `items[${index}]`));
|
|
642
|
+
}
|
|
643
|
+
if (payload.item_id || payload.track_value || payload.name) {
|
|
644
|
+
return [buildSingleGroupAddBody(payload)];
|
|
645
|
+
}
|
|
646
|
+
throw new CliError('group add_items requires item_ids, items, or a single item payload.', {
|
|
647
|
+
code: 'MISSING_ARGUMENT',
|
|
648
|
+
exitCode: EXIT_CODES.USAGE,
|
|
649
|
+
hint: 'Use item_ids to bulk attach existing tracking items, or use items with track_type/type for value-based adds.',
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
515
653
|
function translateTrackingAction(payload, workspaceId) {
|
|
516
654
|
const action = payload.action ? payload.action.toLowerCase() : null;
|
|
517
655
|
if (!action) {
|
|
@@ -572,6 +710,28 @@ function translateTrackingAction(payload, workspaceId) {
|
|
|
572
710
|
};
|
|
573
711
|
}
|
|
574
712
|
|
|
713
|
+
if (action === 'resolve' || action === 'item_resolve' || action === 'get_by_value' || action === 'item_get_by_value') {
|
|
714
|
+
if (!payload.track_type || !payload.track_value) {
|
|
715
|
+
throw new CliError('track_type and track_value are required for tracking resolve.', {
|
|
716
|
+
code: 'MISSING_ARGUMENT',
|
|
717
|
+
exitCode: EXIT_CODES.USAGE,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
method: 'GET',
|
|
722
|
+
pathSuffix: buildPathWithQuery('', {
|
|
723
|
+
workspace_id: workspaceId || undefined,
|
|
724
|
+
resolve: 'true',
|
|
725
|
+
track_type: payload.track_type,
|
|
726
|
+
track_value: payload.track_value,
|
|
727
|
+
platform: payload.platform,
|
|
728
|
+
region: payload.region,
|
|
729
|
+
}),
|
|
730
|
+
body: undefined,
|
|
731
|
+
workspaceId,
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
|
|
575
735
|
if (action === 'create' || action === 'item_create') {
|
|
576
736
|
return {
|
|
577
737
|
method: 'POST',
|
|
@@ -644,7 +804,7 @@ function translateTrackingAction(payload, workspaceId) {
|
|
|
644
804
|
throw new CliError(`Unsupported tracking action: ${payload.action}`, {
|
|
645
805
|
code: 'INVALID_ARGUMENT',
|
|
646
806
|
exitCode: EXIT_CODES.USAGE,
|
|
647
|
-
hint: 'Supported tracking actions: list, get, create, update, delete, refresh.',
|
|
807
|
+
hint: 'Supported tracking actions: list, get, resolve, create, update, delete, refresh.',
|
|
648
808
|
});
|
|
649
809
|
}
|
|
650
810
|
|
|
@@ -791,10 +951,59 @@ function translateGroupManagementAction(payload, workspaceId, originalMethod) {
|
|
|
791
951
|
};
|
|
792
952
|
}
|
|
793
953
|
|
|
954
|
+
if (action === 'add_item' || action === 'group_add_item') {
|
|
955
|
+
const groupId = coercePositiveInteger(payload.group_id, 'group_id');
|
|
956
|
+
if (!groupId) {
|
|
957
|
+
throw new CliError('group_id is required for group add_item.', {
|
|
958
|
+
code: 'MISSING_ARGUMENT',
|
|
959
|
+
exitCode: EXIT_CODES.USAGE,
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
return {
|
|
963
|
+
method: 'POST',
|
|
964
|
+
pathSuffix: buildPathWithQuery(`/groups/${groupId}/items`, { workspace_id: workspaceId || undefined }),
|
|
965
|
+
body: buildSingleGroupAddBody(payload),
|
|
966
|
+
workspaceId,
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (action === 'add_items' || action === 'group_add_items') {
|
|
971
|
+
const groupId = coercePositiveInteger(payload.group_id, 'group_id');
|
|
972
|
+
if (!groupId) {
|
|
973
|
+
throw new CliError('group_id is required for group add_items.', {
|
|
974
|
+
code: 'MISSING_ARGUMENT',
|
|
975
|
+
exitCode: EXIT_CODES.USAGE,
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
return {
|
|
979
|
+
method: 'POST',
|
|
980
|
+
pathSuffix: buildPathWithQuery(`/groups/${groupId}/items/bulk`, { workspace_id: workspaceId || undefined }),
|
|
981
|
+
body: buildBulkGroupAddBody(payload),
|
|
982
|
+
workspaceId,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if (action === 'remove_item' || action === 'group_remove_item') {
|
|
987
|
+
const groupId = coercePositiveInteger(payload.group_id, 'group_id');
|
|
988
|
+
const itemId = coercePositiveInteger(payload.item_id, 'item_id');
|
|
989
|
+
if (!groupId || !itemId) {
|
|
990
|
+
throw new CliError('group_id and item_id are required for group remove_item.', {
|
|
991
|
+
code: 'MISSING_ARGUMENT',
|
|
992
|
+
exitCode: EXIT_CODES.USAGE,
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
return {
|
|
996
|
+
method: 'DELETE',
|
|
997
|
+
pathSuffix: buildPathWithQuery(`/groups/${groupId}/items/${itemId}`, { workspace_id: workspaceId || undefined }),
|
|
998
|
+
body: undefined,
|
|
999
|
+
workspaceId,
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
|
|
794
1003
|
throw new CliError(`Unsupported group-management action: ${payload.action}`, {
|
|
795
1004
|
code: 'INVALID_ARGUMENT',
|
|
796
1005
|
exitCode: EXIT_CODES.USAGE,
|
|
797
|
-
hint: 'Supported group-management actions: list, get, create, update, delete, refresh, list_items.',
|
|
1006
|
+
hint: 'Supported group-management actions: list, get, create, update, delete, refresh, list_items, add_item, add_items, remove_item.',
|
|
798
1007
|
});
|
|
799
1008
|
}
|
|
800
1009
|
|