@geoly-ai/social-hub-cli 0.0.12 → 0.0.13
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/dist/admin-index-gates.test.d.ts +2 -0
- package/dist/admin-index-gates.test.d.ts.map +1 -0
- package/dist/admin-index-gates.test.js +33 -0
- package/dist/admin-index-gates.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +684 -63
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +87 -5
- package/dist/index.test.js.map +1 -1
- package/dist/permission-runner.d.ts +11 -0
- package/dist/permission-runner.d.ts.map +1 -0
- package/dist/permission-runner.js +30 -0
- package/dist/permission-runner.js.map +1 -0
- package/dist/permission-runner.test.d.ts +2 -0
- package/dist/permission-runner.test.d.ts.map +1 -0
- package/dist/permission-runner.test.js +69 -0
- package/dist/permission-runner.test.js.map +1 -0
- package/dist/permissions-gates-admin.d.ts +4 -0
- package/dist/permissions-gates-admin.d.ts.map +1 -0
- package/dist/permissions-gates-admin.js +80 -0
- package/dist/permissions-gates-admin.js.map +1 -0
- package/dist/permissions-gates-admin.test.d.ts +2 -0
- package/dist/permissions-gates-admin.test.d.ts.map +1 -0
- package/dist/permissions-gates-admin.test.js +25 -0
- package/dist/permissions-gates-admin.test.js.map +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +2 -3
- package/dist/permissions.js.map +1 -1
- package/dist/register-admin.d.ts.map +1 -1
- package/dist/register-admin.js +343 -29
- package/dist/register-admin.js.map +1 -1
- package/dist/register-extensions.d.ts.map +1 -1
- package/dist/register-extensions.js +16 -19
- package/dist/register-extensions.js.map +1 -1
- package/package.json +2 -2
- package/skills/README.md +7 -5
- package/skills/manifest.json +17 -7
- package/skills/social-hub-accounts/SKILL.md +46 -13
- package/skills/social-hub-admin/SKILL.md +76 -10
- package/skills/social-hub-calendar-jobs/SKILL.md +26 -10
- package/skills/social-hub-cli/SKILL.md +35 -191
- package/skills/social-hub-cli/evals/evals.json +4 -4
- package/skills/social-hub-events-observability/SKILL.md +49 -0
- package/skills/social-hub-graph-compliance/SKILL.md +60 -0
- package/skills/social-hub-intelligence/SKILL.md +72 -7
- package/skills/social-hub-migration/SKILL.md +18 -5
- package/skills/social-hub-openclaw-context/SKILL.md +21 -6
- package/skills/social-hub-ops-runtime/SKILL.md +10 -5
- package/skills/social-hub-posts/SKILL.md +54 -23
- package/skills/social-hub-posts/evals/evals.json +23 -0
- package/skills/social-hub-publishing/SKILL.md +75 -11
- package/skills/social-hub-shared/SKILL.md +8 -4
package/dist/index.js
CHANGED
|
@@ -4,6 +4,8 @@ import { getSocialHubHealth } from "@geoly-ai/social-hub-sdk";
|
|
|
4
4
|
import { getBaseUrl, requireClient } from "./client.js";
|
|
5
5
|
import { registerAccountsExtensions, registerAuthAndConfig, registerPermissionsExplain, registerRedditExtensions, } from "./register-extensions.js";
|
|
6
6
|
import { registerAdminCommands } from "./register-admin.js";
|
|
7
|
+
import { assertApplyOrDryRun } from "./dry-run.js";
|
|
8
|
+
import { withPermissionGate } from "./permission-runner.js";
|
|
7
9
|
import { registerBatchAndExport } from "./register-batch.js";
|
|
8
10
|
import { registerAgentContext, registerOpsRuntime, } from "./register-ops.js";
|
|
9
11
|
import { registerDoctorAndVersion } from "./register-shared.js";
|
|
@@ -604,6 +606,28 @@ compliance
|
|
|
604
606
|
const res = await requireClient().upsertAccountRiskProfile(opts.team, opts.account, body);
|
|
605
607
|
console.log(JSON.stringify(res, null, 2));
|
|
606
608
|
});
|
|
609
|
+
compliance
|
|
610
|
+
.command("rule-caches-list")
|
|
611
|
+
.description("GET /subreddit-rule-caches")
|
|
612
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
613
|
+
.option("--include-expired", "include expired caches")
|
|
614
|
+
.action(async (opts) => {
|
|
615
|
+
const res = await requireClient().listSubredditRuleCaches(opts.team, {
|
|
616
|
+
includeExpired: Boolean(opts.includeExpired),
|
|
617
|
+
});
|
|
618
|
+
console.log(JSON.stringify(res, null, 2));
|
|
619
|
+
});
|
|
620
|
+
compliance
|
|
621
|
+
.command("rule-caches-upsert")
|
|
622
|
+
.description("PUT /subreddit-rule-caches/:subreddit")
|
|
623
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
624
|
+
.requiredOption("--sub <name>", "subreddit name")
|
|
625
|
+
.requiredOption("-j, --json <json>", "{ rulesMarkdown, sourceUrl?, expiresInDays? }")
|
|
626
|
+
.action(async (opts) => {
|
|
627
|
+
const body = JSON.parse(opts.json);
|
|
628
|
+
const res = await requireClient().upsertSubredditRuleCache(opts.team, opts.sub, body);
|
|
629
|
+
console.log(JSON.stringify(res, null, 2));
|
|
630
|
+
});
|
|
607
631
|
// --- openclaw ---
|
|
608
632
|
program
|
|
609
633
|
.command("openclaw-ingest")
|
|
@@ -716,8 +740,14 @@ agentTeams
|
|
|
716
740
|
.command("list")
|
|
717
741
|
.description("GET /v1/agent-teams")
|
|
718
742
|
.action(async () => {
|
|
719
|
-
|
|
720
|
-
|
|
743
|
+
await withPermissionGate({
|
|
744
|
+
command: "agent-teams list",
|
|
745
|
+
resource: "agentTeam",
|
|
746
|
+
action: "list",
|
|
747
|
+
}, async () => {
|
|
748
|
+
const res = await requireClient().listAgentTeams();
|
|
749
|
+
console.log(JSON.stringify(res, null, 2));
|
|
750
|
+
});
|
|
721
751
|
});
|
|
722
752
|
agentTeams
|
|
723
753
|
.command("workspace-docs")
|
|
@@ -726,30 +756,71 @@ agentTeams
|
|
|
726
756
|
.option("--kind <kind>", "file|daily_report|weekly_report|ops_record")
|
|
727
757
|
.option("-n, --limit <n>", "limit", "50")
|
|
728
758
|
.action(async (opts) => {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
759
|
+
await withPermissionGate({
|
|
760
|
+
command: "agent-teams workspace-docs",
|
|
761
|
+
resource: "agentTeam",
|
|
762
|
+
action: "read",
|
|
763
|
+
teamId: opts.team,
|
|
764
|
+
}, async () => {
|
|
765
|
+
const res = await requireClient().listWorkspaceDocuments(opts.team, {
|
|
766
|
+
kind: opts.kind,
|
|
767
|
+
limit: Number(opts.limit),
|
|
768
|
+
});
|
|
769
|
+
console.log(JSON.stringify(res, null, 2));
|
|
732
770
|
});
|
|
733
|
-
console.log(JSON.stringify(res, null, 2));
|
|
734
771
|
});
|
|
735
772
|
agentTeams
|
|
736
773
|
.command("create")
|
|
737
774
|
.description("POST /v1/agent-teams — 新建团队(admin only)")
|
|
738
775
|
.requiredOption("--slug <slug>", "团队 slug(小写字母、数字、横线)")
|
|
739
776
|
.requiredOption("--name <name>", "团队名称")
|
|
740
|
-
.
|
|
741
|
-
|
|
742
|
-
|
|
777
|
+
.option("--dry-run", "预览", false)
|
|
778
|
+
.option("--apply", "执行写入", false)
|
|
779
|
+
.action(async (opts) => {
|
|
780
|
+
await withPermissionGate({
|
|
781
|
+
command: "agent-teams create",
|
|
782
|
+
resource: "agentTeam",
|
|
783
|
+
action: "create",
|
|
784
|
+
}, async () => {
|
|
785
|
+
if (!assertApplyOrDryRun(opts, {
|
|
786
|
+
command: "agent-teams create",
|
|
787
|
+
danger: "admin",
|
|
788
|
+
summary: { slug: opts.slug, name: opts.name },
|
|
789
|
+
})) {
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const res = await requireClient().createTeam({
|
|
793
|
+
slug: opts.slug,
|
|
794
|
+
name: opts.name,
|
|
795
|
+
});
|
|
796
|
+
console.log(JSON.stringify(res, null, 2));
|
|
797
|
+
});
|
|
743
798
|
});
|
|
744
799
|
agentTeams
|
|
745
800
|
.command("update")
|
|
746
801
|
.description("PATCH /v1/agent-teams/:teamId — 更新团队(admin only)")
|
|
747
802
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
748
803
|
.requiredOption("-j, --json <json>", "{ slug?, name? }")
|
|
749
|
-
.
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
804
|
+
.option("--dry-run", "预览", false)
|
|
805
|
+
.option("--apply", "执行写入", false)
|
|
806
|
+
.action(async (opts) => {
|
|
807
|
+
await withPermissionGate({
|
|
808
|
+
command: "agent-teams update",
|
|
809
|
+
resource: "agentTeam",
|
|
810
|
+
action: "update",
|
|
811
|
+
teamId: opts.team,
|
|
812
|
+
}, async () => {
|
|
813
|
+
const body = JSON.parse(opts.json);
|
|
814
|
+
if (!assertApplyOrDryRun(opts, {
|
|
815
|
+
command: "agent-teams update",
|
|
816
|
+
danger: "admin",
|
|
817
|
+
summary: { teamId: opts.team, ...body },
|
|
818
|
+
})) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const res = await requireClient().updateTeam(opts.team, body);
|
|
822
|
+
console.log(JSON.stringify(res, null, 2));
|
|
823
|
+
});
|
|
753
824
|
});
|
|
754
825
|
agentTeams
|
|
755
826
|
.command("add-member")
|
|
@@ -757,12 +828,32 @@ agentTeams
|
|
|
757
828
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
758
829
|
.requiredOption("--user <userId>", "User UUID")
|
|
759
830
|
.requiredOption("--role <role>", "admin|manager|supervisor|senior|internal|client")
|
|
760
|
-
.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
831
|
+
.option("--dry-run", "预览", false)
|
|
832
|
+
.option("--apply", "执行写入", false)
|
|
833
|
+
.action(async (opts) => {
|
|
834
|
+
await withPermissionGate({
|
|
835
|
+
command: "agent-teams add-member",
|
|
836
|
+
resource: "agentTeam",
|
|
837
|
+
action: "update",
|
|
838
|
+
teamId: opts.team,
|
|
839
|
+
}, async () => {
|
|
840
|
+
if (!assertApplyOrDryRun(opts, {
|
|
841
|
+
command: "agent-teams add-member",
|
|
842
|
+
danger: "admin",
|
|
843
|
+
summary: {
|
|
844
|
+
teamId: opts.team,
|
|
845
|
+
userId: opts.user,
|
|
846
|
+
role: opts.role,
|
|
847
|
+
},
|
|
848
|
+
})) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
const res = await requireClient().addTeamMember(opts.team, {
|
|
852
|
+
userId: opts.user,
|
|
853
|
+
role: opts.role,
|
|
854
|
+
});
|
|
855
|
+
console.log(JSON.stringify(res, null, 2));
|
|
764
856
|
});
|
|
765
|
-
console.log(JSON.stringify(res, null, 2));
|
|
766
857
|
});
|
|
767
858
|
// --- intelligence (subreddit-intelligence) ---
|
|
768
859
|
const intel = program.command("intelligence").description("板块情报与 KOL 挖掘");
|
|
@@ -903,6 +994,192 @@ intel
|
|
|
903
994
|
const res = await requireClient().dispatchTaskFromHotPost(opts.team, body);
|
|
904
995
|
console.log(JSON.stringify(res, null, 2));
|
|
905
996
|
});
|
|
997
|
+
intel
|
|
998
|
+
.command("tier-rules-list")
|
|
999
|
+
.description("GET .../subreddit-intelligence/tier-rules")
|
|
1000
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1001
|
+
.option("--tier <tier>", "tier filter")
|
|
1002
|
+
.option("--enabled <bool>", "true|false")
|
|
1003
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
1004
|
+
.option("--offset <n>", "offset", "0")
|
|
1005
|
+
.action(async (opts) => {
|
|
1006
|
+
const res = await requireClient().listTierRules(opts.team, {
|
|
1007
|
+
tier: opts.tier,
|
|
1008
|
+
enabled: opts.enabled === undefined
|
|
1009
|
+
? undefined
|
|
1010
|
+
: opts.enabled === "true" || opts.enabled === "1",
|
|
1011
|
+
limit: Number(opts.limit),
|
|
1012
|
+
offset: Number(opts.offset),
|
|
1013
|
+
});
|
|
1014
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1015
|
+
});
|
|
1016
|
+
intel
|
|
1017
|
+
.command("tier-rules-create")
|
|
1018
|
+
.description("POST .../subreddit-intelligence/tier-rules")
|
|
1019
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1020
|
+
.requiredOption("-j, --json <json>", "tier rule body")
|
|
1021
|
+
.action(async (opts) => {
|
|
1022
|
+
const body = JSON.parse(opts.json);
|
|
1023
|
+
const res = await requireClient().createTierRule(opts.team, body);
|
|
1024
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1025
|
+
});
|
|
1026
|
+
intel
|
|
1027
|
+
.command("tier-rules-update")
|
|
1028
|
+
.description("PATCH .../subreddit-intelligence/tier-rules/:id")
|
|
1029
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1030
|
+
.requiredOption("--id <uuid>", "Tier rule UUID")
|
|
1031
|
+
.requiredOption("-j, --json <json>", "update body")
|
|
1032
|
+
.action(async (opts) => {
|
|
1033
|
+
const body = JSON.parse(opts.json);
|
|
1034
|
+
const res = await requireClient().updateTierRule(opts.team, opts.id, body);
|
|
1035
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1036
|
+
});
|
|
1037
|
+
intel
|
|
1038
|
+
.command("tier-rules-delete")
|
|
1039
|
+
.description("DELETE .../subreddit-intelligence/tier-rules/:id")
|
|
1040
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1041
|
+
.requiredOption("--id <uuid>", "Tier rule UUID")
|
|
1042
|
+
.action(async (opts) => {
|
|
1043
|
+
const res = await requireClient().deleteTierRule(opts.team, opts.id);
|
|
1044
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1045
|
+
});
|
|
1046
|
+
intel
|
|
1047
|
+
.command("runs-list")
|
|
1048
|
+
.description("GET .../subreddit-intelligence/runs")
|
|
1049
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1050
|
+
.option("--dimension <d>", "industry|keywords|tier")
|
|
1051
|
+
.option("--status <s>", "queued|running|succeeded|failed")
|
|
1052
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
1053
|
+
.option("--offset <n>", "offset", "0")
|
|
1054
|
+
.action(async (opts) => {
|
|
1055
|
+
const res = await requireClient().listIntelRuns(opts.team, {
|
|
1056
|
+
dimension: opts.dimension,
|
|
1057
|
+
status: opts.status,
|
|
1058
|
+
limit: Number(opts.limit),
|
|
1059
|
+
offset: Number(opts.offset),
|
|
1060
|
+
});
|
|
1061
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1062
|
+
});
|
|
1063
|
+
intel
|
|
1064
|
+
.command("kol-profiles-list")
|
|
1065
|
+
.description("GET .../subreddit-intelligence/kol-profiles")
|
|
1066
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1067
|
+
.option("--platform <p>", "reddit")
|
|
1068
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
1069
|
+
.option("--offset <n>", "offset", "0")
|
|
1070
|
+
.action(async (opts) => {
|
|
1071
|
+
const res = await requireClient().listKolProfiles(opts.team, {
|
|
1072
|
+
platform: opts.platform,
|
|
1073
|
+
limit: Number(opts.limit),
|
|
1074
|
+
offset: Number(opts.offset),
|
|
1075
|
+
});
|
|
1076
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1077
|
+
});
|
|
1078
|
+
intel
|
|
1079
|
+
.command("kol-profiles-get")
|
|
1080
|
+
.description("GET .../subreddit-intelligence/kol-profiles/:id")
|
|
1081
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1082
|
+
.requiredOption("--id <uuid>", "KOL profile UUID")
|
|
1083
|
+
.action(async (opts) => {
|
|
1084
|
+
const res = await requireClient().getKolProfile(opts.team, opts.id);
|
|
1085
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1086
|
+
});
|
|
1087
|
+
intel
|
|
1088
|
+
.command("fetch-by-industry")
|
|
1089
|
+
.description("POST .../subreddit-intelligence/hot-posts/fetch-by-industry")
|
|
1090
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1091
|
+
.requiredOption("-j, --json <json>", "fetch body")
|
|
1092
|
+
.action(async (opts) => {
|
|
1093
|
+
const body = JSON.parse(opts.json);
|
|
1094
|
+
const res = await requireClient().fetchHotPostsByIndustry(opts.team, body);
|
|
1095
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1096
|
+
});
|
|
1097
|
+
intel
|
|
1098
|
+
.command("fetch-by-tier")
|
|
1099
|
+
.description("POST .../subreddit-intelligence/hot-posts/fetch-by-tier")
|
|
1100
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1101
|
+
.requiredOption("-j, --json <json>", "fetch body")
|
|
1102
|
+
.action(async (opts) => {
|
|
1103
|
+
const body = JSON.parse(opts.json);
|
|
1104
|
+
const res = await requireClient().fetchHotPostsByTier(opts.team, body);
|
|
1105
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1106
|
+
});
|
|
1107
|
+
intel
|
|
1108
|
+
.command("fetch-by-keywords")
|
|
1109
|
+
.description("POST .../subreddit-intelligence/insights/fetch-by-keywords")
|
|
1110
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1111
|
+
.requiredOption("-j, --json <json>", "fetch body")
|
|
1112
|
+
.action(async (opts) => {
|
|
1113
|
+
const body = JSON.parse(opts.json);
|
|
1114
|
+
const res = await requireClient().fetchInsightsByKeywords(opts.team, body);
|
|
1115
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1116
|
+
});
|
|
1117
|
+
intel
|
|
1118
|
+
.command("brand-mention-radar")
|
|
1119
|
+
.description("POST .../subreddit-intelligence/insights/brand-mention-radar")
|
|
1120
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1121
|
+
.requiredOption("-j, --json <json>", "{ keywords, minScore?, minComments? }")
|
|
1122
|
+
.action(async (opts) => {
|
|
1123
|
+
const body = JSON.parse(opts.json);
|
|
1124
|
+
const res = await requireClient().getBrandMentionRadar(opts.team, body);
|
|
1125
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1126
|
+
});
|
|
1127
|
+
intel
|
|
1128
|
+
.command("opportunity-map")
|
|
1129
|
+
.description("POST .../subreddit-intelligence/insights/opportunity-map")
|
|
1130
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1131
|
+
.requiredOption("-j, --json <json>", "{ keywords, minScore?, minComments? }")
|
|
1132
|
+
.action(async (opts) => {
|
|
1133
|
+
const body = JSON.parse(opts.json);
|
|
1134
|
+
const res = await requireClient().getOpportunityMap(opts.team, body);
|
|
1135
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1136
|
+
});
|
|
1137
|
+
intel
|
|
1138
|
+
.command("sov")
|
|
1139
|
+
.description("POST .../subreddit-intelligence/insights/sov")
|
|
1140
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1141
|
+
.requiredOption("-j, --json <json>", "{ brandKeywords, competitorKeywords, minScore?, minComments? }")
|
|
1142
|
+
.action(async (opts) => {
|
|
1143
|
+
const body = JSON.parse(opts.json);
|
|
1144
|
+
const res = await requireClient().getInsightsSov(opts.team, body);
|
|
1145
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1146
|
+
});
|
|
1147
|
+
intel
|
|
1148
|
+
.command("sentiment-intent")
|
|
1149
|
+
.description("GET .../subreddit-intelligence/insights/sentiment-intent")
|
|
1150
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1151
|
+
.action(async (opts) => {
|
|
1152
|
+
const res = await requireClient().getSentimentIntent(opts.team);
|
|
1153
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1154
|
+
});
|
|
1155
|
+
intel
|
|
1156
|
+
.command("campaign-lift")
|
|
1157
|
+
.description("POST .../subreddit-intelligence/insights/campaign-lift")
|
|
1158
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1159
|
+
.requiredOption("-j, --json <json>", "{ keywords, campaignStartAt, campaignEndAt, windowDays?, minScore?, minComments? }")
|
|
1160
|
+
.action(async (opts) => {
|
|
1161
|
+
const body = JSON.parse(opts.json);
|
|
1162
|
+
const res = await requireClient().getCampaignLift(opts.team, body);
|
|
1163
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1164
|
+
});
|
|
1165
|
+
intel
|
|
1166
|
+
.command("snapshot-latest")
|
|
1167
|
+
.description("GET .../subreddit-intelligence/insights/snapshot-latest")
|
|
1168
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1169
|
+
.action(async (opts) => {
|
|
1170
|
+
const res = await requireClient().getLatestInsightSnapshot(opts.team);
|
|
1171
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1172
|
+
});
|
|
1173
|
+
intel
|
|
1174
|
+
.command("snapshot-save")
|
|
1175
|
+
.description("POST .../subreddit-intelligence/insights/snapshot")
|
|
1176
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1177
|
+
.requiredOption("-j, --json <json>", "{ payload: { ... } }")
|
|
1178
|
+
.action(async (opts) => {
|
|
1179
|
+
const body = JSON.parse(opts.json);
|
|
1180
|
+
const res = await requireClient().saveInsightSnapshot(opts.team, body);
|
|
1181
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1182
|
+
});
|
|
906
1183
|
// --- users ---
|
|
907
1184
|
const usersCmd = program.command("users").description("团队成员管理");
|
|
908
1185
|
usersCmd
|
|
@@ -910,8 +1187,28 @@ usersCmd
|
|
|
910
1187
|
.description("GET /users")
|
|
911
1188
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
912
1189
|
.action(async (opts) => {
|
|
913
|
-
|
|
914
|
-
|
|
1190
|
+
await withPermissionGate({
|
|
1191
|
+
command: "users list",
|
|
1192
|
+
resource: "systemMember",
|
|
1193
|
+
action: "list",
|
|
1194
|
+
teamId: opts.team,
|
|
1195
|
+
}, async () => {
|
|
1196
|
+
const res = await requireClient().listUsers(opts.team);
|
|
1197
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1198
|
+
});
|
|
1199
|
+
});
|
|
1200
|
+
usersCmd
|
|
1201
|
+
.command("system-list")
|
|
1202
|
+
.description("GET /v1/system/users")
|
|
1203
|
+
.action(async () => {
|
|
1204
|
+
await withPermissionGate({
|
|
1205
|
+
command: "users system-list",
|
|
1206
|
+
resource: "systemMember",
|
|
1207
|
+
action: "list",
|
|
1208
|
+
}, async () => {
|
|
1209
|
+
const res = await requireClient().listSystemUsers();
|
|
1210
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1211
|
+
});
|
|
915
1212
|
});
|
|
916
1213
|
usersCmd
|
|
917
1214
|
.command("create")
|
|
@@ -919,9 +1216,40 @@ usersCmd
|
|
|
919
1216
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
920
1217
|
.requiredOption("-j, --json <json>", "{ email, password, role? }")
|
|
921
1218
|
.action(async (opts) => {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1219
|
+
await withPermissionGate({
|
|
1220
|
+
command: "users create",
|
|
1221
|
+
resource: "systemMember",
|
|
1222
|
+
action: "create",
|
|
1223
|
+
teamId: opts.team,
|
|
1224
|
+
}, async () => {
|
|
1225
|
+
const body = JSON.parse(opts.json);
|
|
1226
|
+
const res = await requireClient().createUser(opts.team, body);
|
|
1227
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
usersCmd
|
|
1231
|
+
.command("system-create")
|
|
1232
|
+
.description("POST /v1/system/users")
|
|
1233
|
+
.requiredOption("-j, --json <json>", "{ email, name, password?, role? }")
|
|
1234
|
+
.option("--dry-run", "预览", false)
|
|
1235
|
+
.option("--apply", "执行写入", false)
|
|
1236
|
+
.action(async (opts) => {
|
|
1237
|
+
await withPermissionGate({
|
|
1238
|
+
command: "users system-create",
|
|
1239
|
+
resource: "systemMember",
|
|
1240
|
+
action: "create",
|
|
1241
|
+
}, async () => {
|
|
1242
|
+
const body = JSON.parse(opts.json);
|
|
1243
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1244
|
+
command: "users system-create",
|
|
1245
|
+
danger: "write",
|
|
1246
|
+
summary: { email: body.email, name: body.name },
|
|
1247
|
+
})) {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const res = await requireClient().createSystemUser(body);
|
|
1251
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1252
|
+
});
|
|
925
1253
|
});
|
|
926
1254
|
// --- brand-members ---
|
|
927
1255
|
const brandMembersCmd = program.command("brand-members").description("品牌成员");
|
|
@@ -930,17 +1258,63 @@ brandMembersCmd
|
|
|
930
1258
|
.description("GET /system/brand-members (preferred)")
|
|
931
1259
|
.option("--user <uuid>", "userId 过滤")
|
|
932
1260
|
.action(async (opts) => {
|
|
933
|
-
|
|
934
|
-
|
|
1261
|
+
await withPermissionGate({
|
|
1262
|
+
command: "brand-members system-list",
|
|
1263
|
+
resource: "systemBrand",
|
|
1264
|
+
action: "list",
|
|
1265
|
+
}, async () => {
|
|
1266
|
+
const res = await requireClient().listSystemBrandMembers({
|
|
1267
|
+
userId: opts.user,
|
|
1268
|
+
});
|
|
1269
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1270
|
+
});
|
|
935
1271
|
});
|
|
936
1272
|
brandMembersCmd
|
|
937
1273
|
.command("system-create")
|
|
938
1274
|
.description("POST /system/brand-members (preferred)")
|
|
939
1275
|
.requiredOption("-j, --json <json>", "{ brandId, userId, role? }")
|
|
940
|
-
.
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1276
|
+
.option("--dry-run", "预览", false)
|
|
1277
|
+
.option("--apply", "执行写入", false)
|
|
1278
|
+
.action(async (opts) => {
|
|
1279
|
+
await withPermissionGate({
|
|
1280
|
+
command: "brand-members system-create",
|
|
1281
|
+
resource: "brandMember",
|
|
1282
|
+
action: "create",
|
|
1283
|
+
}, async () => {
|
|
1284
|
+
const body = JSON.parse(opts.json);
|
|
1285
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1286
|
+
command: "brand-members system-create",
|
|
1287
|
+
danger: "write",
|
|
1288
|
+
summary: body,
|
|
1289
|
+
})) {
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
const res = await requireClient().createSystemBrandMember(body);
|
|
1293
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
brandMembersCmd
|
|
1297
|
+
.command("system-remove")
|
|
1298
|
+
.description("DELETE /system/brand-members/:memberId")
|
|
1299
|
+
.requiredOption("--id <memberId>", "BrandMember UUID")
|
|
1300
|
+
.option("--dry-run", "预览", false)
|
|
1301
|
+
.option("--apply", "执行写入", false)
|
|
1302
|
+
.action(async (opts) => {
|
|
1303
|
+
await withPermissionGate({
|
|
1304
|
+
command: "brand-members system-remove",
|
|
1305
|
+
resource: "brandMember",
|
|
1306
|
+
action: "delete",
|
|
1307
|
+
}, async () => {
|
|
1308
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1309
|
+
command: "brand-members system-remove",
|
|
1310
|
+
danger: "delete",
|
|
1311
|
+
summary: { memberId: opts.id },
|
|
1312
|
+
})) {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
await requireClient().deleteSystemBrandMember(opts.id);
|
|
1316
|
+
console.log("OK");
|
|
1317
|
+
});
|
|
944
1318
|
});
|
|
945
1319
|
brandMembersCmd
|
|
946
1320
|
.command("list")
|
|
@@ -948,18 +1322,43 @@ brandMembersCmd
|
|
|
948
1322
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
949
1323
|
.option("--user <uuid>", "userId 过滤")
|
|
950
1324
|
.action(async (opts) => {
|
|
951
|
-
|
|
952
|
-
|
|
1325
|
+
await withPermissionGate({
|
|
1326
|
+
command: "brand-members list",
|
|
1327
|
+
resource: "brandMember",
|
|
1328
|
+
action: "list",
|
|
1329
|
+
teamId: opts.team,
|
|
1330
|
+
}, async () => {
|
|
1331
|
+
const res = await requireClient().listBrandMembers(opts.team, {
|
|
1332
|
+
userId: opts.user,
|
|
1333
|
+
});
|
|
1334
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1335
|
+
});
|
|
953
1336
|
});
|
|
954
1337
|
brandMembersCmd
|
|
955
1338
|
.command("create")
|
|
956
1339
|
.description("POST /brand-members")
|
|
957
1340
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
958
1341
|
.requiredOption("-j, --json <json>", "{ brandId, userId, role? }")
|
|
959
|
-
.
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1342
|
+
.option("--dry-run", "预览", false)
|
|
1343
|
+
.option("--apply", "执行写入", false)
|
|
1344
|
+
.action(async (opts) => {
|
|
1345
|
+
await withPermissionGate({
|
|
1346
|
+
command: "brand-members create",
|
|
1347
|
+
resource: "brandMember",
|
|
1348
|
+
action: "create",
|
|
1349
|
+
teamId: opts.team,
|
|
1350
|
+
}, async () => {
|
|
1351
|
+
const body = JSON.parse(opts.json);
|
|
1352
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1353
|
+
command: "brand-members create",
|
|
1354
|
+
danger: "write",
|
|
1355
|
+
summary: { teamId: opts.team, ...body },
|
|
1356
|
+
})) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
const res = await requireClient().createBrandMember(opts.team, body);
|
|
1360
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1361
|
+
});
|
|
963
1362
|
});
|
|
964
1363
|
// --- notification-channels ---
|
|
965
1364
|
const notifChannels = program
|
|
@@ -1023,56 +1422,147 @@ apiKeys
|
|
|
1023
1422
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1024
1423
|
.option("-n, --limit <n>", "limit", "50")
|
|
1025
1424
|
.action(async (opts) => {
|
|
1026
|
-
|
|
1027
|
-
|
|
1425
|
+
await withPermissionGate({
|
|
1426
|
+
command: "api-keys list",
|
|
1427
|
+
resource: "apiKey",
|
|
1428
|
+
action: "list",
|
|
1429
|
+
teamId: opts.team,
|
|
1430
|
+
}, async () => {
|
|
1431
|
+
const res = await requireClient().listApiKeys(opts.team, {
|
|
1432
|
+
limit: Number(opts.limit),
|
|
1433
|
+
});
|
|
1434
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1435
|
+
});
|
|
1028
1436
|
});
|
|
1029
1437
|
apiKeys
|
|
1030
1438
|
.command("create")
|
|
1031
1439
|
.description("POST /api-keys")
|
|
1032
1440
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1033
1441
|
.requiredOption("-j, --json <json>", "{ name, role, visibleCampaignIds? }")
|
|
1034
|
-
.
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1442
|
+
.option("--dry-run", "预览", false)
|
|
1443
|
+
.option("--apply", "执行写入", false)
|
|
1444
|
+
.action(async (opts) => {
|
|
1445
|
+
await withPermissionGate({
|
|
1446
|
+
command: "api-keys create",
|
|
1447
|
+
resource: "apiKey",
|
|
1448
|
+
action: "create",
|
|
1449
|
+
teamId: opts.team,
|
|
1450
|
+
}, async () => {
|
|
1451
|
+
const body = JSON.parse(opts.json);
|
|
1452
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1453
|
+
command: "api-keys create",
|
|
1454
|
+
danger: "secret",
|
|
1455
|
+
summary: { teamId: opts.team, ...body },
|
|
1456
|
+
})) {
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
const res = await requireClient().createApiKey(opts.team, body);
|
|
1460
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1461
|
+
});
|
|
1038
1462
|
});
|
|
1039
1463
|
apiKeys
|
|
1040
1464
|
.command("delete")
|
|
1041
1465
|
.description("DELETE /api-keys/:id")
|
|
1042
1466
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1043
1467
|
.requiredOption("--key <uuid>", "API Key UUID")
|
|
1044
|
-
.
|
|
1045
|
-
|
|
1046
|
-
|
|
1468
|
+
.option("--dry-run", "预览", false)
|
|
1469
|
+
.option("--apply", "执行写入", false)
|
|
1470
|
+
.action(async (opts) => {
|
|
1471
|
+
await withPermissionGate({
|
|
1472
|
+
command: "api-keys delete",
|
|
1473
|
+
resource: "apiKey",
|
|
1474
|
+
action: "delete",
|
|
1475
|
+
teamId: opts.team,
|
|
1476
|
+
}, async () => {
|
|
1477
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1478
|
+
command: "api-keys delete",
|
|
1479
|
+
danger: "delete",
|
|
1480
|
+
summary: { teamId: opts.team, keyId: opts.key },
|
|
1481
|
+
})) {
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
await requireClient().deleteApiKey(opts.team, opts.key);
|
|
1485
|
+
console.log("OK");
|
|
1486
|
+
});
|
|
1047
1487
|
});
|
|
1048
1488
|
apiKeys
|
|
1049
1489
|
.command("rotate")
|
|
1050
1490
|
.description("POST /api-keys/:id/rotate")
|
|
1051
1491
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1052
1492
|
.requiredOption("--key <uuid>", "API Key UUID")
|
|
1053
|
-
.
|
|
1054
|
-
|
|
1055
|
-
|
|
1493
|
+
.option("--dry-run", "预览", false)
|
|
1494
|
+
.option("--apply", "执行写入", false)
|
|
1495
|
+
.action(async (opts) => {
|
|
1496
|
+
await withPermissionGate({
|
|
1497
|
+
command: "api-keys rotate",
|
|
1498
|
+
resource: "apiKey",
|
|
1499
|
+
action: "update",
|
|
1500
|
+
teamId: opts.team,
|
|
1501
|
+
}, async () => {
|
|
1502
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1503
|
+
command: "api-keys rotate",
|
|
1504
|
+
danger: "secret",
|
|
1505
|
+
summary: { teamId: opts.team, keyId: opts.key },
|
|
1506
|
+
})) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
const res = await requireClient().rotateApiKey(opts.team, opts.key);
|
|
1510
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1511
|
+
});
|
|
1056
1512
|
});
|
|
1057
1513
|
apiKeys
|
|
1058
1514
|
.command("batch-revoke")
|
|
1059
1515
|
.description("POST /api-keys/batch/revoke")
|
|
1060
1516
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1061
|
-
.requiredOption("-j, --json <json>", '{ "
|
|
1062
|
-
.
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1517
|
+
.requiredOption("-j, --json <json>", '{ "apiKeyIds": ["uuid1","uuid2"] }')
|
|
1518
|
+
.option("--dry-run", "预览", false)
|
|
1519
|
+
.option("--apply", "执行写入", false)
|
|
1520
|
+
.action(async (opts) => {
|
|
1521
|
+
await withPermissionGate({
|
|
1522
|
+
command: "api-keys batch-revoke",
|
|
1523
|
+
resource: "apiKey",
|
|
1524
|
+
action: "delete",
|
|
1525
|
+
teamId: opts.team,
|
|
1526
|
+
}, async () => {
|
|
1527
|
+
const body = JSON.parse(opts.json);
|
|
1528
|
+
const apiKeyIds = body.apiKeyIds ?? body.ids ?? [];
|
|
1529
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1530
|
+
command: "api-keys batch-revoke",
|
|
1531
|
+
danger: "delete",
|
|
1532
|
+
summary: { teamId: opts.team, apiKeyIds },
|
|
1533
|
+
})) {
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
const res = await requireClient().batchRevokeApiKeys(opts.team, apiKeyIds);
|
|
1537
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1538
|
+
});
|
|
1066
1539
|
});
|
|
1067
1540
|
apiKeys
|
|
1068
1541
|
.command("batch-rotate")
|
|
1069
1542
|
.description("POST /api-keys/batch/rotate")
|
|
1070
1543
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1071
|
-
.requiredOption("-j, --json <json>", '{ "
|
|
1072
|
-
.
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1544
|
+
.requiredOption("-j, --json <json>", '{ "apiKeyIds": ["uuid1","uuid2"] }')
|
|
1545
|
+
.option("--dry-run", "预览", false)
|
|
1546
|
+
.option("--apply", "执行写入", false)
|
|
1547
|
+
.action(async (opts) => {
|
|
1548
|
+
await withPermissionGate({
|
|
1549
|
+
command: "api-keys batch-rotate",
|
|
1550
|
+
resource: "apiKey",
|
|
1551
|
+
action: "update",
|
|
1552
|
+
teamId: opts.team,
|
|
1553
|
+
}, async () => {
|
|
1554
|
+
const body = JSON.parse(opts.json);
|
|
1555
|
+
const apiKeyIds = body.apiKeyIds ?? body.ids ?? [];
|
|
1556
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1557
|
+
command: "api-keys batch-rotate",
|
|
1558
|
+
danger: "secret",
|
|
1559
|
+
summary: { teamId: opts.team, apiKeyIds },
|
|
1560
|
+
})) {
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
const res = await requireClient().batchRotateApiKeys(opts.team, apiKeyIds);
|
|
1564
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1565
|
+
});
|
|
1076
1566
|
});
|
|
1077
1567
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1078
1568
|
// Group C: scattered endpoint additions
|
|
@@ -1127,9 +1617,16 @@ program
|
|
|
1127
1617
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1128
1618
|
.requiredOption("-j, --json <json>", "权限矩阵更新 body")
|
|
1129
1619
|
.action(async (opts) => {
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1620
|
+
await withPermissionGate({
|
|
1621
|
+
command: "permissions-update",
|
|
1622
|
+
resource: "permissionMatrix",
|
|
1623
|
+
action: "update",
|
|
1624
|
+
teamId: opts.team,
|
|
1625
|
+
}, async () => {
|
|
1626
|
+
const body = JSON.parse(opts.json);
|
|
1627
|
+
const res = await requireClient().updatePermissionsMatrix(opts.team, body);
|
|
1628
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1629
|
+
});
|
|
1133
1630
|
});
|
|
1134
1631
|
graph
|
|
1135
1632
|
.command("drilldown")
|
|
@@ -1144,6 +1641,114 @@ graph
|
|
|
1144
1641
|
});
|
|
1145
1642
|
console.log(JSON.stringify(res, null, 2));
|
|
1146
1643
|
});
|
|
1644
|
+
graph
|
|
1645
|
+
.command("v2-ego")
|
|
1646
|
+
.description("GET /graph/v2/ego")
|
|
1647
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1648
|
+
.option("--node-id <uuid>", "graph nodeId")
|
|
1649
|
+
.option("--node-ref <id>", "nodeRefId (e.g. account UUID)")
|
|
1650
|
+
.option("--node-type <type>", "account|team|campaign")
|
|
1651
|
+
.option("--relation-type <type>", "relationType filter")
|
|
1652
|
+
.option("--edge-kind <kind>", "edgeKind filter")
|
|
1653
|
+
.option("-n, --limit <n>", "limit", "100")
|
|
1654
|
+
.action(async (opts) => {
|
|
1655
|
+
const res = await requireClient().getGraphV2Ego(opts.team, {
|
|
1656
|
+
nodeId: opts.nodeId,
|
|
1657
|
+
nodeRefId: opts.nodeRef,
|
|
1658
|
+
nodeType: opts.nodeType,
|
|
1659
|
+
relationType: opts.relationType,
|
|
1660
|
+
edgeKind: opts.edgeKind,
|
|
1661
|
+
limit: Number(opts.limit),
|
|
1662
|
+
});
|
|
1663
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1664
|
+
});
|
|
1665
|
+
graph
|
|
1666
|
+
.command("v2-timeline")
|
|
1667
|
+
.description("GET /graph/v2/timeline")
|
|
1668
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1669
|
+
.option("--node-id <uuid>", "graph nodeId")
|
|
1670
|
+
.option("--node-ref <id>", "nodeRefId")
|
|
1671
|
+
.option("--node-type <type>", "account|team|campaign")
|
|
1672
|
+
.option("--from <iso>", "from ISO time")
|
|
1673
|
+
.option("--to <iso>", "to ISO time")
|
|
1674
|
+
.option("-n, --limit <n>", "limit", "100")
|
|
1675
|
+
.action(async (opts) => {
|
|
1676
|
+
const res = await requireClient().getGraphV2Timeline(opts.team, {
|
|
1677
|
+
nodeId: opts.nodeId,
|
|
1678
|
+
nodeRefId: opts.nodeRef,
|
|
1679
|
+
nodeType: opts.nodeType,
|
|
1680
|
+
from: opts.from,
|
|
1681
|
+
to: opts.to,
|
|
1682
|
+
limit: Number(opts.limit),
|
|
1683
|
+
});
|
|
1684
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1685
|
+
});
|
|
1686
|
+
graph
|
|
1687
|
+
.command("v2-explain")
|
|
1688
|
+
.description("GET /graph/v2/explain/:edgeId")
|
|
1689
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1690
|
+
.requiredOption("--edge-id <id>", "edge UUID")
|
|
1691
|
+
.action(async (opts) => {
|
|
1692
|
+
const res = await requireClient().getGraphV2Explain(opts.team, opts.edgeId);
|
|
1693
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1694
|
+
});
|
|
1695
|
+
graph
|
|
1696
|
+
.command("v2-path")
|
|
1697
|
+
.description("GET /graph/v2/path")
|
|
1698
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1699
|
+
.option("--source-id <uuid>", "source nodeId")
|
|
1700
|
+
.option("--source-ref <id>", "source nodeRefId")
|
|
1701
|
+
.option("--source-type <type>", "source nodeType")
|
|
1702
|
+
.option("--target-id <uuid>", "target nodeId")
|
|
1703
|
+
.option("--target-ref <id>", "target nodeRefId")
|
|
1704
|
+
.option("--target-type <type>", "target nodeType")
|
|
1705
|
+
.option("--max-depth <n>", "maxDepth", "4")
|
|
1706
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
1707
|
+
.action(async (opts) => {
|
|
1708
|
+
const res = await requireClient().getGraphV2Path(opts.team, {
|
|
1709
|
+
sourceNodeId: opts.sourceId,
|
|
1710
|
+
sourceNodeRefId: opts.sourceRef,
|
|
1711
|
+
sourceNodeType: opts.sourceType,
|
|
1712
|
+
targetNodeId: opts.targetId,
|
|
1713
|
+
targetNodeRefId: opts.targetRef,
|
|
1714
|
+
targetNodeType: opts.targetType,
|
|
1715
|
+
maxDepth: Number(opts.maxDepth),
|
|
1716
|
+
limit: Number(opts.limit),
|
|
1717
|
+
});
|
|
1718
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1719
|
+
});
|
|
1720
|
+
graph
|
|
1721
|
+
.command("v2-clusters")
|
|
1722
|
+
.description("GET /graph/v2/clusters")
|
|
1723
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1724
|
+
.option("--scope-ref <id>", "scopeNodeRefId")
|
|
1725
|
+
.option("--scope-type <type>", "scopeNodeType", "account")
|
|
1726
|
+
.option("--min-risk <n>", "minRiskScore", "60")
|
|
1727
|
+
.option("-n, --limit <n>", "limit", "100")
|
|
1728
|
+
.action(async (opts) => {
|
|
1729
|
+
const res = await requireClient().getGraphV2Clusters(opts.team, {
|
|
1730
|
+
scopeNodeRefId: opts.scopeRef,
|
|
1731
|
+
scopeNodeType: opts.scopeType,
|
|
1732
|
+
minRiskScore: Number(opts.minRisk),
|
|
1733
|
+
limit: Number(opts.limit),
|
|
1734
|
+
});
|
|
1735
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1736
|
+
});
|
|
1737
|
+
graph
|
|
1738
|
+
.command("v2-impact")
|
|
1739
|
+
.description("GET /graph/v2/impact")
|
|
1740
|
+
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1741
|
+
.option("--campaign-ref <id>", "campaignNodeRefId")
|
|
1742
|
+
.option("--min-reuse <n>", "minReuseCount", "2")
|
|
1743
|
+
.option("-n, --limit <n>", "limit", "100")
|
|
1744
|
+
.action(async (opts) => {
|
|
1745
|
+
const res = await requireClient().getGraphV2Impact(opts.team, {
|
|
1746
|
+
campaignNodeRefId: opts.campaignRef,
|
|
1747
|
+
minReuseCount: Number(opts.minReuse),
|
|
1748
|
+
limit: Number(opts.limit),
|
|
1749
|
+
});
|
|
1750
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1751
|
+
});
|
|
1147
1752
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1148
1753
|
// Group D: add filter params to existing list commands
|
|
1149
1754
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1380,9 +1985,25 @@ brandMembersCmd
|
|
|
1380
1985
|
.description("DELETE /brand-members/:memberId")
|
|
1381
1986
|
.requiredOption("-t, --team <teamId>", "Team UUID")
|
|
1382
1987
|
.requiredOption("-m, --member <memberId>", "BrandMember UUID")
|
|
1383
|
-
.
|
|
1384
|
-
|
|
1385
|
-
|
|
1988
|
+
.option("--dry-run", "预览", false)
|
|
1989
|
+
.option("--apply", "执行写入", false)
|
|
1990
|
+
.action(async (opts) => {
|
|
1991
|
+
await withPermissionGate({
|
|
1992
|
+
command: "brand-members remove",
|
|
1993
|
+
resource: "brandMember",
|
|
1994
|
+
action: "delete",
|
|
1995
|
+
teamId: opts.team,
|
|
1996
|
+
}, async () => {
|
|
1997
|
+
if (!assertApplyOrDryRun(opts, {
|
|
1998
|
+
command: "brand-members remove",
|
|
1999
|
+
danger: "delete",
|
|
2000
|
+
summary: { teamId: opts.team, memberId: opts.member },
|
|
2001
|
+
})) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
const res = await requireClient().deleteBrandMember(opts.team, opts.member);
|
|
2005
|
+
console.log(JSON.stringify(res, null, 2));
|
|
2006
|
+
});
|
|
1386
2007
|
});
|
|
1387
2008
|
// Only parse when run directly (not when imported for testing)
|
|
1388
2009
|
if (!process.env["VITEST"]) {
|