@jclvsh/iris 0.2.0
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/README.md +78 -0
- package/dist/cli-utils.d.ts +4 -0
- package/dist/cli-utils.js +31 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +43 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.js +100 -0
- package/dist/commands/ai.d.ts +3 -0
- package/dist/commands/ai.js +97 -0
- package/dist/commands/analytics.d.ts +3 -0
- package/dist/commands/analytics.js +75 -0
- package/dist/commands/billing.d.ts +3 -0
- package/dist/commands/billing.js +16 -0
- package/dist/commands/campaigns.d.ts +3 -0
- package/dist/commands/campaigns.js +123 -0
- package/dist/commands/channels.d.ts +3 -0
- package/dist/commands/channels.js +53 -0
- package/dist/commands/contacts.d.ts +3 -0
- package/dist/commands/contacts.js +120 -0
- package/dist/commands/conversations.d.ts +3 -0
- package/dist/commands/conversations.js +71 -0
- package/dist/commands/credits.d.ts +10 -0
- package/dist/commands/credits.js +38 -0
- package/dist/commands/discovery.d.ts +3 -0
- package/dist/commands/discovery.js +76 -0
- package/dist/commands/keys.d.ts +3 -0
- package/dist/commands/keys.js +70 -0
- package/dist/commands/messages.d.ts +3 -0
- package/dist/commands/messages.js +110 -0
- package/dist/commands/notifications.d.ts +3 -0
- package/dist/commands/notifications.js +66 -0
- package/dist/commands/webhooks.d.ts +3 -0
- package/dist/commands/webhooks.js +122 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +37 -0
- package/dist/tools/agent-credits.d.ts +10 -0
- package/dist/tools/agent-credits.js +43 -0
- package/dist/tools/ai.d.ts +3 -0
- package/dist/tools/ai.js +81 -0
- package/dist/tools/analytics.d.ts +3 -0
- package/dist/tools/analytics.js +84 -0
- package/dist/tools/billing.d.ts +3 -0
- package/dist/tools/billing.js +14 -0
- package/dist/tools/campaigns.d.ts +3 -0
- package/dist/tools/campaigns.js +211 -0
- package/dist/tools/channels.d.ts +3 -0
- package/dist/tools/channels.js +49 -0
- package/dist/tools/contacts.d.ts +3 -0
- package/dist/tools/contacts.js +149 -0
- package/dist/tools/conversations.d.ts +3 -0
- package/dist/tools/conversations.js +84 -0
- package/dist/tools/discovery.d.ts +3 -0
- package/dist/tools/discovery.js +62 -0
- package/dist/tools/keys.d.ts +3 -0
- package/dist/tools/keys.js +92 -0
- package/dist/tools/messages.d.ts +3 -0
- package/dist/tools/messages.js +99 -0
- package/dist/tools/notifications.d.ts +3 -0
- package/dist/tools/notifications.js +64 -0
- package/dist/tools/webhooks.d.ts +3 -0
- package/dist/tools/webhooks.js +161 -0
- package/dist/types.d.ts +256 -0
- package/dist/types.js +2 -0
- package/package.json +33 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat } from "../cli-utils.js";
|
|
2
|
+
export function registerContactCommands(program, client) {
|
|
3
|
+
const contacts = program.command("contacts").alias("ct").description("manage contacts");
|
|
4
|
+
contacts
|
|
5
|
+
.command("list")
|
|
6
|
+
.description("list contacts with pagination")
|
|
7
|
+
.option("-p, --page <n>", "page number", "1")
|
|
8
|
+
.option("-s, --page-size <n>", "items per page (max 100)", "50")
|
|
9
|
+
.option("--campaign-id <id>", "filter by campaign")
|
|
10
|
+
.option("--search <text>", "search by name, email, or company")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
try {
|
|
13
|
+
const params = {};
|
|
14
|
+
if (opts.page)
|
|
15
|
+
params.page = opts.page;
|
|
16
|
+
if (opts.pageSize)
|
|
17
|
+
params.page_size = opts.pageSize;
|
|
18
|
+
if (opts.campaignId)
|
|
19
|
+
params.campaign_id = opts.campaignId;
|
|
20
|
+
if (opts.search)
|
|
21
|
+
params.search = opts.search;
|
|
22
|
+
const result = await client.get("/contacts", params);
|
|
23
|
+
formatOutput(result, getFormat(program.opts()));
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
handleError(error);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
contacts
|
|
30
|
+
.command("get <id>")
|
|
31
|
+
.description("get a contact by ID")
|
|
32
|
+
.action(async (id) => {
|
|
33
|
+
try {
|
|
34
|
+
const result = await client.get(`/contacts/${id}`);
|
|
35
|
+
formatOutput(result, getFormat(program.opts()));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
handleError(error);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
contacts
|
|
42
|
+
.command("create")
|
|
43
|
+
.description("create a new contact")
|
|
44
|
+
.requiredOption("--campaign-id <id>", "campaign ID")
|
|
45
|
+
.requiredOption("-e, --email <email>", "contact email")
|
|
46
|
+
.option("--full-name <name>", "full name")
|
|
47
|
+
.option("--company-name <name>", "company name")
|
|
48
|
+
.option("--phone <phone>", "phone number")
|
|
49
|
+
.action(async (opts) => {
|
|
50
|
+
try {
|
|
51
|
+
const body = {
|
|
52
|
+
campaign_id: opts.campaignId,
|
|
53
|
+
email: opts.email,
|
|
54
|
+
};
|
|
55
|
+
if (opts.fullName)
|
|
56
|
+
body.full_name = opts.fullName;
|
|
57
|
+
if (opts.companyName)
|
|
58
|
+
body.company_name = opts.companyName;
|
|
59
|
+
if (opts.phone)
|
|
60
|
+
body.phone = opts.phone;
|
|
61
|
+
const result = await client.post("/contacts", body);
|
|
62
|
+
formatOutput(result, getFormat(program.opts()));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
handleError(error);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
contacts
|
|
69
|
+
.command("update <id>")
|
|
70
|
+
.description("update a contact")
|
|
71
|
+
.option("-e, --email <email>", "contact email")
|
|
72
|
+
.option("--full-name <name>", "full name")
|
|
73
|
+
.option("--company-name <name>", "company name")
|
|
74
|
+
.option("--phone <phone>", "phone number")
|
|
75
|
+
.option("--status <status>", "contact status")
|
|
76
|
+
.action(async (id, opts) => {
|
|
77
|
+
try {
|
|
78
|
+
const body = {};
|
|
79
|
+
if (opts.email)
|
|
80
|
+
body.email = opts.email;
|
|
81
|
+
if (opts.fullName)
|
|
82
|
+
body.full_name = opts.fullName;
|
|
83
|
+
if (opts.companyName)
|
|
84
|
+
body.company_name = opts.companyName;
|
|
85
|
+
if (opts.phone)
|
|
86
|
+
body.phone = opts.phone;
|
|
87
|
+
if (opts.status)
|
|
88
|
+
body.status = opts.status;
|
|
89
|
+
const result = await client.patch(`/contacts/${id}`, body);
|
|
90
|
+
formatOutput(result, getFormat(program.opts()));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
handleError(error);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
contacts
|
|
97
|
+
.command("delete <id>")
|
|
98
|
+
.description("delete a contact")
|
|
99
|
+
.action(async (id) => {
|
|
100
|
+
try {
|
|
101
|
+
await client.delete(`/contacts/${id}`);
|
|
102
|
+
console.log("contact deleted");
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
handleError(error);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
contacts
|
|
109
|
+
.command("usage")
|
|
110
|
+
.description("get contact usage stats for the current billing period")
|
|
111
|
+
.action(async () => {
|
|
112
|
+
try {
|
|
113
|
+
const result = await client.get("/contacts/usage");
|
|
114
|
+
formatOutput(result, getFormat(program.opts()));
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
handleError(error);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat } from "../cli-utils.js";
|
|
2
|
+
export function registerConversationCommands(program, client) {
|
|
3
|
+
const conversations = program
|
|
4
|
+
.command("conversations")
|
|
5
|
+
.alias("conv")
|
|
6
|
+
.description("manage cross-channel conversations");
|
|
7
|
+
conversations
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("list conversations with pagination")
|
|
10
|
+
.option("-p, --page <n>", "page number", "1")
|
|
11
|
+
.option("-s, --page-size <n>", "items per page (max 100)", "50")
|
|
12
|
+
.option("--status <status>", "filter by status")
|
|
13
|
+
.option("--campaign-id <id>", "filter by campaign")
|
|
14
|
+
.option("--channel <channel>", "filter by channel: email, instagram, twitter, linkedin")
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
try {
|
|
17
|
+
const params = {};
|
|
18
|
+
if (opts.page)
|
|
19
|
+
params.page = opts.page;
|
|
20
|
+
if (opts.pageSize)
|
|
21
|
+
params.page_size = opts.pageSize;
|
|
22
|
+
if (opts.status)
|
|
23
|
+
params.status = opts.status;
|
|
24
|
+
if (opts.campaignId)
|
|
25
|
+
params.campaign_id = opts.campaignId;
|
|
26
|
+
if (opts.channel)
|
|
27
|
+
params.channel = opts.channel;
|
|
28
|
+
const result = await client.get("/conversations", params);
|
|
29
|
+
formatOutput(result, getFormat(program.opts()));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
handleError(error);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
conversations
|
|
36
|
+
.command("get <id>")
|
|
37
|
+
.description("get a conversation by ID")
|
|
38
|
+
.action(async (id) => {
|
|
39
|
+
try {
|
|
40
|
+
const result = await client.get(`/conversations/${id}`);
|
|
41
|
+
formatOutput(result, getFormat(program.opts()));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
handleError(error);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
conversations
|
|
48
|
+
.command("messages <id>")
|
|
49
|
+
.description("list messages in a conversation")
|
|
50
|
+
.action(async (id) => {
|
|
51
|
+
try {
|
|
52
|
+
const result = await client.get(`/conversations/${id}/messages`);
|
|
53
|
+
formatOutput(result, getFormat(program.opts()));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
handleError(error);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
conversations
|
|
60
|
+
.command("read <id>")
|
|
61
|
+
.description("mark a conversation as read")
|
|
62
|
+
.action(async (id) => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await client.post(`/conversations/${id}/read`);
|
|
65
|
+
formatOutput(result, getFormat(program.opts()));
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
handleError(error);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { IrisClient } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Agent credit CLI commands.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: credits apply only to agents authenticating via x402 or MPP. With a
|
|
7
|
+
* regular API key (the typical CLI setup), the balance command returns a
|
|
8
|
+
* message indicating credits are not applicable, and buy returns a 400.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerCreditCommands(program: Command, client: IrisClient): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat } from "../cli-utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* Agent credit CLI commands.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: credits apply only to agents authenticating via x402 or MPP. With a
|
|
6
|
+
* regular API key (the typical CLI setup), the balance command returns a
|
|
7
|
+
* message indicating credits are not applicable, and buy returns a 400.
|
|
8
|
+
*/
|
|
9
|
+
export function registerCreditCommands(program, client) {
|
|
10
|
+
const credits = program
|
|
11
|
+
.command("credits")
|
|
12
|
+
.alias("cr")
|
|
13
|
+
.description("agent credit balance and pack purchase (x402/MPP only)");
|
|
14
|
+
credits
|
|
15
|
+
.command("balance")
|
|
16
|
+
.description("check the agent credit balance")
|
|
17
|
+
.action(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await client.get("/agent/credits");
|
|
20
|
+
formatOutput(result, getFormat(program.opts()));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
handleError(error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
credits
|
|
27
|
+
.command("buy")
|
|
28
|
+
.description("purchase a 5-credit pack via MPP ($12.00 USD). API key users do not need credits.")
|
|
29
|
+
.action(async () => {
|
|
30
|
+
try {
|
|
31
|
+
const result = await client.post("/agent/credits");
|
|
32
|
+
formatOutput(result, getFormat(program.opts()));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
handleError(error);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
|
|
2
|
+
export function registerDiscoveryCommands(program, client) {
|
|
3
|
+
const discovery = program.command("discovery").alias("d").description("discover contacts via external sources");
|
|
4
|
+
discovery
|
|
5
|
+
.command("search")
|
|
6
|
+
.description("run a discovery search")
|
|
7
|
+
.requiredOption("-k, --keywords <list>", "comma-separated search keywords", parseList)
|
|
8
|
+
.option("-l, --location <location>", "location for local search (city, address, etc.)")
|
|
9
|
+
.option("--radius-miles <n>", "search radius in miles (default: 25)")
|
|
10
|
+
.option("--max-results <n>", "max results to return (default: 50, max: 500)")
|
|
11
|
+
.option("--sources <list>", "comma-separated discovery sources", parseList)
|
|
12
|
+
.option("--campaign-id <id>", "associate results with this campaign")
|
|
13
|
+
.option("--profile-type <type>", "target profile type")
|
|
14
|
+
.option("--no-enrich-emails", "skip email enrichment")
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
try {
|
|
17
|
+
const body = { keywords: opts.keywords };
|
|
18
|
+
if (opts.location)
|
|
19
|
+
body.location = opts.location;
|
|
20
|
+
if (opts.radiusMiles)
|
|
21
|
+
body.radius_miles = Number(opts.radiusMiles);
|
|
22
|
+
if (opts.maxResults)
|
|
23
|
+
body.max_results = Number(opts.maxResults);
|
|
24
|
+
if (opts.sources)
|
|
25
|
+
body.sources = opts.sources;
|
|
26
|
+
if (opts.campaignId)
|
|
27
|
+
body.campaign_id = opts.campaignId;
|
|
28
|
+
if (opts.profileType)
|
|
29
|
+
body.profile_type = opts.profileType;
|
|
30
|
+
if (opts.enrichEmails === false)
|
|
31
|
+
body.enrich_emails = false;
|
|
32
|
+
const result = await client.post("/discovery/search", body);
|
|
33
|
+
formatOutput(result, getFormat(program.opts()));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
handleError(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
discovery
|
|
40
|
+
.command("search-campaign")
|
|
41
|
+
.description("run discovery scoped to a campaign's target profiles")
|
|
42
|
+
.requiredOption("--campaign-id <id>", "campaign ID")
|
|
43
|
+
.action(async (opts) => {
|
|
44
|
+
try {
|
|
45
|
+
const result = await client.post("/discovery/search/campaign", { campaign_id: opts.campaignId });
|
|
46
|
+
formatOutput(result, getFormat(program.opts()));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
handleError(error);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
discovery
|
|
53
|
+
.command("sources")
|
|
54
|
+
.description("list available discovery sources")
|
|
55
|
+
.action(async () => {
|
|
56
|
+
try {
|
|
57
|
+
const result = await client.get("/discovery/sources");
|
|
58
|
+
formatOutput(result, getFormat(program.opts()));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
handleError(error);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
discovery
|
|
65
|
+
.command("job <id>")
|
|
66
|
+
.description("get the status of a discovery job")
|
|
67
|
+
.action(async (id) => {
|
|
68
|
+
try {
|
|
69
|
+
const result = await client.get(`/discovery/jobs/${id}`);
|
|
70
|
+
formatOutput(result, getFormat(program.opts()));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
handleError(error);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
|
|
2
|
+
export function registerKeyCommands(program, client) {
|
|
3
|
+
const keys = program.command("keys").alias("k").description("manage API keys");
|
|
4
|
+
keys
|
|
5
|
+
.command("me")
|
|
6
|
+
.description("get current API key info")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const result = await client.get("/keys/me");
|
|
10
|
+
formatOutput(result, getFormat(program.opts()));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
handleError(error);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
keys
|
|
17
|
+
.command("list")
|
|
18
|
+
.description("list API keys (requires admin scope)")
|
|
19
|
+
.action(async () => {
|
|
20
|
+
try {
|
|
21
|
+
const result = await client.get("/keys");
|
|
22
|
+
formatOutput(result, getFormat(program.opts()));
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
handleError(error);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
keys
|
|
29
|
+
.command("create")
|
|
30
|
+
.description("create a new API key (requires admin scope)")
|
|
31
|
+
.requiredOption("-n, --name <name>", "key name")
|
|
32
|
+
.option("--scopes <list>", "comma-separated scopes: campaigns:read, campaigns:write, contacts:read, contacts:write, messages:read, messages:write, conversations:read, conversations:write, discovery:write, ai:write, notifications:read, notifications:write, webhooks:read, webhooks:write", parseList)
|
|
33
|
+
.action(async (opts) => {
|
|
34
|
+
try {
|
|
35
|
+
const body = { name: opts.name };
|
|
36
|
+
if (opts.scopes)
|
|
37
|
+
body.scopes = opts.scopes;
|
|
38
|
+
const result = await client.post("/keys", body);
|
|
39
|
+
formatOutput(result, getFormat(program.opts()));
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
handleError(error);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
keys
|
|
46
|
+
.command("rename <id>")
|
|
47
|
+
.description("rename an API key (requires admin scope)")
|
|
48
|
+
.requiredOption("-n, --name <name>", "new key name")
|
|
49
|
+
.action(async (id, opts) => {
|
|
50
|
+
try {
|
|
51
|
+
const result = await client.patch(`/keys/${id}`, { name: opts.name });
|
|
52
|
+
formatOutput(result, getFormat(program.opts()));
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
handleError(error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
keys
|
|
59
|
+
.command("revoke <id>")
|
|
60
|
+
.description("permanently revoke an API key (requires admin scope)")
|
|
61
|
+
.action(async (id) => {
|
|
62
|
+
try {
|
|
63
|
+
await client.delete(`/keys/${id}`);
|
|
64
|
+
console.log("api key revoked");
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
handleError(error);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat, parseList } from "../cli-utils.js";
|
|
2
|
+
export function registerMessageCommands(program, client) {
|
|
3
|
+
const messages = program.command("messages").alias("m").description("manage AI-generated messages and approval queue");
|
|
4
|
+
messages
|
|
5
|
+
.command("pending")
|
|
6
|
+
.description("list messages pending approval")
|
|
7
|
+
.option("-p, --page <n>", "page number", "1")
|
|
8
|
+
.option("-s, --page-size <n>", "items per page (max 100)", "50")
|
|
9
|
+
.option("--campaign-id <id>", "filter by campaign")
|
|
10
|
+
.option("--channel <channel>", "filter by channel: email, instagram, twitter, linkedin")
|
|
11
|
+
.option("--status <status>", "queue status (default: pending_approval)")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
try {
|
|
14
|
+
const params = {};
|
|
15
|
+
if (opts.page)
|
|
16
|
+
params.page = opts.page;
|
|
17
|
+
if (opts.pageSize)
|
|
18
|
+
params.page_size = opts.pageSize;
|
|
19
|
+
if (opts.campaignId)
|
|
20
|
+
params.campaign_id = opts.campaignId;
|
|
21
|
+
if (opts.channel)
|
|
22
|
+
params.channel = opts.channel;
|
|
23
|
+
if (opts.status)
|
|
24
|
+
params.status = opts.status;
|
|
25
|
+
const result = await client.get("/messages/pending", params);
|
|
26
|
+
formatOutput(result, getFormat(program.opts()));
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
handleError(error);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
messages
|
|
33
|
+
.command("approve <id>")
|
|
34
|
+
.description("approve a single pending message")
|
|
35
|
+
.action(async (id) => {
|
|
36
|
+
try {
|
|
37
|
+
const result = await client.post(`/messages/${id}/approve`);
|
|
38
|
+
formatOutput(result, getFormat(program.opts()));
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
handleError(error);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
messages
|
|
45
|
+
.command("reject <id>")
|
|
46
|
+
.description("reject a single pending message")
|
|
47
|
+
.option("--reason <text>", "rejection reason")
|
|
48
|
+
.action(async (id, opts) => {
|
|
49
|
+
try {
|
|
50
|
+
const body = {};
|
|
51
|
+
if (opts.reason)
|
|
52
|
+
body.reason = opts.reason;
|
|
53
|
+
const result = await client.post(`/messages/${id}/reject`, body);
|
|
54
|
+
formatOutput(result, getFormat(program.opts()));
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
handleError(error);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
messages
|
|
61
|
+
.command("retry <id>")
|
|
62
|
+
.description("retry a failed message send")
|
|
63
|
+
.action(async (id) => {
|
|
64
|
+
try {
|
|
65
|
+
const result = await client.post(`/messages/${id}/retry`);
|
|
66
|
+
formatOutput(result, getFormat(program.opts()));
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
handleError(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
messages
|
|
73
|
+
.command("feedback <id>")
|
|
74
|
+
.description("submit feedback to improve future AI generations")
|
|
75
|
+
.requiredOption("-f, --feedback <text>", "feedback text")
|
|
76
|
+
.option("--approval-queue-id <id>", "approval queue item ID")
|
|
77
|
+
.action(async (id, opts) => {
|
|
78
|
+
try {
|
|
79
|
+
const body = { feedback: opts.feedback };
|
|
80
|
+
if (opts.approvalQueueId)
|
|
81
|
+
body.approval_queue_id = opts.approvalQueueId;
|
|
82
|
+
const result = await client.post(`/messages/${id}/feedback`, body);
|
|
83
|
+
formatOutput(result, getFormat(program.opts()));
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
handleError(error);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
messages
|
|
90
|
+
.command("bulk")
|
|
91
|
+
.description("bulk approve or reject pending messages")
|
|
92
|
+
.requiredOption("-a, --action <action>", "action: approve or reject")
|
|
93
|
+
.requiredOption("--ids <list>", "comma-separated message IDs", parseList)
|
|
94
|
+
.option("--reason <text>", "rejection reason (when action is reject)")
|
|
95
|
+
.action(async (opts) => {
|
|
96
|
+
try {
|
|
97
|
+
const body = {
|
|
98
|
+
action: opts.action,
|
|
99
|
+
ids: opts.ids,
|
|
100
|
+
};
|
|
101
|
+
if (opts.reason)
|
|
102
|
+
body.reason = opts.reason;
|
|
103
|
+
const result = await client.post("/messages/bulk", body);
|
|
104
|
+
formatOutput(result, getFormat(program.opts()));
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
handleError(error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { formatOutput, handleError, getFormat } from "../cli-utils.js";
|
|
2
|
+
export function registerNotificationCommands(program, client) {
|
|
3
|
+
const notifications = program.command("notifications").alias("n").description("manage user notifications");
|
|
4
|
+
notifications
|
|
5
|
+
.command("list")
|
|
6
|
+
.description("list notifications with pagination")
|
|
7
|
+
.option("-p, --page <n>", "page number", "1")
|
|
8
|
+
.option("-s, --page-size <n>", "items per page (max 100)", "50")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
try {
|
|
11
|
+
const params = {};
|
|
12
|
+
if (opts.page)
|
|
13
|
+
params.page = opts.page;
|
|
14
|
+
if (opts.pageSize)
|
|
15
|
+
params.page_size = opts.pageSize;
|
|
16
|
+
const result = await client.get("/notifications", params);
|
|
17
|
+
formatOutput(result, getFormat(program.opts()));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
handleError(error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
notifications
|
|
24
|
+
.command("update <id>")
|
|
25
|
+
.description("update a notification (e.g., mark as read)")
|
|
26
|
+
.option("--read", "mark as read", true)
|
|
27
|
+
.option("--unread", "mark as unread")
|
|
28
|
+
.action(async (id, opts) => {
|
|
29
|
+
try {
|
|
30
|
+
const body = {};
|
|
31
|
+
if (opts.unread)
|
|
32
|
+
body.read = false;
|
|
33
|
+
else if (opts.read)
|
|
34
|
+
body.read = true;
|
|
35
|
+
const result = await client.patch(`/notifications/${id}`, body);
|
|
36
|
+
formatOutput(result, getFormat(program.opts()));
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
handleError(error);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
notifications
|
|
43
|
+
.command("delete <id>")
|
|
44
|
+
.description("delete a notification")
|
|
45
|
+
.action(async (id) => {
|
|
46
|
+
try {
|
|
47
|
+
await client.delete(`/notifications/${id}`);
|
|
48
|
+
console.log("notification deleted");
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
handleError(error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
notifications
|
|
55
|
+
.command("read-all")
|
|
56
|
+
.description("mark all notifications as read")
|
|
57
|
+
.action(async () => {
|
|
58
|
+
try {
|
|
59
|
+
await client.post("/notifications/read-all");
|
|
60
|
+
console.log("all notifications marked as read");
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
handleError(error);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|