sella-cli 0.6.6 → 0.8.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 +24 -6
- package/dist/api.js +60 -19
- package/dist/clients.js +79 -0
- package/dist/doctor.js +4 -1
- package/dist/index.js +43 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<p align="center">
|
|
20
20
|
<a href="https://sellag.vercel.app">Website</a> ·
|
|
21
|
-
<a href="https://
|
|
21
|
+
<a href="https://docs.selltoagent.dev">Docs</a> ·
|
|
22
22
|
<a href="https://sellag.vercel.app/marketplace">Marketplace</a> ·
|
|
23
23
|
<a href="https://github.com/010100100100011101010100/ogsella/issues">Report a bug</a>
|
|
24
24
|
</p>
|
|
@@ -33,7 +33,7 @@ npx sella-cli
|
|
|
33
33
|
|
|
34
34
|
That one command is the whole setup. The wizard:
|
|
35
35
|
|
|
36
|
-
1. **Detects your agent clients**: Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, Cline.
|
|
36
|
+
1. **Detects your agent clients**: Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, Cline, Codex, Antigravity, OpenClaw.
|
|
37
37
|
2. **Installs the Sella MCP server** into each one. Writes are idempotent and your other MCP servers are preserved.
|
|
38
38
|
3. **Pairs the machine**: paste a setup code from the dashboard, or use your email and a 6-digit code.
|
|
39
39
|
4. **Proves it works** with a live `sella doctor` run at the end.
|
|
@@ -77,7 +77,9 @@ What's in there: a catalogue of 1,100+ machine-payable API providers, plus first
|
|
|
77
77
|
|
|
78
78
|
- **One-command onboarding**, so you never hand-edit an MCP config again.
|
|
79
79
|
- **Pay-per-call in USDC**: fractions of a cent for most calls, multi-chain, with budgets you set and keys you can revoke.
|
|
80
|
-
- **
|
|
80
|
+
- **One search across everything**: datasets, APIs, workflows, and Sella Native products are all discoverable in a single MCP call, ranked by computed quality, so your agent buys mid-task instead of stalling.
|
|
81
|
+
- **Policy-aware buying**: your agent can preview a quote and check it against your budget before paying, and every purchase leaves a decision receipt it can explain.
|
|
82
|
+
- **Businesses**: your agent can open a named run before it starts work, and everything it buys, calls, and decides gets attached to that run. You see what a piece of work actually cost instead of one undifferentiated spend total. Run `sella businesses` to read them from the terminal.
|
|
81
83
|
- **Publishing from a CSV**, so you can sell your own data without opening a browser.
|
|
82
84
|
- **Agent-grade output**: every command supports `--json`, `--yes`, and env vars, with meaningful exit codes. Your CI can run it. Your agent can run it.
|
|
83
85
|
|
|
@@ -91,6 +93,7 @@ What's in there: a catalogue of 1,100+ machine-payable API providers, plus first
|
|
|
91
93
|
| `sella clients` | List detected agent clients. `--install` writes configs, `--client a,b` filters, `--dry-run` previews. |
|
|
92
94
|
| `sella doctor` | Six live checks, from endpoint reachability to a real x402 pay quote. Every failure names its fix. |
|
|
93
95
|
| `sella status` | Your API key and agent wallet balances, each chain labelled live or deposit-only. |
|
|
96
|
+
| `sella businesses` | Your agent's named runs, newest first: status, spend, tool calls, and the outcome it wrote. `--active` or `--closed` filters. |
|
|
94
97
|
| `sella fund` | Per-chain USDC deposit addresses, plus the funding page with QR codes and a fiat on-ramp. |
|
|
95
98
|
| `sella mcp` | Run a local stdio MCP server that proxies Sella with your stored key, for clients that cannot use a remote endpoint. |
|
|
96
99
|
| `sella publish init <file.csv>` | Scaffold `sella-dataset.json` and pre-check the CSV structure. |
|
|
@@ -118,7 +121,21 @@ Then ask your agent:
|
|
|
118
121
|
|
|
119
122
|
> Search Sella for a web search API and tell me what it costs per call.
|
|
120
123
|
|
|
121
|
-
The agent answers using
|
|
124
|
+
The agent answers using Sella's MCP tools, starting with `search_catalog` (one search across datasets, APIs, workflows, and Sella Native products) and `get_listing` for the details, with the key this CLI stored for it. When you fund the agent wallet, it can preview the price with `purchase_preview` and buy what it found.
|
|
125
|
+
|
|
126
|
+
### Keep track of what a piece of work cost
|
|
127
|
+
|
|
128
|
+
Ask your agent to open a business before it starts:
|
|
129
|
+
|
|
130
|
+
> Start a Sella business called "Q3 pricing research", then find me comparable pricing datasets under $20.
|
|
131
|
+
|
|
132
|
+
It calls `business_start`, and from that point every Sella call it makes is attached to that run. When it finishes it closes the run with a summary. Then:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
sella businesses
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You get each run with its spend, tool-call count, and the outcome the agent wrote, instead of a single spend figure you cannot attribute to anything. A business is a label over the agent wallet you already funded, so there are no extra wallets, keys, or balances to manage.
|
|
122
139
|
|
|
123
140
|
### Real-world: publish a CSV and get paid in USDC
|
|
124
141
|
|
|
@@ -204,15 +221,16 @@ Sella has two other ways in: your agent can onboard itself over MCP with your em
|
|
|
204
221
|
| | |
|
|
205
222
|
|---|---|
|
|
206
223
|
| Website | https://sellag.vercel.app |
|
|
207
|
-
| Docs | https://
|
|
224
|
+
| Docs | https://docs.selltoagent.dev |
|
|
208
225
|
| Marketplace | https://sellag.vercel.app/marketplace |
|
|
209
226
|
| Agent task ideas | https://sellag.vercel.app/rfi |
|
|
210
227
|
| npm | https://www.npmjs.com/package/sella-cli |
|
|
211
228
|
| Issues | https://github.com/010100100100011101010100/ogsella/issues |
|
|
229
|
+
| Email | rasesh@buildifi.ai |
|
|
212
230
|
|
|
213
231
|
## Found a bug?
|
|
214
232
|
|
|
215
|
-
Found a bug? Have an idea? [
|
|
233
|
+
Found a bug? Have an idea? [Open an issue](https://github.com/010100100100011101010100/ogsella/issues) or [email us](mailto:rasesh@buildifi.ai). We read every one.
|
|
216
234
|
|
|
217
235
|
## License
|
|
218
236
|
|
package/dist/api.js
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
* the CLI speaks the exact same tools/call surface agents use (sella_setup_claim,
|
|
4
4
|
* sella_auth_start/complete), so CLI, web, and agent onboarding cannot drift.
|
|
5
5
|
*/
|
|
6
|
-
export async function callToolRaw(mcpUrl, name, args, fetchImpl = fetch) {
|
|
6
|
+
export async function callToolRaw(mcpUrl, name, args, fetchImpl = fetch, apiKey) {
|
|
7
7
|
let res;
|
|
8
8
|
try {
|
|
9
9
|
res = await fetchImpl(mcpUrl, {
|
|
10
10
|
method: 'POST',
|
|
11
|
-
headers: {
|
|
11
|
+
headers: {
|
|
12
|
+
'content-type': 'application/json',
|
|
13
|
+
...(apiKey ? { authorization: `Bearer ${apiKey}` } : {}),
|
|
14
|
+
},
|
|
12
15
|
body: JSON.stringify({ jsonrpc: '2.0', id: name, method: 'tools/call', params: { name, arguments: args } }),
|
|
13
16
|
});
|
|
14
17
|
}
|
|
@@ -17,7 +20,9 @@ export async function callToolRaw(mcpUrl, name, args, fetchImpl = fetch) {
|
|
|
17
20
|
'Check your connection, proxy settings, or SELLA_MCP_URL.');
|
|
18
21
|
}
|
|
19
22
|
if (res.status === 429) {
|
|
20
|
-
throw new Error(
|
|
23
|
+
throw new Error(apiKey
|
|
24
|
+
? 'Sella rate limit reached. Wait a moment and try again.'
|
|
25
|
+
: 'Sandbox rate limit reached. Run `sella pair` for unmetered access.');
|
|
21
26
|
}
|
|
22
27
|
if (!res.ok) {
|
|
23
28
|
throw new Error(`Sella endpoint at ${mcpUrl} responded ${res.status}. Check SELLA_MCP_URL.`);
|
|
@@ -38,24 +43,60 @@ export async function callToolRaw(mcpUrl, name, args, fetchImpl = fetch) {
|
|
|
38
43
|
throw new Error('Unexpected response shape from the Sella MCP endpoint.');
|
|
39
44
|
}
|
|
40
45
|
export const callAuthTool = (mcpUrl, name, args, fetchImpl = fetch) => callToolRaw(mcpUrl, name, args, fetchImpl);
|
|
41
|
-
/**
|
|
46
|
+
/** Price on a search_catalog result is `{ amountUSDC, minUSDC, ... }`; older shapes were a number. */
|
|
47
|
+
function priceUSDCOf(entry) {
|
|
48
|
+
const raw = entry?.price ?? entry?.priceUSDC;
|
|
49
|
+
const n = typeof raw === 'number' ? raw : Number(raw?.amountUSDC ?? raw?.minUSDC);
|
|
50
|
+
return Number.isFinite(n) ? n : undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Zero-identity demo: ONE free `search_catalog` call across every listing kind.
|
|
54
|
+
*
|
|
55
|
+
* Replaces the previous pair of calls to `search_datasets` + `list_market_apis` (both deprecated
|
|
56
|
+
* aliases scheduled for removal, and the latter reads a backend that can be empty or asleep).
|
|
57
|
+
* One call now covers datasets, APIs, workflows and Sella Native products, so the sandbox shows
|
|
58
|
+
* the same ranked surface an agent sees.
|
|
59
|
+
*/
|
|
42
60
|
export async function sandboxSearch(mcpUrl, query, fetchImpl = fetch) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
const payload = await callToolRaw(mcpUrl, 'search_catalog', { query, limit: 10 }, fetchImpl);
|
|
62
|
+
const results = Array.isArray(payload?.results)
|
|
63
|
+
? payload.results
|
|
64
|
+
: Array.isArray(payload)
|
|
65
|
+
? payload
|
|
66
|
+
: [];
|
|
67
|
+
const datasets = results
|
|
68
|
+
.filter((r) => r?.kind === 'dataset')
|
|
69
|
+
.slice(0, 5)
|
|
70
|
+
.map((r) => ({
|
|
71
|
+
id: String(r?.id ?? ''),
|
|
72
|
+
title: r?.title,
|
|
73
|
+
tier: r?.attributes?.tier,
|
|
74
|
+
priceUSDC: priceUSDCOf(r),
|
|
75
|
+
}));
|
|
76
|
+
// Everything that is not a dataset (api, workflow, native) prints in the "api" column.
|
|
77
|
+
const apis = results
|
|
78
|
+
.filter((r) => r?.kind && r.kind !== 'dataset')
|
|
79
|
+
.slice(0, 5)
|
|
80
|
+
.map((r) => ({
|
|
81
|
+
name: r?.title,
|
|
82
|
+
description: r?.description,
|
|
83
|
+
priceUSDC: priceUSDCOf(r),
|
|
84
|
+
chains: Array.isArray(r?.chains) ? r.chains : undefined,
|
|
85
|
+
}));
|
|
86
|
+
return { datasets, apis };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* `business_list`: the caller's named agent runs, newest first. Businesses label the existing
|
|
90
|
+
* agent wallet rather than creating new ones, so this is a read over the same key the CLI stored.
|
|
91
|
+
*/
|
|
92
|
+
export async function listBusinesses(mcpUrl, apiKey, args = {}, fetchImpl = fetch) {
|
|
93
|
+
const payload = await callToolRaw(mcpUrl, 'business_list', { ...args }, fetchImpl, apiKey);
|
|
94
|
+
if (payload?.error)
|
|
95
|
+
throw new Error(String(payload.error));
|
|
56
96
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
97
|
+
businesses: Array.isArray(payload?.businesses) ? payload.businesses : [],
|
|
98
|
+
active: payload?.active ?? null,
|
|
99
|
+
count: Number(payload?.count ?? 0),
|
|
59
100
|
};
|
|
60
101
|
}
|
|
61
102
|
export const claimSetupCode = (mcpUrl, code, fetchImpl) => callAuthTool(mcpUrl, 'sella_setup_claim', { code, client: 'sella-cli' }, fetchImpl);
|
package/dist/clients.js
CHANGED
|
@@ -27,6 +27,27 @@ function stdioBridgeEntry(mcpUrl, apiKey) {
|
|
|
27
27
|
args: ['-y', 'mcp-remote', mcpUrl, ...(apiKey ? ['--header', `Authorization: Bearer ${apiKey}`] : [])],
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Codex keeps MCP servers in ~/.codex/config.toml. We do a targeted section upsert instead of a
|
|
32
|
+
* TOML parse/serialize round-trip so user comments and formatting survive. The `url` key selects
|
|
33
|
+
* streamable HTTP; `http_headers` carries static auth headers (both per the Codex config docs).
|
|
34
|
+
* Only the standard `[mcp_servers.sella]` table form is recognized; exotic spellings (dotted keys,
|
|
35
|
+
* inline tables) are left alone and would shadow ours — the backup covers that case.
|
|
36
|
+
*/
|
|
37
|
+
export function upsertCodexToml(raw, mcpUrl, apiKey) {
|
|
38
|
+
const lines = [`[mcp_servers.sella]`, `url = "${mcpUrl}"`];
|
|
39
|
+
if (apiKey)
|
|
40
|
+
lines.push(`http_headers = { "Authorization" = "Bearer ${apiKey}" }`);
|
|
41
|
+
const section = lines.join('\n');
|
|
42
|
+
// Our table (plus any of its sub-tables) up to the next unrelated header or end of file.
|
|
43
|
+
const existing = /(^|\n)\[mcp_servers\.sella\][\s\S]*?(?=\n\[(?!mcp_servers\.sella[.\]])|$)/;
|
|
44
|
+
if (existing.test(raw)) {
|
|
45
|
+
const next = raw.replace(existing, (_match, lead) => `${lead}${section}`);
|
|
46
|
+
return next.endsWith('\n') ? next : `${next}\n`;
|
|
47
|
+
}
|
|
48
|
+
const head = raw.trimEnd();
|
|
49
|
+
return `${head ? `${head}\n\n` : ''}${section}\n`;
|
|
50
|
+
}
|
|
30
51
|
const CLIENTS = [
|
|
31
52
|
{
|
|
32
53
|
id: 'claude-code',
|
|
@@ -91,6 +112,43 @@ const CLIENTS = [
|
|
|
91
112
|
doc.mcpServers.sella = stdioBridgeEntry(mcpUrl, apiKey);
|
|
92
113
|
},
|
|
93
114
|
},
|
|
115
|
+
{
|
|
116
|
+
id: 'codex',
|
|
117
|
+
name: 'Codex',
|
|
118
|
+
marker: (env) => path.join(env.home, '.codex'),
|
|
119
|
+
configPath: (env) => path.join(env.home, '.codex', 'config.toml'),
|
|
120
|
+
applyRaw: upsertCodexToml,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
// Antigravity IDE + CLI share one MCP config at ~/.gemini/config/mcp_config.json.
|
|
124
|
+
// Remote servers use `serverUrl` (`httpUrl` is deprecated).
|
|
125
|
+
id: 'antigravity',
|
|
126
|
+
name: 'Antigravity',
|
|
127
|
+
marker: (env) => appSupport(env, 'Antigravity'),
|
|
128
|
+
configPath: (env) => path.join(env.home, '.gemini', 'config', 'mcp_config.json'),
|
|
129
|
+
apply: (doc, mcpUrl, apiKey) => {
|
|
130
|
+
doc.mcpServers = doc.mcpServers || {};
|
|
131
|
+
const entry = { serverUrl: mcpUrl };
|
|
132
|
+
if (apiKey)
|
|
133
|
+
entry.headers = { Authorization: `Bearer ${apiKey}` };
|
|
134
|
+
doc.mcpServers.sella = entry;
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
// OpenClaw stores MCP servers under mcp.servers in ~/.openclaw/openclaw.json.
|
|
139
|
+
id: 'openclaw',
|
|
140
|
+
name: 'OpenClaw',
|
|
141
|
+
marker: (env) => path.join(env.home, '.openclaw'),
|
|
142
|
+
configPath: (env) => path.join(env.home, '.openclaw', 'openclaw.json'),
|
|
143
|
+
apply: (doc, mcpUrl, apiKey) => {
|
|
144
|
+
doc.mcp = doc.mcp || {};
|
|
145
|
+
doc.mcp.servers = doc.mcp.servers || {};
|
|
146
|
+
const entry = { url: mcpUrl, transport: 'streamable-http' };
|
|
147
|
+
if (apiKey)
|
|
148
|
+
entry.headers = { Authorization: `Bearer ${apiKey}` };
|
|
149
|
+
doc.mcp.servers.sella = entry;
|
|
150
|
+
},
|
|
151
|
+
},
|
|
94
152
|
];
|
|
95
153
|
export function detectClients(env = defaultEnv()) {
|
|
96
154
|
return CLIENTS.map((spec) => ({
|
|
@@ -108,6 +166,25 @@ export function installSellaIntoClient(id, opts) {
|
|
|
108
166
|
throw new Error(`Unknown client: ${id}`);
|
|
109
167
|
const configPath = spec.configPath(env);
|
|
110
168
|
const exists = fs.existsSync(configPath);
|
|
169
|
+
// Raw-text configs (Codex's TOML): targeted rewrite, byte-compare for idempotency.
|
|
170
|
+
if (spec.applyRaw) {
|
|
171
|
+
const raw = exists ? fs.readFileSync(configPath, 'utf8') : '';
|
|
172
|
+
const next = spec.applyRaw(raw, opts.mcpUrl, opts.apiKey);
|
|
173
|
+
if (exists && raw === next) {
|
|
174
|
+
return { id, configPath, action: 'unchanged' };
|
|
175
|
+
}
|
|
176
|
+
let backupPath;
|
|
177
|
+
if (!opts.dryRun) {
|
|
178
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
179
|
+
if (exists && raw.trim()) {
|
|
180
|
+
backupPath = `${configPath}.sella-backup`;
|
|
181
|
+
if (!fs.existsSync(backupPath))
|
|
182
|
+
fs.writeFileSync(backupPath, raw);
|
|
183
|
+
}
|
|
184
|
+
fs.writeFileSync(configPath, next);
|
|
185
|
+
}
|
|
186
|
+
return { id, configPath, action: exists ? 'updated' : 'created', backupPath };
|
|
187
|
+
}
|
|
111
188
|
let doc = {};
|
|
112
189
|
if (exists) {
|
|
113
190
|
const raw = fs.readFileSync(configPath, 'utf8').trim();
|
|
@@ -121,6 +198,8 @@ export function installSellaIntoClient(id, opts) {
|
|
|
121
198
|
}
|
|
122
199
|
}
|
|
123
200
|
const before = JSON.stringify(doc);
|
|
201
|
+
if (!spec.apply)
|
|
202
|
+
throw new Error(`Client ${id} has no config writer`);
|
|
124
203
|
spec.apply(doc, opts.mcpUrl, opts.apiKey);
|
|
125
204
|
const after = JSON.stringify(doc, null, 2);
|
|
126
205
|
if (exists && JSON.stringify(JSON.parse(before)) === JSON.stringify(JSON.parse(after))) {
|
package/dist/doctor.js
CHANGED
|
@@ -91,7 +91,10 @@ export async function runDoctor(opts) {
|
|
|
91
91
|
// 4. auth — the stored key actually authenticates a protected call
|
|
92
92
|
if (stored) {
|
|
93
93
|
try {
|
|
94
|
-
const called = await rpc(opts.mcpUrl,
|
|
94
|
+
const called = await rpc(opts.mcpUrl,
|
|
95
|
+
// search_catalog, not the deprecated list_datasets alias: this check must outlive the
|
|
96
|
+
// one-release deprecation window for the legacy discovery names.
|
|
97
|
+
{ method: 'tools/call', params: { name: 'search_catalog', arguments: { limit: 1 } } }, fetchImpl, stored.apiKey);
|
|
95
98
|
const isError = Boolean(called?.result?.isError) || Boolean(called?.error);
|
|
96
99
|
checks.push({
|
|
97
100
|
id: 'auth',
|
package/dist/index.js
CHANGED
|
@@ -6,14 +6,14 @@ import { pair } from './pairing.js';
|
|
|
6
6
|
import { runDoctor, runStatus, loadStoredKey } from './doctor.js';
|
|
7
7
|
import { runMcpBridge } from './mcp-bridge.js';
|
|
8
8
|
import { scaffoldCard, pushDataset, CARD_FILENAME } from './publish.js';
|
|
9
|
-
import { sandboxSearch } from './api.js';
|
|
9
|
+
import { sandboxSearch, listBusinesses } from './api.js';
|
|
10
10
|
import { getFundingInfo, annotateFunding } from './fund.js';
|
|
11
11
|
import { capabilityLabel } from './chains.js';
|
|
12
12
|
import { defaultIo, Printer } from './output.js';
|
|
13
13
|
import { Ui } from './ui.js';
|
|
14
14
|
import { recordCliEvent, saveTelemetryDecision, shouldPromptTelemetry } from './telemetry.js';
|
|
15
15
|
const DEFAULT_MCP_URL = 'https://sellag.vercel.app/api/mcp';
|
|
16
|
-
const VERSION = '0.
|
|
16
|
+
const VERSION = '0.8.0';
|
|
17
17
|
function parseFlags(argv) {
|
|
18
18
|
const flags = {
|
|
19
19
|
json: false, yes: false, noColor: false, dryRun: false, noKeychain: false,
|
|
@@ -62,6 +62,7 @@ Commands:
|
|
|
62
62
|
clients List detected agent clients (--install to write configs)
|
|
63
63
|
doctor Verify the install: endpoint, credentials, auth, wallets, pay-quote
|
|
64
64
|
status Show your key + AgentWallet balances
|
|
65
|
+
businesses Show your agent's named runs: spend, tool calls, outcome
|
|
65
66
|
fund Show deposit addresses + funding links to add USDC to your agent wallet
|
|
66
67
|
mcp Run as a local stdio MCP server that proxies Sella with your stored key
|
|
67
68
|
publish Publish a dataset from a CSV: 'publish init <file.csv>' then 'publish push'
|
|
@@ -70,7 +71,7 @@ Options:
|
|
|
70
71
|
--setup-code <code> Pair with a dashboard setup code (also: SELLA_SETUP_CODE env)
|
|
71
72
|
--email <address> Pair with email + OTP (interactive)
|
|
72
73
|
--card <path> Dataset card for 'publish push' (default ./sella-dataset.json)
|
|
73
|
-
--client <ids> Comma-separated subset (claude-code,claude-desktop,cursor,windsurf,vscode,cline)
|
|
74
|
+
--client <ids> Comma-separated subset (claude-code,claude-desktop,cursor,windsurf,vscode,cline,codex,antigravity,openclaw)
|
|
74
75
|
--no-keychain Skip the OS keychain; store the key in a 0600 file (also: SELLA_NO_KEYCHAIN)
|
|
75
76
|
--dry-run Show what would change without writing
|
|
76
77
|
--json Machine-readable output (one JSON document on stdout)
|
|
@@ -86,7 +87,7 @@ Environment:
|
|
|
86
87
|
|
|
87
88
|
Links:
|
|
88
89
|
Website https://sellag.vercel.app
|
|
89
|
-
Docs https://
|
|
90
|
+
Docs https://docs.selltoagent.dev
|
|
90
91
|
Issues https://github.com/010100100100011101010100/ogsella/issues
|
|
91
92
|
`;
|
|
92
93
|
function selectClientIds(flags, detected) {
|
|
@@ -339,7 +340,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
|
|
|
339
340
|
io.stdout(VERSION);
|
|
340
341
|
// TTY-only: scripts capturing `sella --version` must still get a bare semver.
|
|
341
342
|
if (io.isTTY)
|
|
342
|
-
io.stdout('docs: https://
|
|
343
|
+
io.stdout('docs: https://docs.selltoagent.dev · issues: https://github.com/010100100100011101010100/ogsella/issues');
|
|
343
344
|
return 0;
|
|
344
345
|
}
|
|
345
346
|
if (flags.help) {
|
|
@@ -483,6 +484,43 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
|
|
|
483
484
|
}
|
|
484
485
|
return 0;
|
|
485
486
|
}
|
|
487
|
+
case 'businesses': {
|
|
488
|
+
const stored = loadStoredKey(ctx.env);
|
|
489
|
+
if (!stored) {
|
|
490
|
+
printer.error('Not paired yet. Run `sella pair` (or `sella init`) first.');
|
|
491
|
+
return 2;
|
|
492
|
+
}
|
|
493
|
+
const statusFlag = flags.positional.includes('--active')
|
|
494
|
+
? 'active'
|
|
495
|
+
: flags.positional.includes('--closed')
|
|
496
|
+
? 'closed'
|
|
497
|
+
: undefined;
|
|
498
|
+
const result = await listBusinesses(ctx.mcpUrl, stored.apiKey, {
|
|
499
|
+
limit: 20,
|
|
500
|
+
...(statusFlag ? { status: statusFlag } : {}),
|
|
501
|
+
});
|
|
502
|
+
printer.jsonOut(result);
|
|
503
|
+
if (!flags.json) {
|
|
504
|
+
if (!result.businesses.length) {
|
|
505
|
+
printer.info('No businesses yet. Ask your agent to start one before it works:\n' +
|
|
506
|
+
' "Start a Sella business called <name>, then research X."');
|
|
507
|
+
return 0;
|
|
508
|
+
}
|
|
509
|
+
printer.info(`Your agent's runs (${result.count}):`);
|
|
510
|
+
for (const b of result.businesses) {
|
|
511
|
+
const t = b.totals || {};
|
|
512
|
+
const spend = `$${Number(t.spendUSDC || 0).toFixed(2)}`;
|
|
513
|
+
const mark = b.status === 'active' ? '●' : '·';
|
|
514
|
+
printer.info(` ${mark} ${b.name}`);
|
|
515
|
+
printer.info(` ${String(b.status).padEnd(7)} ${spend.padStart(8)} ${String(t.toolCalls || 0).padStart(4)} calls ${b.businessId}`);
|
|
516
|
+
const summary = b.outcome || b.goal;
|
|
517
|
+
if (summary)
|
|
518
|
+
printer.info(` ${summary.length > 88 ? `${summary.slice(0, 88)}…` : summary}`);
|
|
519
|
+
}
|
|
520
|
+
printer.info('\nFull detail: https://sellag.vercel.app/dashboard/businesses');
|
|
521
|
+
}
|
|
522
|
+
return 0;
|
|
523
|
+
}
|
|
486
524
|
case 'publish': {
|
|
487
525
|
const sub = flags.positional[1];
|
|
488
526
|
const origin = ctx.mcpUrl.replace(/\/api\/mcp\/?$/, '') || 'https://sellag.vercel.app';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sella-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Connect your AI agent to Sella, the marketplace where agents buy data and APIs, in one command: npx sella-cli. Installs the Sella MCP server into Claude Code, Cursor and more, then pairs, verifies, funds, and publishes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|