@heyamiko/amiko-cli 0.9.9-beta.1 → 0.9.9-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +69 -29
- package/package.json +1 -1
- package/skills/SKILL.md +77 -1
package/dist/index.js
CHANGED
|
@@ -22013,7 +22013,7 @@ function registerNotificationsCommand(program2) {
|
|
|
22013
22013
|
}
|
|
22014
22014
|
|
|
22015
22015
|
// src/commands/memory.ts
|
|
22016
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
22016
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
22017
22017
|
import { dirname, isAbsolute, normalize, resolve as resolve2 } from "node:path";
|
|
22018
22018
|
var VALID_CATEGORIES = ["fact", "preference", "pattern", "decision", "context"];
|
|
22019
22019
|
var VALID_SOURCES = ["chat", "file", "manual"];
|
|
@@ -22184,13 +22184,18 @@ function registerMemoryCommand(program2) {
|
|
|
22184
22184
|
fail(e instanceof Error ? e.message : String(e));
|
|
22185
22185
|
}
|
|
22186
22186
|
});
|
|
22187
|
-
memory.command("sync").description("Sync MEMORY.md
|
|
22187
|
+
memory.command("sync").description("Sync MEMORY.md, its referenced files, and every .md under <workspace>/memory/ (one-way: local → server)").option("--path <dir>", `Workspace dir (default ${DEFAULT_WORKSPACE}). Looks for MEMORY.md, memory/MEMORY.md, and memory/**/*.md`).option("--dry-run", "Print what would be synced without uploading").option("--prune", "Delete server-side memory files that no longer exist locally").option("--json", "Output as JSON").action(async (opts) => {
|
|
22188
22188
|
const root = resolve2(opts.path || DEFAULT_WORKSPACE);
|
|
22189
|
-
const
|
|
22190
|
-
|
|
22191
|
-
|
|
22192
|
-
|
|
22193
|
-
const
|
|
22189
|
+
const candidateIndexes = [
|
|
22190
|
+
resolve2(root, "MEMORY.md"),
|
|
22191
|
+
resolve2(root, "memory", "MEMORY.md")
|
|
22192
|
+
].filter((p) => existsSync3(p));
|
|
22193
|
+
const memoryDir = resolve2(root, "memory");
|
|
22194
|
+
const memoryDirExists = existsSync3(memoryDir) && statSync(memoryDir).isDirectory();
|
|
22195
|
+
if (!candidateIndexes.length && !memoryDirExists) {
|
|
22196
|
+
fail(`No MEMORY.md or memory/ folder found under ${root}. Expected ${root}/MEMORY.md or ${root}/memory/.`);
|
|
22197
|
+
}
|
|
22198
|
+
const collected = collectMemoryFiles(root, candidateIndexes, memoryDirExists ? memoryDir : null);
|
|
22194
22199
|
if (collected.errors.length && !opts.json) {
|
|
22195
22200
|
for (const e of collected.errors)
|
|
22196
22201
|
console.error(error(e));
|
|
@@ -22273,37 +22278,72 @@ function registerMemoryCommand(program2) {
|
|
|
22273
22278
|
}
|
|
22274
22279
|
});
|
|
22275
22280
|
}
|
|
22276
|
-
function collectMemoryFiles(root,
|
|
22281
|
+
function collectMemoryFiles(root, indexPaths, memoryDir) {
|
|
22277
22282
|
const errors2 = [];
|
|
22278
22283
|
const seen = new Set;
|
|
22279
22284
|
const files = [];
|
|
22280
|
-
const
|
|
22281
|
-
|
|
22282
|
-
|
|
22283
|
-
pushFile(files, seen, indexPath, indexContent, root);
|
|
22284
|
-
const indexDir = dirname(indexPath);
|
|
22285
|
-
for (const ref of extractMarkdownLinks(indexContent)) {
|
|
22286
|
-
if (isExternal(ref))
|
|
22287
|
-
continue;
|
|
22288
|
-
const abs = normalize(isAbsolute(ref) ? ref : resolve2(indexDir, ref));
|
|
22289
|
-
if (!abs.startsWith(root)) {
|
|
22290
|
-
errors2.push(`Skipping ${ref}: outside workspace ${root}`);
|
|
22285
|
+
for (const indexPath of indexPaths) {
|
|
22286
|
+
const indexContent = safeRead(indexPath, errors2);
|
|
22287
|
+
if (indexContent === null)
|
|
22291
22288
|
continue;
|
|
22289
|
+
pushFile(files, seen, indexPath, indexContent, root);
|
|
22290
|
+
const indexDir = dirname(indexPath);
|
|
22291
|
+
for (const ref of extractMarkdownLinks(indexContent)) {
|
|
22292
|
+
if (isExternal(ref))
|
|
22293
|
+
continue;
|
|
22294
|
+
const abs = normalize(isAbsolute(ref) ? ref : resolve2(indexDir, ref));
|
|
22295
|
+
if (!abs.startsWith(root)) {
|
|
22296
|
+
errors2.push(`Skipping ${ref}: outside workspace ${root}`);
|
|
22297
|
+
continue;
|
|
22298
|
+
}
|
|
22299
|
+
if (!existsSync3(abs)) {
|
|
22300
|
+
errors2.push(`Referenced file missing: ${ref}`);
|
|
22301
|
+
continue;
|
|
22302
|
+
}
|
|
22303
|
+
const st = statSync(abs);
|
|
22304
|
+
if (!st.isFile())
|
|
22305
|
+
continue;
|
|
22306
|
+
const content = safeRead(abs, errors2);
|
|
22307
|
+
if (content === null)
|
|
22308
|
+
continue;
|
|
22309
|
+
pushFile(files, seen, abs, content, root);
|
|
22292
22310
|
}
|
|
22293
|
-
|
|
22294
|
-
|
|
22295
|
-
|
|
22311
|
+
}
|
|
22312
|
+
if (memoryDir) {
|
|
22313
|
+
for (const abs of walkMarkdown(memoryDir, errors2)) {
|
|
22314
|
+
const content = safeRead(abs, errors2);
|
|
22315
|
+
if (content === null)
|
|
22316
|
+
continue;
|
|
22317
|
+
pushFile(files, seen, abs, content, root);
|
|
22296
22318
|
}
|
|
22297
|
-
const st = statSync(abs);
|
|
22298
|
-
if (!st.isFile())
|
|
22299
|
-
continue;
|
|
22300
|
-
const content = safeRead(abs, errors2);
|
|
22301
|
-
if (content === null)
|
|
22302
|
-
continue;
|
|
22303
|
-
pushFile(files, seen, abs, content, root);
|
|
22304
22319
|
}
|
|
22305
22320
|
return { files, errors: errors2 };
|
|
22306
22321
|
}
|
|
22322
|
+
function walkMarkdown(dir, errors2) {
|
|
22323
|
+
const out = [];
|
|
22324
|
+
let names;
|
|
22325
|
+
try {
|
|
22326
|
+
names = readdirSync(dir);
|
|
22327
|
+
} catch (e) {
|
|
22328
|
+
errors2.push(`Failed to read ${dir}: ${e instanceof Error ? e.message : String(e)}`);
|
|
22329
|
+
return out;
|
|
22330
|
+
}
|
|
22331
|
+
for (const name of names) {
|
|
22332
|
+
const abs = resolve2(dir, name);
|
|
22333
|
+
let st;
|
|
22334
|
+
try {
|
|
22335
|
+
st = statSync(abs);
|
|
22336
|
+
} catch {
|
|
22337
|
+
continue;
|
|
22338
|
+
}
|
|
22339
|
+
if (st.isDirectory()) {
|
|
22340
|
+
out.push(...walkMarkdown(abs, errors2));
|
|
22341
|
+
} else if (st.isFile() && name.toLowerCase().endsWith(".md")) {
|
|
22342
|
+
out.push(abs);
|
|
22343
|
+
}
|
|
22344
|
+
}
|
|
22345
|
+
return out;
|
|
22346
|
+
}
|
|
22307
22347
|
function pushFile(files, seen, abs, content, root) {
|
|
22308
22348
|
const key = relativeKey(abs, root);
|
|
22309
22349
|
if (seen.has(key))
|
package/package.json
CHANGED
package/skills/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: amiko-cli
|
|
3
|
-
description: The Amiko CLI lets an agent act on the Amiko platform end-to-end — read and send platform DMs with other users (conversations list/find/read/send, the right tool when the owner asks "did X message me?" or "check my chat history with Y" — NOT the built-in sessions_list/sessions_history, which only see the agent's own local sessions), read platform notifications (friend requests, mentions, system alerts), manage Solana/Base wallets (create, swap via Jupiter, bridge USDC via Across, transfer tokens to external addresses), top up and spend credits, call paid MPP marketplace services (X/Twitter search, image generation, Amazon product search, TTS/STT, AI chat, SFX/music), manage the twin's identity and RAG documents, voice and avatar, social graph (friends, posts, comments, feed), and Composio OAuth connections. Auth is automatic when run from the agent's workspace folder; payments are platform-custodied (no keys on disk). Use this skill whenever the user asks about their Amiko inbox/DMs/notifications or to do anything that would show up in their Amiko account or cost AMIKO/credits.
|
|
3
|
+
description: The Amiko CLI lets an agent act on the Amiko platform end-to-end — read and send platform DMs with other users (conversations list/find/read/send, the right tool when the owner asks "did X message me?" or "check my chat history with Y" — NOT the built-in sessions_list/sessions_history, which only see the agent's own local sessions), read platform notifications (friend requests, mentions, system alerts), search and write **cross-agent memories** about the owner (what other agents already know — preferences, decisions, facts), manage Solana/Base wallets (create, swap via Jupiter, bridge USDC via Across, transfer tokens to external addresses), top up and spend credits, call paid MPP marketplace services (X/Twitter search, image generation, Amazon product search, TTS/STT, AI chat, SFX/music), manage the twin's identity and RAG documents, voice and avatar, social graph (friends, posts, comments, feed), and Composio OAuth connections. Auth is automatic when run from the agent's workspace folder; payments are platform-custodied (no keys on disk). Use this skill whenever the user asks about their Amiko inbox/DMs/notifications or to do anything that would show up in their Amiko account or cost AMIKO/credits.
|
|
4
4
|
homepage: https://platform.heyamiko.com
|
|
5
5
|
metadata: {"openclaw":{"emoji":"🤖","requires":{"bins":["node"]}}}
|
|
6
6
|
---
|
|
@@ -34,6 +34,7 @@ Each row is a first-level command group or command. Start here when the user ask
|
|
|
34
34
|
| `amiko composio <cmd>` | Connect / disconnect third-party OAuth apps (Gmail, GitHub, …) |
|
|
35
35
|
| `amiko conversation <cmd>` | DM/chat — list, find, create, send messages |
|
|
36
36
|
| `amiko notifications <cmd>` | Platform notifications — list, mark as read |
|
|
37
|
+
| `amiko memory <cmd>` | Cross-agent memory — `search` before answering personal questions, `add` what's worth remembering, `list` / `rm` / `status` / `sync` local memory files |
|
|
37
38
|
| `amiko accounts` | Show the resolved identity (authenticated, userId, twinId, platform) |
|
|
38
39
|
| `amiko info` | Show the active twin (name, description, public, voice, avatar) |
|
|
39
40
|
| `amiko config <cmd>` | Show resolved config |
|
|
@@ -298,6 +299,81 @@ amiko notifications read --all # mark all read
|
|
|
298
299
|
|
|
299
300
|
Platform notifications cover friend requests, mentions, system alerts, and other activity that doesn't belong to any conversation. Use this when the user asks "any notifications?" or "what's new on the platform?". Notifications belonging to a conversation (new DM, comment on your post) still show up here when the platform writes one — they don't replace `conversation read` for actual chat content.
|
|
300
301
|
|
|
302
|
+
## Memory (cross-agent)
|
|
303
|
+
|
|
304
|
+
Memories are scoped to the **owner's `user_id`**, not to your individual agent — every agent the owner runs reads and writes the same pool. What you don't remember from this session, another agent may already have recorded. Three commands cover almost everything:
|
|
305
|
+
|
|
306
|
+
- `amiko memory search "<query>"` — natural-language hybrid search (vector + FTS). Query in any language.
|
|
307
|
+
- `amiko memory add "<content>" --category <cat>` — save a durable memory for cross-agent recall.
|
|
308
|
+
- `amiko memory sync` — upload local `MEMORY.md` + `memory/**/*.md` so the platform extracts granular memories from them.
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
amiko memory search "git workflow" --limit 5 # ranked results with score
|
|
312
|
+
amiko memory list --limit 25 # newest-first, paginate with --offset
|
|
313
|
+
amiko memory list --category preference # filter: fact | preference | pattern | decision | context
|
|
314
|
+
amiko memory list --source chat|file|manual # filter by origin
|
|
315
|
+
amiko memory add "Owner prefers terse PR descriptions" --category preference --tags pr,style
|
|
316
|
+
amiko memory rm <memoryId> # soft-delete
|
|
317
|
+
amiko memory status # totals: memories + memory_files
|
|
318
|
+
amiko memory sync # one-way upload of local MEMORY.md + memory/**/*.md
|
|
319
|
+
amiko memory sync --dry-run # show what would be uploaded
|
|
320
|
+
amiko memory sync --prune # also delete server files that no longer exist locally
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
All `memory` commands support `--json`.
|
|
324
|
+
|
|
325
|
+
### When to search — bias toward calling
|
|
326
|
+
|
|
327
|
+
**Default assumption: the owner has stored context you don't have. Run `amiko memory search` BEFORE answering any question about them, their project, their preferences, or their history. A call that returns empty costs ~100ms; a missed hit makes you look amnesic and forces them to re-teach you every session.**
|
|
328
|
+
|
|
329
|
+
The single most common failure mode is NOT calling `memory search` on abstract self-referential questions. If the owner's message has any of these shapes, you MUST search — no judgment, no exceptions:
|
|
330
|
+
|
|
331
|
+
1. **Preference / habit questions**, even without a specific entity named.
|
|
332
|
+
Examples: "what do I usually use for X", "how do I normally do Y", "what's my preferred tool for Z", "what's my coding style". Pass a short paraphrase as the query.
|
|
333
|
+
2. **Callbacks to prior context.** "as I mentioned", "like last time", "you know the one", "we discussed before", "what was that X we set up".
|
|
334
|
+
3. **Named entities specific to this owner.** Their project / repo / service / team / tool name. A person by name.
|
|
335
|
+
4. **Past bugs, decisions, investigations, design choices.**
|
|
336
|
+
5. **Start of a new session** where they reference anything about themselves or their work.
|
|
337
|
+
|
|
338
|
+
Do NOT search for:
|
|
339
|
+
- Purely textbook programming questions with no owner-specific signal ("how does `useEffect` work", "what is the time complexity of quicksort").
|
|
340
|
+
- Questions the current code or `git log` already answers directly.
|
|
341
|
+
|
|
342
|
+
**When unsure, search.** Empty results cost you nothing. Missing the owner's context costs you their trust.
|
|
343
|
+
|
|
344
|
+
### When to save
|
|
345
|
+
|
|
346
|
+
Use `amiko memory add` after:
|
|
347
|
+
|
|
348
|
+
- Fixing a non-obvious bug → save root cause + fix as `pattern` or `fact`
|
|
349
|
+
- Making an architecture decision → save reasoning as `decision`
|
|
350
|
+
- Discovering a useful pattern or workaround → `pattern`
|
|
351
|
+
- Owner explicitly says "remember this" / "save this" / "from now on..." → match the category to the content
|
|
352
|
+
- Learning a preference you'd otherwise have to re-ask ("I prefer rg", "I always use pnpm") → `preference`
|
|
353
|
+
|
|
354
|
+
Write memories as **standalone sentences with full context** — include names, not pronouns. A future session will read this without knowing today's conversation. Bad: "He prefers it that way." Good: "William prefers terse PR descriptions in the Amiko-Layer repo."
|
|
355
|
+
|
|
356
|
+
Categories:
|
|
357
|
+
|
|
358
|
+
| Category | Use for |
|
|
359
|
+
|----------|---------|
|
|
360
|
+
| `fact` | Technical facts, API details, config values, stable facts about the owner |
|
|
361
|
+
| `preference` | How they like things done (tone, formats, tools, coding style) |
|
|
362
|
+
| `pattern` | Recurring patterns, pitfalls, team conventions, workarounds |
|
|
363
|
+
| `decision` | Architecture decisions and their reasoning |
|
|
364
|
+
| `context` | Project context, deadlines, ongoing work, transient state |
|
|
365
|
+
|
|
366
|
+
Do NOT save:
|
|
367
|
+
- Trivial facts obvious from the code itself or generic programming knowledge.
|
|
368
|
+
- Ephemeral state already captured by `git log` / the current diff.
|
|
369
|
+
- Duplicates — `memory search` first; if a near-match exists, skip or `rm` the old one before adding.
|
|
370
|
+
|
|
371
|
+
### `source` and `sync` semantics
|
|
372
|
+
|
|
373
|
+
`source` is set automatically: `manual` for `memory add`, `chat` for cron-extracted conversation memories, `file` for memories the platform extracted from a synced `MEMORY.md`/file.
|
|
374
|
+
|
|
375
|
+
`sync` walks `<workspace>/MEMORY.md`, every markdown link inside it, **and** every `.md` under `<workspace>/memory/` (recursively). Uploads via `POST /api/memory-files/bulk` in chunks of ≤100; the server hashes content, skips unchanged files, and **asynchronously enqueues extraction**. Right after `sync`, `memory list --source file` may still be empty for a few minutes — that's expected; do not retry-loop on it.
|
|
376
|
+
|
|
301
377
|
## Composio
|
|
302
378
|
|
|
303
379
|
```bash
|