@heyamiko/amiko-cli 0.9.5 → 0.9.6-beta.1
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 +273 -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,186 @@ 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 spinner = opts.json ? null : ora("Sending message...").start();
|
|
21922
|
+
try {
|
|
21923
|
+
const data = await amikoWebFetch(auth, `/api/conversations/${encodeURIComponent(opts.id)}/messages`, {
|
|
21924
|
+
method: "POST",
|
|
21925
|
+
body: {
|
|
21926
|
+
content: opts.message,
|
|
21927
|
+
message_type: "text",
|
|
21928
|
+
...opts.replyTo ? { reply_to_id: opts.replyTo } : {}
|
|
21929
|
+
}
|
|
21930
|
+
});
|
|
21931
|
+
spinner?.stop();
|
|
21932
|
+
if (opts.json) {
|
|
21933
|
+
console.log(JSON.stringify(data, null, 2));
|
|
21934
|
+
return;
|
|
21935
|
+
}
|
|
21936
|
+
console.log(success("Message sent"));
|
|
21937
|
+
if (data.message?.id)
|
|
21938
|
+
console.log(label("Message ID", data.message.id));
|
|
21939
|
+
} catch (e) {
|
|
21940
|
+
spinner?.stop();
|
|
21941
|
+
console.error(error(e instanceof Error ? e.message : String(e)));
|
|
21942
|
+
process.exit(1);
|
|
21943
|
+
}
|
|
21944
|
+
});
|
|
21945
|
+
}
|
|
21946
|
+
|
|
21727
21947
|
// src/commands/wallets.ts
|
|
21728
21948
|
function formatBalance(b) {
|
|
21729
21949
|
const n = Number(b.amount) / 10 ** b.decimals;
|
|
@@ -21938,6 +22158,7 @@ var users = program2.command("users").description("Search users and view public
|
|
|
21938
22158
|
var post = program2.command("post").description("Create posts and comments on the feed");
|
|
21939
22159
|
var review = program2.command("review").description("Review queue — list, approve, or reject twin-drafted comments");
|
|
21940
22160
|
var composio = program2.command("composio").description("Manage Composio app connections");
|
|
22161
|
+
var conversation = program2.command("conversation").description("Conversations — list, find, create, send messages between users/agents");
|
|
21941
22162
|
registerCreditsCommand(program2);
|
|
21942
22163
|
registerSearchCommand(markets);
|
|
21943
22164
|
registerImageCommand(markets);
|
|
@@ -21963,4 +22184,5 @@ registerFeedCommand(program2);
|
|
|
21963
22184
|
registerPostCommand(post);
|
|
21964
22185
|
registerReviewCommand(review);
|
|
21965
22186
|
registerComposioCommand(composio);
|
|
22187
|
+
registerConversationCommand(conversation);
|
|
21966
22188
|
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-web's `POST /api/conversations/<id>/messages` with the Clawd twin token. The server persists the message and fans it out to other participants via the WebSocket broadcast.
|
|
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
|