@heyamiko/amiko-cli 0.4.0 → 0.4.7

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/src/config.ts ADDED
@@ -0,0 +1,31 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { AppConfig } from "./types.js";
5
+
6
+ function defaultWorkspacePath() {
7
+ return path.join(os.homedir(), ".amiko");
8
+ }
9
+
10
+ function newSessionId() {
11
+ return randomUUID().split("-")[0];
12
+ }
13
+
14
+ export function loadConfig(): AppConfig {
15
+ const workspacePath = process.env.AMIKO_WORKSPACE || defaultWorkspacePath();
16
+ const sessionId = process.env.AMIKO_SESSION_ID || newSessionId();
17
+
18
+ return {
19
+ workspacePath,
20
+ sessionId,
21
+ qmdBin: process.env.AMIKO_QMD_BIN || "qmd",
22
+ qmdLimit: Number(process.env.AMIKO_QMD_LIMIT || 5),
23
+ qmdEnabled: process.env.AMIKO_QMD_ENABLED !== "0",
24
+ qmdCollection: process.env.AMIKO_QMD_COLLECTION || undefined,
25
+ qmdFull: process.env.AMIKO_QMD_FULL === "1",
26
+ model: process.env.AMIKO_MODEL || undefined,
27
+ modelProvider: process.env.AMIKO_MODEL_PROVIDER || undefined,
28
+ modelId: process.env.AMIKO_MODEL_ID || undefined,
29
+ thinkingLevel: (process.env.AMIKO_THINKING_LEVEL as any) || undefined
30
+ };
31
+ }
@@ -0,0 +1,33 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { AppConfig } from "./types.js";
5
+
6
+ export type PersistedConfig = {
7
+ model?: string;
8
+ modelProvider?: string;
9
+ modelId?: string;
10
+ thinkingLevel?: AppConfig["thinkingLevel"];
11
+ };
12
+
13
+ export function getConfigFilePath(workspacePath: string) {
14
+ const base = workspacePath || path.join(os.homedir(), ".amiko");
15
+ return path.join(base, "config.json");
16
+ }
17
+
18
+ export async function loadConfigFile(workspacePath: string): Promise<PersistedConfig> {
19
+ const filePath = getConfigFilePath(workspacePath);
20
+ try {
21
+ const raw = await fs.readFile(filePath, "utf8");
22
+ const parsed = JSON.parse(raw) as PersistedConfig;
23
+ return parsed || {};
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+
29
+ export async function saveConfigFile(workspacePath: string, config: PersistedConfig): Promise<void> {
30
+ const filePath = getConfigFilePath(workspacePath);
31
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
32
+ await fs.writeFile(filePath, JSON.stringify(config, null, 2) + "\n", "utf8");
33
+ }
@@ -0,0 +1,111 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { MemoryHit } from "../types.js";
4
+
5
+ const execFileAsync = promisify(execFile);
6
+
7
+ function parseJsonLines(text: string) {
8
+ const lines = text.split("\n").map((line) => line.trim()).filter(Boolean);
9
+ const results: any[] = [];
10
+ for (const line of lines) {
11
+ try {
12
+ results.push(JSON.parse(line));
13
+ } catch {
14
+ // ignore
15
+ }
16
+ }
17
+ return results;
18
+ }
19
+
20
+ export async function qmdSearch(options: {
21
+ qmdBin: string;
22
+ query: string;
23
+ limit: number;
24
+ collection?: string;
25
+ }): Promise<MemoryHit[]> {
26
+ const { qmdBin, query, limit, collection } = options;
27
+
28
+ try {
29
+ const args = ["query", "--json", "-n", String(limit)];
30
+ if (collection) {
31
+ args.push("-c", collection);
32
+ }
33
+ args.push(query);
34
+
35
+ const { stdout } = await execFileAsync(qmdBin, [
36
+ ...args
37
+ ]);
38
+
39
+ try {
40
+ const parsed = JSON.parse(stdout);
41
+ if (Array.isArray(parsed)) {
42
+ return parsed.map(normalizeHit);
43
+ }
44
+ } catch {
45
+ // fall through to JSONL parsing
46
+ }
47
+
48
+ return parseJsonLines(stdout).map(normalizeHit);
49
+ } catch {
50
+ return [];
51
+ }
52
+ }
53
+
54
+ export async function qmdGet(options: {
55
+ qmdBin: string;
56
+ docId: string;
57
+ full?: boolean;
58
+ }): Promise<string | null> {
59
+ const { qmdBin, docId, full } = options;
60
+
61
+ try {
62
+ const args = ["get", docId];
63
+ if (full) args.push("--full");
64
+
65
+ const { stdout } = await execFileAsync(qmdBin, args);
66
+ return stdout.trim();
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ export async function qmdCollectionAdd(options: {
73
+ qmdBin: string;
74
+ name: string;
75
+ path: string;
76
+ }): Promise<boolean> {
77
+ const { qmdBin, name, path } = options;
78
+
79
+ try {
80
+ await execFileAsync(qmdBin, ["collection", "add", path, "--name", name]);
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ export async function qmdEmbed(options: {
88
+ qmdBin: string;
89
+ collection?: string;
90
+ }): Promise<boolean> {
91
+ const { qmdBin, collection } = options;
92
+
93
+ try {
94
+ const args = ["embed"];
95
+ if (collection) args.push("-c", collection);
96
+ await execFileAsync(qmdBin, args);
97
+ return true;
98
+ } catch {
99
+ return false;
100
+ }
101
+ }
102
+
103
+ function normalizeHit(hit: any): MemoryHit {
104
+ return {
105
+ id: String(hit.id ?? hit.docId ?? hit.path ?? "unknown"),
106
+ score: typeof hit.score === "number" ? hit.score : undefined,
107
+ title: hit.title ?? hit.name,
108
+ snippet: hit.snippet ?? hit.text,
109
+ path: hit.path
110
+ };
111
+ }
package/src/prompt.ts ADDED
@@ -0,0 +1,55 @@
1
+ import os from "node:os";
2
+ import { MemoryHit } from "./types.js";
3
+
4
+ export function buildPrompt(options: {
5
+ identity: string;
6
+ personality: string;
7
+ memory: string;
8
+ hits: MemoryHit[];
9
+ }) {
10
+ const { identity, personality, memory, hits } = options;
11
+ const hitText = hits
12
+ .map((hit, index) => {
13
+ const title = hit.title || hit.path || hit.id;
14
+ const snippet = hit.snippet || "";
15
+ return `(${index + 1}) ${title}\n${snippet}`.trim();
16
+ })
17
+ .filter(Boolean)
18
+ .join("\n\n");
19
+
20
+ const systemInfo = [
21
+ `platform: ${process.platform}`,
22
+ `arch: ${process.arch}`,
23
+ `cwd: ${process.cwd()}`,
24
+ `home: ${os.homedir()}`
25
+ ].join("\n");
26
+
27
+ const toolSpec = [
28
+ "Available tools:",
29
+ "- read: { path: string, maxBytes?: number }",
30
+ "- bash: { command: string, cwd?: string, timeoutMs?: number }",
31
+ "",
32
+ "Tool call rules:",
33
+ "1) Always include the tool name.",
34
+ "2) Always include required fields (read.path, bash.command).",
35
+ "3) Do not call tools with empty arguments.",
36
+ "4) Use bash for shell commands; do not invent other tool names.",
37
+ ].join("\n");
38
+
39
+ const sections = [
40
+ "# Identity\n" + identity.trim(),
41
+ "# Personality\n" + personality.trim(),
42
+ "# System Info\n" + systemInfo,
43
+ "# Tooling Policy\n" +
44
+ "You can use tools (read, bash) to answer questions. Prefer tools over asking the user to run commands. " +
45
+ "Only ask for clarification if needed to choose a safe tool or path.",
46
+ "# Tool Schemas\n" + toolSpec,
47
+ "# Long-term Memory\n" + memory.trim()
48
+ ];
49
+
50
+ if (hitText.length > 0) {
51
+ sections.push("# Retrieved Memory\n" + hitText);
52
+ }
53
+
54
+ return sections.join("\n\n").trim();
55
+ }
package/src/session.ts ADDED
@@ -0,0 +1,35 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ export type SessionFile = {
5
+ id: string;
6
+ path: string;
7
+ };
8
+
9
+ function formatDate(date: Date) {
10
+ const yyyy = date.getFullYear();
11
+ const mm = String(date.getMonth() + 1).padStart(2, "0");
12
+ const dd = String(date.getDate()).padStart(2, "0");
13
+ return `${yyyy}-${mm}-${dd}`;
14
+ }
15
+
16
+ export async function createSessionFile(sessionsDir: string, sessionId: string): Promise<SessionFile> {
17
+ const date = formatDate(new Date());
18
+ const fileName = `${date}-${sessionId}.md`;
19
+ const sessionPath = path.join(sessionsDir, fileName);
20
+
21
+ try {
22
+ await fs.access(sessionPath);
23
+ } catch {
24
+ const header = `# Session ${fileName}\n\n`;
25
+ await fs.writeFile(sessionPath, header, "utf8");
26
+ }
27
+
28
+ return { id: sessionId, path: sessionPath };
29
+ }
30
+
31
+ export async function appendSession(sessionPath: string, role: "user" | "assistant", content: string) {
32
+ const timestamp = new Date().toISOString();
33
+ const block = `## ${role} @ ${timestamp}\n\n${content}\n\n`;
34
+ await fs.appendFile(sessionPath, block, "utf8");
35
+ }
package/src/types.ts ADDED
@@ -0,0 +1,40 @@
1
+ export type Role = "user" | "assistant" | "system" | "tool";
2
+
3
+ export type Message = {
4
+ role: Role;
5
+ content: string;
6
+ };
7
+
8
+ export type MemoryHit = {
9
+ id: string;
10
+ score?: number;
11
+ title?: string;
12
+ snippet?: string;
13
+ path?: string;
14
+ };
15
+
16
+ export type AgentInput = {
17
+ prompt: string;
18
+ userMessage: string;
19
+ };
20
+
21
+ export type Agent = {
22
+ streamReply: (input: AgentInput) => AsyncGenerator<string>;
23
+ setModel?: (provider: string, modelId: string) => { ok: boolean; message: string };
24
+ getCurrentModel?: () => string | null;
25
+ onEvent?: (handler: (event: any) => void) => void;
26
+ };
27
+
28
+ export type AppConfig = {
29
+ workspacePath: string;
30
+ sessionId: string;
31
+ qmdBin: string;
32
+ qmdLimit: number;
33
+ qmdEnabled: boolean;
34
+ qmdCollection?: string;
35
+ qmdFull: boolean;
36
+ model?: string;
37
+ modelProvider?: string;
38
+ modelId?: string;
39
+ thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
40
+ };
@@ -0,0 +1,58 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ const DEFAULT_IDENTITY = "# Identity\n\nYou are Amiko, a helpful CLI agent.\n";
5
+ const DEFAULT_PERSONALITY = "# Personality\n\n- Clear, concise, friendly.\n- Ask for clarification when unsure.\n";
6
+ const DEFAULT_MEMORY = "# Memory\n\n";
7
+
8
+ export type WorkspaceFiles = {
9
+ root: string;
10
+ identityPath: string;
11
+ personalityPath: string;
12
+ memoryPath: string;
13
+ sessionsDir: string;
14
+ };
15
+
16
+ async function ensureDir(dirPath: string) {
17
+ await fs.mkdir(dirPath, { recursive: true });
18
+ }
19
+
20
+ async function ensureFile(filePath: string, content: string) {
21
+ try {
22
+ await fs.access(filePath);
23
+ } catch {
24
+ await fs.writeFile(filePath, content, "utf8");
25
+ }
26
+ }
27
+
28
+ export async function initWorkspace(root: string): Promise<WorkspaceFiles> {
29
+ const identityPath = path.join(root, "IDENTITY.md");
30
+ const personalityPath = path.join(root, "PERSONALITY.md");
31
+ const memoryPath = path.join(root, "MEMORY.md");
32
+ const sessionsDir = path.join(root, "sessions");
33
+
34
+ await ensureDir(root);
35
+ await ensureDir(sessionsDir);
36
+
37
+ await ensureFile(identityPath, DEFAULT_IDENTITY);
38
+ await ensureFile(personalityPath, DEFAULT_PERSONALITY);
39
+ await ensureFile(memoryPath, DEFAULT_MEMORY);
40
+
41
+ return {
42
+ root,
43
+ identityPath,
44
+ personalityPath,
45
+ memoryPath,
46
+ sessionsDir
47
+ };
48
+ }
49
+
50
+ export async function readWorkspaceFiles(files: WorkspaceFiles) {
51
+ const [identity, personality, memory] = await Promise.all([
52
+ fs.readFile(files.identityPath, "utf8"),
53
+ fs.readFile(files.personalityPath, "utf8"),
54
+ fs.readFile(files.memoryPath, "utf8")
55
+ ]);
56
+
57
+ return { identity, personality, memory };
58
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "jsx": "react-jsx",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "skipLibCheck": true,
13
+ "types": ["node"]
14
+ },
15
+ "include": ["src"]
16
+ }
package/README.md DELETED
@@ -1,222 +0,0 @@
1
- # Amiko CLI
2
-
3
- Manage agents, wallets, credits, and the MPP marketplace from your terminal. Works for both human users and AI agents running on OpenClaw.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install -g @heyamiko/amiko-cli
9
- # or
10
- bun install -g @heyamiko/amiko-cli
11
- ```
12
-
13
- Update to latest:
14
-
15
- ```bash
16
- amiko update
17
- ```
18
-
19
- ## Quick Start
20
-
21
- ```bash
22
- # Connect your account
23
- amiko connect <CODE> # paste code from Amiko settings
24
- amiko connect amk_<key> # or use your API key directly
25
- amiko connect # or open browser to sign in
26
-
27
- # Check your balance
28
- amiko credits balance
29
-
30
- # Top up credits from your agent's wallet
31
- amiko credits topup 10000 --token AMIKO --yes
32
-
33
- # Swap tokens on Solana
34
- amiko swap send 1 amiko usdc
35
-
36
- # Browse and call marketplace agents
37
- amiko browse
38
- amiko call titan-research "Summarize the latest AI news"
39
- ```
40
-
41
- ## Connect
42
-
43
- Three ways to authenticate:
44
-
45
- ```bash
46
- amiko connect <CODE> # 7-char code from platform settings (recommended)
47
- amiko connect amk_<key> # API key (shown once at creation)
48
- amiko connect # browser sign-in flow
49
- ```
50
-
51
- The connect code is the simplest — generate one from your Amiko settings page, paste it to the agent or terminal. Connect auto-detects your Solana wallet for swaps.
52
-
53
- ```bash
54
- amiko whoami # show current auth status
55
- amiko logout # clear stored credentials
56
- ```
57
-
58
- ## Credits
59
-
60
- ```bash
61
- amiko credits balance # credit balance + wallet balances across all chains
62
- amiko credits topup <amount> # top up credits (amount in credits, e.g. 10000)
63
- ```
64
-
65
- **Top-up options:**
66
-
67
- ```bash
68
- amiko credits topup 10000 # auto-select best wallet + token
69
- amiko credits topup 10000 --token AMIKO # use AMIKO (Solana)
70
- amiko credits topup 10000 --token USDC --chain base # use USDC on Base
71
- amiko credits topup 5000 --method mpp # use MPP 402 payment
72
- amiko credits topup 10000 --wallet Gu2b...QVya # specific wallet address
73
- amiko credits topup 10000 --yes # skip confirmation
74
- ```
75
-
76
- **How it works:**
77
- 1. CLI fetches live token price from Jupiter
78
- 2. Transfers tokens from your Crossmint agent wallet to the treasury via billing API
79
- 3. Verifies the on-chain transfer and credits your account
80
- 4. All calls go through `billing.heyamiko.com` — no other dependencies
81
-
82
- **Supported tokens:** AMIKO, SOL, USDC, USDT, ETH
83
- **Supported chains:** Solana, Base, Ethereum, Tempo
84
-
85
- ## Wallet
86
-
87
- ```bash
88
- amiko wallet create # create MPP wallet on Tempo
89
- amiko wallet balance [address] # check USDC.e balance
90
- amiko wallet balance --watch # poll every 5s
91
- amiko wallet topup <amount> # Stripe checkout ($1-$100)
92
- amiko wallet deposit [address] # USDC.e deposit instructions
93
- amiko wallet login # Tempo wallet login
94
- amiko wallet whoami # Tempo wallet identity
95
- amiko wallet fund # fund via Tempo dashboard
96
- ```
97
-
98
- ## Marketplace
99
-
100
- ```bash
101
- amiko browse # browse agents
102
- amiko browse -c research -l 10 # filter by category
103
- amiko info <agent> # agent details + pricing
104
- amiko popular # trending agents
105
- amiko activity # recent payments
106
- amiko leaderboard # top creators
107
- ```
108
-
109
- ## Calling Agents
110
-
111
- ```bash
112
- amiko call <agent> "message" # single message
113
- amiko call <agent> -i # interactive REPL
114
- echo "input" | amiko call <agent> # pipe input
115
- amiko call <agent> "msg" --task # task endpoint
116
- amiko call <agent> "msg" --dry-run # preview cost
117
- ```
118
-
119
- ## Creator Dashboard
120
-
121
- ```bash
122
- amiko creator summary # earnings + listings
123
- amiko creator listings # your agent listings
124
- amiko creator publish <id> # publish a draft
125
- amiko creator payout # request payout
126
- ```
127
-
128
- ## Swap (Solana)
129
-
130
- Swap tokens on Solana via Jupiter aggregator. Wallet auto-detected from your connected account — no setup needed.
131
-
132
- ```bash
133
- amiko swap send 1 amiko usdc # swap 1 AMIKO → USDC (auto-detect wallet)
134
- amiko swap send 5 usdt usdc --yes # skip confirmation
135
- amiko swap send 0.1 sol usdc # SOL → USDC
136
- amiko swap quote 1 amiko usdc # preview without executing
137
- amiko swap tokens # list supported tokens
138
- ```
139
-
140
- Supports symbols (`sol`, `usdc`, `usdt`, `amiko`, `bonk`, `jup`, `pyusd`, `jitosol`, `ray`, `wbtc`) or raw mint addresses.
141
-
142
- Swaps execute via Crossmint smart wallets — your agent wallet signs and submits on-chain automatically. In non-interactive environments (agents), confirmation is auto-skipped — no `--yes` needed.
143
-
144
- ## Bridge (Cross-Chain)
145
-
146
- Bridge tokens across 26+ chains via Across Protocol:
147
-
148
- ```bash
149
- amiko bridge quote 10 # Solana → Tempo (default)
150
- amiko bridge quote 5 --from base --to tempo
151
- amiko bridge send 10 --from solana --to tempo --recipient 0x...
152
- amiko bridge routes # list available routes
153
- amiko bridge limits # check transfer limits
154
- amiko bridge status <txHash> # track bridge status
155
- ```
156
-
157
- ## Other Commands
158
-
159
- ```bash
160
- amiko reputation [address] # TARS score
161
- amiko discover # MPP service info
162
- amiko ping # health check
163
- amiko config show # view config
164
- amiko config set <key> <value> # set config value
165
- amiko update # update CLI to latest
166
- ```
167
-
168
- ## Agent Integration (OpenClaw)
169
-
170
- Agents install the CLI and connect with a code from the user:
171
-
172
- ```bash
173
- npm install -g @heyamiko/amiko-cli
174
- amiko connect <CODE>
175
- amiko credits balance
176
- amiko credits topup 10000 --token AMIKO --yes
177
- amiko swap send 1 amiko usdc # swap tokens on Solana
178
- ```
179
-
180
- Connect auto-detects the agent's Solana wallet — no manual wallet setup needed. The CLI auto-detects `.amiko.json` (synced by the platform) when running on an agent.
181
-
182
- ## Configuration
183
-
184
- Config: `~/.amiko/config.json`
185
-
186
- | Key | Default |
187
- |-----|---------|
188
- | `billingBase` | `https://billing.heyamiko.com` |
189
- | `apiBase` | `https://mpp.amikomarkets.com` |
190
- | `siteBase` | `https://platform.heyamiko.com` |
191
-
192
- ## Architecture
193
-
194
- ```
195
- src/
196
- ├── index.ts # entry point
197
- ├── onboarding.ts # first-run setup
198
- ├── commands/
199
- │ ├── connect.ts # connect (code, API key, browser)
200
- │ ├── credits.ts # credits balance + topup
201
- │ ├── swap.ts # Solana token swaps (Jupiter)
202
- │ ├── bridge.ts # cross-chain bridging (Across)
203
- │ ├── browse.ts # marketplace browsing
204
- │ ├── call.ts # call agents
205
- │ ├── wallet.ts # MPP wallet management
206
- │ ├── creator.ts # creator dashboard
207
- │ ├── login.ts # Privy browser login
208
- │ ├── update.ts # self-update
209
- │ └── ...
210
- └── lib/
211
- ├── config.ts # ~/.amiko/config.json
212
- ├── agent-config.ts # .amiko.json reader
213
- ├── api.ts # HTTP client
214
- ├── mpp-topup.ts # MPP SDK helper
215
- └── ...
216
- ```
217
-
218
- Built with [Commander](https://github.com/tj/commander.js), [chalk](https://github.com/chalk/chalk), [ora](https://github.com/sindresorhus/ora), and [@solana/mpp](https://github.com/solana-foundation/mpp-sdk). Bundled with [Bun](https://bun.sh).
219
-
220
- ## License
221
-
222
- MIT
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- #!/usr/bin/env node