@heyamiko/amiko-cli 0.9.5 → 0.9.6-beta.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/dist/index.js +285 -51
- package/package.json +1 -1
- package/skills/SKILL.md +20 -0
package/dist/index.js
CHANGED
|
@@ -5,43 +5,25 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
function __accessProp(key) {
|
|
9
|
-
return this[key];
|
|
10
|
-
}
|
|
11
|
-
var __toESMCache_node;
|
|
12
|
-
var __toESMCache_esm;
|
|
13
8
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
-
var canCache = mod != null && typeof mod === "object";
|
|
15
|
-
if (canCache) {
|
|
16
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
-
var cached = cache.get(mod);
|
|
18
|
-
if (cached)
|
|
19
|
-
return cached;
|
|
20
|
-
}
|
|
21
9
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
10
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
11
|
for (let key of __getOwnPropNames(mod))
|
|
24
12
|
if (!__hasOwnProp.call(to, key))
|
|
25
13
|
__defProp(to, key, {
|
|
26
|
-
get:
|
|
14
|
+
get: () => mod[key],
|
|
27
15
|
enumerable: true
|
|
28
16
|
});
|
|
29
|
-
if (canCache)
|
|
30
|
-
cache.set(mod, to);
|
|
31
17
|
return to;
|
|
32
18
|
};
|
|
33
19
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
-
var __returnValue = (v) => v;
|
|
35
|
-
function __exportSetter(name, newValue) {
|
|
36
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
-
}
|
|
38
20
|
var __export = (target, all) => {
|
|
39
21
|
for (var name in all)
|
|
40
22
|
__defProp(target, name, {
|
|
41
23
|
get: all[name],
|
|
42
24
|
enumerable: true,
|
|
43
25
|
configurable: true,
|
|
44
|
-
set:
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
45
27
|
});
|
|
46
28
|
};
|
|
47
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -3533,36 +3515,11 @@ var require_emoji_regex = __commonJS((exports, module) => {
|
|
|
3533
3515
|
};
|
|
3534
3516
|
});
|
|
3535
3517
|
|
|
3536
|
-
// node_modules/mppx/dist/
|
|
3537
|
-
var
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
from: () => from
|
|
3542
|
-
});
|
|
3543
|
-
function from(method) {
|
|
3544
|
-
return method;
|
|
3545
|
-
}
|
|
3546
|
-
function toClient(method, options) {
|
|
3547
|
-
const { context, createCredential } = options;
|
|
3548
|
-
return {
|
|
3549
|
-
...method,
|
|
3550
|
-
context,
|
|
3551
|
-
createCredential
|
|
3552
|
-
};
|
|
3553
|
-
}
|
|
3554
|
-
function toServer(method, options) {
|
|
3555
|
-
const { defaults, html, request, respond, transport, verify } = options;
|
|
3556
|
-
return {
|
|
3557
|
-
...method,
|
|
3558
|
-
defaults,
|
|
3559
|
-
html,
|
|
3560
|
-
request,
|
|
3561
|
-
respond,
|
|
3562
|
-
transport,
|
|
3563
|
-
verify
|
|
3564
|
-
};
|
|
3565
|
-
}
|
|
3518
|
+
// node_modules/mppx/dist/BodyDigest.js
|
|
3519
|
+
var init_BodyDigest = () => {};
|
|
3520
|
+
|
|
3521
|
+
// node_modules/mppx/dist/PaymentRequest.js
|
|
3522
|
+
var init_PaymentRequest = () => {};
|
|
3566
3523
|
|
|
3567
3524
|
// node_modules/mppx/node_modules/zod/v4/core/core.js
|
|
3568
3525
|
function $constructor(name, initializer, params) {
|
|
@@ -16647,8 +16604,89 @@ var init_zod = __esm(() => {
|
|
|
16647
16604
|
init_mini();
|
|
16648
16605
|
});
|
|
16649
16606
|
|
|
16607
|
+
// node_modules/mppx/dist/Challenge.js
|
|
16608
|
+
var Schema;
|
|
16609
|
+
var init_Challenge = __esm(() => {
|
|
16610
|
+
init_zod();
|
|
16611
|
+
Schema = object({
|
|
16612
|
+
description: optional(string2()),
|
|
16613
|
+
digest: optional(string2().check(_regex(/^sha-256=/, "Invalid digest format"))),
|
|
16614
|
+
expires: optional(datetime3()),
|
|
16615
|
+
id: string2(),
|
|
16616
|
+
intent: string2(),
|
|
16617
|
+
method: string2(),
|
|
16618
|
+
opaque: optional(record(string2(), string2())),
|
|
16619
|
+
realm: string2(),
|
|
16620
|
+
request: record(string2(), unknown())
|
|
16621
|
+
});
|
|
16622
|
+
});
|
|
16623
|
+
|
|
16624
|
+
// node_modules/mppx/dist/Credential.js
|
|
16625
|
+
var init_Credential = () => {};
|
|
16626
|
+
|
|
16627
|
+
// node_modules/mppx/dist/Errors.js
|
|
16628
|
+
var init_Errors = () => {};
|
|
16629
|
+
|
|
16630
|
+
// node_modules/mppx/dist/Expires.js
|
|
16631
|
+
var init_Expires = () => {};
|
|
16632
|
+
|
|
16633
|
+
// node_modules/mppx/dist/Method.js
|
|
16634
|
+
var exports_Method = {};
|
|
16635
|
+
__export(exports_Method, {
|
|
16636
|
+
toServer: () => toServer,
|
|
16637
|
+
toClient: () => toClient,
|
|
16638
|
+
from: () => from
|
|
16639
|
+
});
|
|
16640
|
+
function from(method) {
|
|
16641
|
+
return method;
|
|
16642
|
+
}
|
|
16643
|
+
function toClient(method, options) {
|
|
16644
|
+
const { context, createCredential } = options;
|
|
16645
|
+
return {
|
|
16646
|
+
...method,
|
|
16647
|
+
context,
|
|
16648
|
+
createCredential
|
|
16649
|
+
};
|
|
16650
|
+
}
|
|
16651
|
+
function toServer(method, options) {
|
|
16652
|
+
const { defaults, html, request, respond, transport, verify } = options;
|
|
16653
|
+
return {
|
|
16654
|
+
...method,
|
|
16655
|
+
defaults,
|
|
16656
|
+
html,
|
|
16657
|
+
request,
|
|
16658
|
+
respond,
|
|
16659
|
+
transport,
|
|
16660
|
+
verify
|
|
16661
|
+
};
|
|
16662
|
+
}
|
|
16663
|
+
|
|
16664
|
+
// node_modules/mppx/dist/Receipt.js
|
|
16665
|
+
var Schema2;
|
|
16666
|
+
var init_Receipt = __esm(() => {
|
|
16667
|
+
init_zod();
|
|
16668
|
+
Schema2 = object({
|
|
16669
|
+
method: string2(),
|
|
16670
|
+
reference: string2(),
|
|
16671
|
+
externalId: optional(string2()),
|
|
16672
|
+
status: literal("success"),
|
|
16673
|
+
timestamp: datetime3()
|
|
16674
|
+
});
|
|
16675
|
+
});
|
|
16676
|
+
|
|
16677
|
+
// node_modules/mppx/dist/Store.js
|
|
16678
|
+
var init_Store = () => {};
|
|
16679
|
+
|
|
16650
16680
|
// node_modules/mppx/dist/index.js
|
|
16651
16681
|
var init_dist = __esm(() => {
|
|
16682
|
+
init_BodyDigest();
|
|
16683
|
+
init_Challenge();
|
|
16684
|
+
init_Credential();
|
|
16685
|
+
init_Errors();
|
|
16686
|
+
init_Expires();
|
|
16687
|
+
init_PaymentRequest();
|
|
16688
|
+
init_Receipt();
|
|
16689
|
+
init_Store();
|
|
16652
16690
|
init_zod();
|
|
16653
16691
|
});
|
|
16654
16692
|
|
|
@@ -17267,7 +17305,8 @@ function requireAuth() {
|
|
|
17267
17305
|
var DEFAULTS = {
|
|
17268
17306
|
apiBase: "https://mpp.amikomarkets.com",
|
|
17269
17307
|
platformUrl: "https://platform.heyamiko.com",
|
|
17270
|
-
siteBase: "https://platform.heyamiko.com"
|
|
17308
|
+
siteBase: "https://platform.heyamiko.com",
|
|
17309
|
+
chatBase: "https://amiko-chat.up.railway.app"
|
|
17271
17310
|
};
|
|
17272
17311
|
function loadConfig() {
|
|
17273
17312
|
const auth = resolveAuth();
|
|
@@ -17275,6 +17314,7 @@ function loadConfig() {
|
|
|
17275
17314
|
apiBase: auth.apiBase ?? DEFAULTS.apiBase,
|
|
17276
17315
|
platformUrl: auth.platformUrl ?? DEFAULTS.platformUrl,
|
|
17277
17316
|
siteBase: DEFAULTS.siteBase,
|
|
17317
|
+
chatBase: DEFAULTS.chatBase,
|
|
17278
17318
|
twinToken: auth.twinToken,
|
|
17279
17319
|
twinId: auth.twinId,
|
|
17280
17320
|
userId: auth.userId
|
|
@@ -21724,6 +21764,198 @@ function registerComposioCommand(program2) {
|
|
|
21724
21764
|
});
|
|
21725
21765
|
}
|
|
21726
21766
|
|
|
21767
|
+
// src/commands/conversation.ts
|
|
21768
|
+
function describeConversation(c, selfUserId) {
|
|
21769
|
+
if (c.title)
|
|
21770
|
+
return c.title;
|
|
21771
|
+
const others = c.participants?.filter((p) => !(p.participant_type === "user" && p.participant_id === selfUserId)) ?? [];
|
|
21772
|
+
return others.map((p) => p.name ?? p.participant_id).join(", ") || c.id;
|
|
21773
|
+
}
|
|
21774
|
+
function findDirectWithUser(list, selfUserId, otherUserId) {
|
|
21775
|
+
return list.find((c) => {
|
|
21776
|
+
if (c.conversation_type !== "direct")
|
|
21777
|
+
return false;
|
|
21778
|
+
const ps = c.participants ?? [];
|
|
21779
|
+
const userIds = ps.filter((p) => p.participant_type === "user" && !p.left_at).map((p) => p.participant_id);
|
|
21780
|
+
if (userIds.length !== 2)
|
|
21781
|
+
return false;
|
|
21782
|
+
if (selfUserId && !userIds.includes(selfUserId))
|
|
21783
|
+
return false;
|
|
21784
|
+
return userIds.includes(otherUserId);
|
|
21785
|
+
});
|
|
21786
|
+
}
|
|
21787
|
+
function registerConversationCommand(program2) {
|
|
21788
|
+
program2.command("list").description("List your conversations").option("--archived <state>", "active | archived | all", "active").option("--limit <n>", "Max results (1–100)", "50").option("--offset <n>", "Pagination offset", "0").option("--json", "Output as JSON").action(async (opts) => {
|
|
21789
|
+
const auth = resolveAuth();
|
|
21790
|
+
const config2 = loadConfig();
|
|
21791
|
+
const spinner = opts.json ? null : ora("Loading conversations...").start();
|
|
21792
|
+
try {
|
|
21793
|
+
const data = await amikoWebFetch(auth, "/api/conversations", {
|
|
21794
|
+
query: {
|
|
21795
|
+
archived: opts.archived,
|
|
21796
|
+
limit: opts.limit,
|
|
21797
|
+
offset: opts.offset
|
|
21798
|
+
}
|
|
21799
|
+
});
|
|
21800
|
+
spinner?.stop();
|
|
21801
|
+
renderOutput(data, (d) => {
|
|
21802
|
+
if (!d.conversations.length) {
|
|
21803
|
+
console.log(dim("No conversations."));
|
|
21804
|
+
return;
|
|
21805
|
+
}
|
|
21806
|
+
console.log(heading(`Conversations — ${d.conversations.length} of ${d.pagination.total}`));
|
|
21807
|
+
for (const c of d.conversations) {
|
|
21808
|
+
console.log("");
|
|
21809
|
+
console.log(label("ID", c.id));
|
|
21810
|
+
console.log(label("With", describeConversation(c, config2.userId)));
|
|
21811
|
+
console.log(label("Type", c.conversation_type));
|
|
21812
|
+
if (c.last_activity_at)
|
|
21813
|
+
console.log(label("Last activity", c.last_activity_at));
|
|
21814
|
+
if (c.unread_count)
|
|
21815
|
+
console.log(label("Unread", String(c.unread_count)));
|
|
21816
|
+
}
|
|
21817
|
+
if (d.pagination.has_more) {
|
|
21818
|
+
console.log("");
|
|
21819
|
+
console.log(dim(`More available — pass --offset ${Number(opts.offset ?? 0) + d.conversations.length}`));
|
|
21820
|
+
}
|
|
21821
|
+
}, { json: opts.json });
|
|
21822
|
+
} catch (e) {
|
|
21823
|
+
spinner?.stop();
|
|
21824
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21825
|
+
process.exit(1);
|
|
21826
|
+
}
|
|
21827
|
+
});
|
|
21828
|
+
program2.command("find").description("Find an existing direct conversation with a user").requiredOption("--user-id <id>", "Internal user id of the other party").option("--json", "Output as JSON").action(async (opts) => {
|
|
21829
|
+
const auth = resolveAuth();
|
|
21830
|
+
const config2 = loadConfig();
|
|
21831
|
+
const spinner = opts.json ? null : ora("Searching...").start();
|
|
21832
|
+
try {
|
|
21833
|
+
const data = await amikoWebFetch(auth, "/api/conversations", { query: { archived: "all", limit: 100 } });
|
|
21834
|
+
spinner?.stop();
|
|
21835
|
+
const match = findDirectWithUser(data.conversations, config2.userId, opts.userId);
|
|
21836
|
+
if (opts.json) {
|
|
21837
|
+
console.log(JSON.stringify({ conversation: match ?? null }, null, 2));
|
|
21838
|
+
return;
|
|
21839
|
+
}
|
|
21840
|
+
if (!match) {
|
|
21841
|
+
console.log(dim(`No direct conversation with user ${opts.userId}. Run \`amiko conversation create --user-id ${opts.userId}\` to start one.`));
|
|
21842
|
+
return;
|
|
21843
|
+
}
|
|
21844
|
+
console.log(success("Found conversation"));
|
|
21845
|
+
console.log(label("ID", match.id));
|
|
21846
|
+
console.log(label("With", describeConversation(match, config2.userId)));
|
|
21847
|
+
if (match.last_activity_at)
|
|
21848
|
+
console.log(label("Last activity", match.last_activity_at));
|
|
21849
|
+
} catch (e) {
|
|
21850
|
+
spinner?.stop();
|
|
21851
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21852
|
+
process.exit(1);
|
|
21853
|
+
}
|
|
21854
|
+
});
|
|
21855
|
+
program2.command("create").description("Create (or reuse) a direct conversation with another user").requiredOption("--user-id <id>", "Internal user id of the other party").option("--json", "Output as JSON").action(async (opts) => {
|
|
21856
|
+
const auth = resolveAuth();
|
|
21857
|
+
const spinner = opts.json ? null : ora("Creating conversation...").start();
|
|
21858
|
+
try {
|
|
21859
|
+
const data = await amikoWebFetch(auth, "/api/conversations", {
|
|
21860
|
+
method: "POST",
|
|
21861
|
+
body: {
|
|
21862
|
+
participant_ids: [opts.userId],
|
|
21863
|
+
participant_types: ["user"],
|
|
21864
|
+
conversation_type: "direct"
|
|
21865
|
+
}
|
|
21866
|
+
});
|
|
21867
|
+
spinner?.stop();
|
|
21868
|
+
if (opts.json) {
|
|
21869
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21870
|
+
return;
|
|
21871
|
+
}
|
|
21872
|
+
console.log(success(data.reused_existing ? "Reused existing conversation" : "Conversation created"));
|
|
21873
|
+
console.log(label("ID", data.conversation.id));
|
|
21874
|
+
} catch (e) {
|
|
21875
|
+
spinner?.stop();
|
|
21876
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21877
|
+
process.exit(1);
|
|
21878
|
+
}
|
|
21879
|
+
});
|
|
21880
|
+
program2.command("read").description("Read messages from a conversation (oldest-first, paginated)").requiredOption("--id <conversationId>", "Target conversation id").option("--limit <n>", "Max messages (1–100)", "50").option("--before-cursor <cursor>", "Page back via next_cursor from a prior call").option("--json", "Output as JSON").action(async (opts) => {
|
|
21881
|
+
const auth = resolveAuth();
|
|
21882
|
+
const spinner = opts.json ? null : ora("Loading messages...").start();
|
|
21883
|
+
try {
|
|
21884
|
+
const data = await amikoWebFetch(auth, `/api/conversations/${encodeURIComponent(opts.id)}/messages`, {
|
|
21885
|
+
query: {
|
|
21886
|
+
limit: opts.limit,
|
|
21887
|
+
before_cursor: opts.beforeCursor
|
|
21888
|
+
}
|
|
21889
|
+
});
|
|
21890
|
+
spinner?.stop();
|
|
21891
|
+
if (opts.json) {
|
|
21892
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21893
|
+
return;
|
|
21894
|
+
}
|
|
21895
|
+
if (!data.messages.length) {
|
|
21896
|
+
console.log(dim("No messages."));
|
|
21897
|
+
return;
|
|
21898
|
+
}
|
|
21899
|
+
console.log(heading(`Messages — ${data.messages.length}`));
|
|
21900
|
+
for (const m of data.messages) {
|
|
21901
|
+
console.log("");
|
|
21902
|
+
console.log(label(m.name ?? m.sender_id ?? "?", m.created_at?.slice(0, 19) ?? ""));
|
|
21903
|
+
if (m.content)
|
|
21904
|
+
console.log(m.content);
|
|
21905
|
+
if (m.message_type && m.message_type !== "text")
|
|
21906
|
+
console.log(dim(`[${m.message_type}]`));
|
|
21907
|
+
console.log(dim(`id: ${m.id}`));
|
|
21908
|
+
}
|
|
21909
|
+
if (data.has_more && data.next_cursor) {
|
|
21910
|
+
console.log("");
|
|
21911
|
+
console.log(dim(`Older messages available — pass --before-cursor ${data.next_cursor}`));
|
|
21912
|
+
}
|
|
21913
|
+
} catch (e) {
|
|
21914
|
+
spinner?.stop();
|
|
21915
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21916
|
+
process.exit(1);
|
|
21917
|
+
}
|
|
21918
|
+
});
|
|
21919
|
+
program2.command("send").description("Send a message into a conversation").requiredOption("--id <conversationId>", "Target conversation id").requiredOption("--message <text>", "Message body").option("--reply-to <messageId>", "Reply to a specific message").option("--json", "Output as JSON").action(async (opts) => {
|
|
21920
|
+
const auth = requireAuth();
|
|
21921
|
+
const config2 = loadConfig();
|
|
21922
|
+
const spinner = opts.json ? null : ora("Sending message...").start();
|
|
21923
|
+
try {
|
|
21924
|
+
const url2 = `${config2.chatBase.replace(/\/$/, "")}/messages`;
|
|
21925
|
+
const res = await fetch(url2, {
|
|
21926
|
+
method: "POST",
|
|
21927
|
+
headers: {
|
|
21928
|
+
Authorization: `Bearer ${auth.twinToken}`,
|
|
21929
|
+
"Content-Type": "application/json"
|
|
21930
|
+
},
|
|
21931
|
+
body: JSON.stringify({
|
|
21932
|
+
conversationId: opts.id,
|
|
21933
|
+
content: opts.message,
|
|
21934
|
+
message_type: "text",
|
|
21935
|
+
...opts.replyTo ? { reply_to_id: opts.replyTo } : {}
|
|
21936
|
+
})
|
|
21937
|
+
});
|
|
21938
|
+
spinner?.stop();
|
|
21939
|
+
if (!res.ok) {
|
|
21940
|
+
const text = await res.text().catch(() => "");
|
|
21941
|
+
throw new Error(`${res.status} POST /messages: ${text.slice(0, 300)}`);
|
|
21942
|
+
}
|
|
21943
|
+
const data = await res.json();
|
|
21944
|
+
if (opts.json) {
|
|
21945
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21946
|
+
return;
|
|
21947
|
+
}
|
|
21948
|
+
console.log(success("Message sent"));
|
|
21949
|
+
if (data.message?.id)
|
|
21950
|
+
console.log(label("Message ID", data.message.id));
|
|
21951
|
+
} catch (e) {
|
|
21952
|
+
spinner?.stop();
|
|
21953
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21954
|
+
process.exit(1);
|
|
21955
|
+
}
|
|
21956
|
+
});
|
|
21957
|
+
}
|
|
21958
|
+
|
|
21727
21959
|
// src/commands/wallets.ts
|
|
21728
21960
|
function formatBalance(b) {
|
|
21729
21961
|
const n = Number(b.amount) / 10 ** b.decimals;
|
|
@@ -21938,6 +22170,7 @@ var users = program2.command("users").description("Search users and view public
|
|
|
21938
22170
|
var post = program2.command("post").description("Create posts and comments on the feed");
|
|
21939
22171
|
var review = program2.command("review").description("Review queue — list, approve, or reject twin-drafted comments");
|
|
21940
22172
|
var composio = program2.command("composio").description("Manage Composio app connections");
|
|
22173
|
+
var conversation = program2.command("conversation").description("Conversations — list, find, create, send messages between users/agents");
|
|
21941
22174
|
registerCreditsCommand(program2);
|
|
21942
22175
|
registerSearchCommand(markets);
|
|
21943
22176
|
registerImageCommand(markets);
|
|
@@ -21963,4 +22196,5 @@ registerFeedCommand(program2);
|
|
|
21963
22196
|
registerPostCommand(post);
|
|
21964
22197
|
registerReviewCommand(review);
|
|
21965
22198
|
registerComposioCommand(composio);
|
|
22199
|
+
registerConversationCommand(conversation);
|
|
21966
22200
|
program2.parse();
|
package/package.json
CHANGED
package/skills/SKILL.md
CHANGED
|
@@ -32,6 +32,7 @@ Each row is a first-level command group or command. Start here when the user ask
|
|
|
32
32
|
| `amiko review <cmd>` | Review queue — list, approve, or reject twin-drafted comments |
|
|
33
33
|
| `amiko feed` | Read the friends feed, for-you feed, or filter by hashtag |
|
|
34
34
|
| `amiko composio <cmd>` | Connect / disconnect third-party OAuth apps (Gmail, GitHub, …) |
|
|
35
|
+
| `amiko conversation <cmd>` | DM/chat — list, find, create, send messages |
|
|
35
36
|
| `amiko accounts` | Show the resolved identity (authenticated, userId, twinId, platform) |
|
|
36
37
|
| `amiko info` | Show the active twin (name, description, public, voice, avatar) |
|
|
37
38
|
| `amiko config <cmd>` | Show resolved config |
|
|
@@ -260,6 +261,25 @@ amiko review reject <commentId> --yes # destructive — delete a draft
|
|
|
260
261
|
|
|
261
262
|
**Comments authored by a twin always go through review.** Any comment created with `amiko post comment ... --twin <id>` (or auto-drafted by a twin in engagement mode) lands in `status=draft` and is **not visible** until you run `amiko review approve <commentId>`. Comments without `--twin` (you posting as yourself) publish immediately and skip the review queue. Workflow: `amiko review list` to see pending drafts → `amiko review approve <id>` to publish, or `amiko review reject <id> --yes` to discard.
|
|
262
263
|
|
|
264
|
+
## Conversations
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
amiko conversation list # all your conversations (default: active)
|
|
268
|
+
amiko conversation list --archived all --limit 100 # include archived
|
|
269
|
+
amiko conversation find --user-id <userId> # is there an existing direct DM with this user?
|
|
270
|
+
amiko conversation create --user-id <userId> # create or reuse a direct DM (idempotent)
|
|
271
|
+
amiko conversation read --id <conversationId> # read recent messages (oldest-first)
|
|
272
|
+
amiko conversation read --id <id> --before-cursor <next_cursor> # page older messages
|
|
273
|
+
amiko conversation send --id <conversationId> --message "hi" # send a text message
|
|
274
|
+
amiko conversation send --id <id> --message "ok" --reply-to <messageId>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
- `list` and `find` query amiko-web's `/api/conversations` (Prisma-backed). `find` filters client-side for a 2-user direct conversation containing both you and `--user-id`.
|
|
278
|
+
- `create` POSTs to `/api/conversations` with `conversation_type=direct`. The server reuses an existing conversation if one already exists between the two users (`reused_existing: true` in the JSON response), so calling it repeatedly is safe.
|
|
279
|
+
- `read` queries amiko-web's `GET /api/conversations/<id>/messages` (paginated by `next_cursor`, oldest-first per page).
|
|
280
|
+
- `send` posts to amiko-chat's HTTP fallback (`POST /messages`) with the same Privy JWT — works for plain text messages outside the WebSocket session.
|
|
281
|
+
- `--user-id` expects the **internal** user id (the one returned by `amiko users search`), not a Privy DID or handle.
|
|
282
|
+
|
|
263
283
|
## Composio
|
|
264
284
|
|
|
265
285
|
```bash
|