sella-cli 0.9.0 → 0.9.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/README.md CHANGED
@@ -96,6 +96,7 @@ What's in there: a catalogue of 1,500+ machine-payable API providers with 8,000+
96
96
  | `sella businesses` | Your agent's named runs, newest first: status, spend, tool calls, and the outcome it wrote. `--active` or `--closed` filters. |
97
97
  | `sella fund` | Per-chain USDC deposit addresses, plus the funding page with QR codes and a fiat on-ramp. |
98
98
  | `sella mcp` | Run a local stdio MCP server that proxies Sella with your stored key, for clients that cannot use a remote endpoint. |
99
+ | `sella skill` | Show the cached agent instruction bundle and its version. `sella skill update` refreshes it. A pinned local copy means two runs of the same prompt read the same instructions, instead of re-fetching 25 KB that can change mid-task. |
99
100
  | `sella publish init <file.csv>` | Scaffold `sella-dataset.json` and pre-check the CSV structure. |
100
101
  | `sella publish push` | Publish the dataset through the same route the web dashboard uses. |
101
102
 
package/dist/chains.js CHANGED
@@ -47,8 +47,17 @@ export async function fetchChainRegistry(apiBase, fetchImpl = fetch) {
47
47
  * What can the agent actually do with funds on this chain *today*?
48
48
  * - `live` — Sella can settle an outbound provider payment from here → spendable now.
49
49
  * - `deposit-only` — accepts deposits, but outbound settle isn't proven yet (fund it, can't spend).
50
- * - `inbound-only` — settles inbound (agents paying Sella) with no agent-wallet spend, e.g. Stellar.
50
+ * - `inbound-only` — settles inbound (agents paying Sella) with no agent-wallet spend.
51
51
  * - `unknown` — chain not in the registry (or registry unreachable).
52
+ *
53
+ * `inbound-only` used to name Stellar as its example. Stellar was removed from the registry on
54
+ * 2026-08-03 and there is no replacement to name: as of 2026-08-31 NO chain carries
55
+ * `settle.inbound: true`, so this branch is unreachable through the registry alone.
56
+ *
57
+ * That is not a bug in either place. Inbound is switched on per deployment by
58
+ * `X402_INBOUND_NETWORKS`, while the registry flag records only what has been PROVEN on-chain,
59
+ * which is deliberately slower-moving. The branch stays because a row can set the flag at any time,
60
+ * and reporting `unknown` for such a chain would be worse than reporting `inbound-only`.
52
61
  */
53
62
  export function chainCapability(info) {
54
63
  if (!info)
package/dist/clients.js CHANGED
@@ -193,7 +193,7 @@ export function installSellaIntoClient(id, opts) {
193
193
  doc = JSON.parse(raw);
194
194
  }
195
195
  catch {
196
- throw new Error(`${spec.name} config at ${configPath} is not valid JSON fix or remove it, then re-run.`);
196
+ throw new Error(`${spec.name} config at ${configPath} is not valid JSON. Fix or remove it, then re-run.`);
197
197
  }
198
198
  }
199
199
  }
@@ -45,7 +45,7 @@ export function saveCredentials(payload, opts) {
45
45
  files.push(p);
46
46
  }
47
47
  const custodyNote = keychainOk
48
- ? `API key stored in the macOS keychain (service "${KEYCHAIN_SERVICE}"). Wallet files are owner-read-only; client configs carry the key in plaintext that is how MCP clients read headers today.`
49
- : `Secrets stored as owner-read-only files (0600)${env.platform === 'win32' ? ' on Windows, protect your user profile' : ''}. Client configs carry the key in plaintext that is how MCP clients read headers today. Never commit or share these files.`;
48
+ ? `API key stored in the macOS keychain (service "${KEYCHAIN_SERVICE}"). Wallet files are owner-read-only; client configs carry the key in plaintext, which is how MCP clients read headers today.`
49
+ : `Secrets stored as owner-read-only files (0600)${env.platform === 'win32' ? '. On Windows, protect your user profile' : ''}. Client configs carry the key in plaintext, which is how MCP clients read headers today. Never commit or share these files.`;
50
50
  return { files, keyStorage: keychainOk ? 'keychain' : 'file', custodyNote };
51
51
  }
package/dist/doctor.js CHANGED
@@ -55,8 +55,8 @@ export async function runDoctor(opts) {
55
55
  id: 'endpoint',
56
56
  label: 'Sella MCP endpoint reachable',
57
57
  ok: toolNames.length > 0,
58
- detail: `${opts.mcpUrl} ${toolNames.length} tools advertised`,
59
- ...(toolNames.length === 0 ? { fix: 'The server answered but advertised no tools check SELLA_MCP_URL points at /api/mcp.' } : {}),
58
+ detail: `${opts.mcpUrl}: ${toolNames.length} tools advertised`,
59
+ ...(toolNames.length === 0 ? { fix: 'The server answered but advertised no tools. Check SELLA_MCP_URL points at /api/mcp.' } : {}),
60
60
  });
61
61
  }
62
62
  catch (err) {
@@ -76,7 +76,7 @@ export async function runDoctor(opts) {
76
76
  label: 'Onboarding tools advertised',
77
77
  ok: hasBootstrap,
78
78
  detail: hasBootstrap ? 'sella_setup_claim + sella_auth_* available' : `advertised: ${toolNames.slice(0, 6).join(', ')}…`,
79
- ...(hasBootstrap ? {} : { fix: 'The endpoint is not a Sella MCP server fix SELLA_MCP_URL.' }),
79
+ ...(hasBootstrap ? {} : { fix: 'The endpoint is not a Sella MCP server. Fix SELLA_MCP_URL.' }),
80
80
  });
81
81
  }
82
82
  // 3. credentials — stored key present
@@ -122,7 +122,7 @@ export async function runDoctor(opts) {
122
122
  try {
123
123
  JSON.parse(fs.readFileSync(walletPath, 'utf8'));
124
124
  walletOk = true;
125
- walletDetail = `${walletPath} ok${fs.existsSync(agentWalletPath) ? ' · AgentWallet config ok' : ' · AgentWallet config absent (proxy payments off re-run `sella pair` later)'}`;
125
+ walletDetail = `${walletPath} ok${fs.existsSync(agentWalletPath) ? ' · AgentWallet config ok' : ' · AgentWallet config absent (proxy payments off, re-run `sella pair` later)'}`;
126
126
  }
127
127
  catch {
128
128
  /* stays missing/corrupt */
@@ -132,7 +132,7 @@ export async function runDoctor(opts) {
132
132
  label: 'Wallet config files',
133
133
  ok: walletOk,
134
134
  detail: walletDetail,
135
- ...(walletOk ? {} : { fix: 'Run `sella pair` wallet keys are delivered once at pairing.' }),
135
+ ...(walletOk ? {} : { fix: 'Run `sella pair`. Wallet keys are delivered once at pairing.' }),
136
136
  });
137
137
  // 6. quote — paid-call economics computable (price + platform fee + settleable chains)
138
138
  try {
@@ -147,7 +147,7 @@ export async function runDoctor(opts) {
147
147
  detail: quote
148
148
  ? `${slug}: $${quote.totalUSD} total (${quote.feeBps} bps fee) on ${quote.payChains?.join('/') || 'no chains'}`
149
149
  : 'catalog reachable but no quote returned',
150
- ...(quote ? {} : { fix: 'Catalog/quote API unavailable paid calls may still work; check the server logs.' }),
150
+ ...(quote ? {} : { fix: 'Catalog/quote API unavailable. Paid calls may still work; check the server logs.' }),
151
151
  });
152
152
  }
153
153
  catch (err) {
@@ -156,7 +156,7 @@ export async function runDoctor(opts) {
156
156
  label: 'x402 pay quote',
157
157
  ok: false,
158
158
  detail: err instanceof Error ? err.message : 'quote fetch failed',
159
- fix: 'Could not fetch a pay quote from the catalog API check the marketplace is up.',
159
+ fix: 'Could not fetch a pay quote from the catalog API. Check the marketplace is up.',
160
160
  });
161
161
  }
162
162
  return { ok: checks.every((c) => c.ok), checks };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import * as readline from 'node:readline/promises';
3
3
  import * as path from 'node:path';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
4
6
  import { detectClients, installSellaIntoClient, defaultEnv } from './clients.js';
5
7
  import { pair } from './pairing.js';
6
8
  import { runDoctor, runStatus, loadStoredKey } from './doctor.js';
@@ -14,7 +16,33 @@ import { defaultIo, Printer } from './output.js';
14
16
  import { Ui } from './ui.js';
15
17
  import { recordCliEvent, saveTelemetryDecision, shouldPromptTelemetry } from './telemetry.js';
16
18
  const DEFAULT_MCP_URL = 'https://sellag.vercel.app/api/mcp';
17
- const VERSION = '0.8.0';
19
+ /**
20
+ * Read from package.json rather than hardcoded.
21
+ *
22
+ * It was hardcoded, and it drifted: this constant still said 0.8.0 while package.json and npm both
23
+ * served 0.9.0. `sella --version` therefore reported the wrong version on every install for weeks,
24
+ * the banner printed it, and `recordCliEvent` shipped it, so telemetry attributed 0.9.0 runs to
25
+ * 0.8.0. A version string that has to be bumped in two places is a version string that will be
26
+ * bumped in one.
27
+ *
28
+ * `../package.json` resolves correctly from both dist/index.js and src/index.ts, and npm always
29
+ * includes package.json in the tarball regardless of the `files` list, so it is there at runtime.
30
+ * Read with fs rather than a JSON import: import attributes are not available across the whole
31
+ * `engines: >=18` range this package claims to support.
32
+ */
33
+ const VERSION = (() => {
34
+ try {
35
+ const here = path.dirname(fileURLToPath(import.meta.url));
36
+ const raw = readFileSync(path.join(here, '..', 'package.json'), 'utf8');
37
+ const v = JSON.parse(raw)?.version;
38
+ return typeof v === 'string' && v ? v : 'unknown';
39
+ }
40
+ catch {
41
+ // Never let a missing or unreadable manifest take down the CLI: the version is informational
42
+ // everywhere it is used.
43
+ return 'unknown';
44
+ }
45
+ })();
18
46
  function parseFlags(argv) {
19
47
  const flags = {
20
48
  json: false, yes: false, noColor: false, dryRun: false, noKeychain: false,
@@ -51,7 +79,7 @@ function parseFlags(argv) {
51
79
  }
52
80
  return flags;
53
81
  }
54
- const HELP = `sella the Sella onboarding CLI
82
+ const HELP = `sella: the Sella onboarding CLI
55
83
 
56
84
  Usage: sella <command> [options]
57
85
 
@@ -59,7 +87,7 @@ Commands:
59
87
  init Guided onboarding: install the Sella MCP server, pair, verify
60
88
  (also runs when you invoke \`sella\` with no command and no credentials yet)
61
89
  pair Pair this machine only (setup code or email + OTP)
62
- sandbox Try Sella with no signup search the live marketplace (rate-limited)
90
+ sandbox Try Sella with no signup. Search the live marketplace (rate-limited)
63
91
  clients List detected agent clients (--install to write configs)
64
92
  doctor Verify the install: endpoint, credentials, auth, wallets, pay-quote
65
93
  status Show your key + AgentWallet balances
@@ -154,12 +182,12 @@ async function runPair(ctx, flags, emit, extra = {}) {
154
182
  emit.error(outcome.error);
155
183
  return { code: outcome.exitCode, summary: { paired: false, error: outcome.error } };
156
184
  }
157
- emit.ok(`Paired via ${outcome.method} — status: ${outcome.payload.status || 'ok'}`);
185
+ emit.ok(`Paired via ${outcome.method}. Status: ${outcome.payload.status || 'ok'}`);
158
186
  for (const file of outcome.save.files)
159
187
  emit.ok(`wrote ${file}`);
160
188
  emit.info(outcome.save.custodyNote);
161
189
  if (outcome.payload.agentWallet?.status === 'unavailable') {
162
- emit.warn(`AgentWallet not provisioned (${outcome.payload.agentWallet.reason || 'backend unavailable'}) MCP access still works; re-run \`sella pair\` later.`);
190
+ emit.warn(`AgentWallet not provisioned (${outcome.payload.agentWallet.reason || 'backend unavailable'}). MCP access still works; re-run \`sella pair\` later.`);
163
191
  }
164
192
  return {
165
193
  code: 0,
@@ -193,7 +221,7 @@ async function collectPairChoice(ui, flags, ctx) {
193
221
  if (method === 'setup-code') {
194
222
  const code = await ui.text('Paste your setup code', {
195
223
  placeholder: 'SELLA-XXXX-XXXX-XXXX-XXXX',
196
- validate: (v) => (v ? undefined : 'A setup code is required mint one on the dashboard (Connect your agent).'),
224
+ validate: (v) => (v ? undefined : 'A setup code is required. Mint one on the dashboard (Connect your agent).'),
197
225
  });
198
226
  return { setupCode: code };
199
227
  }
@@ -282,14 +310,14 @@ async function cmdInit(ctx, flags, printer) {
282
310
  (verify.ok ? sp.succeed : sp.succeed)(`${passed}/${verify.checks.length} checks passed`);
283
311
  ui.checkStrip(verify.checks.map((c) => ({ id: c.id, ok: c.ok })));
284
312
  for (const check of verify.checks.filter((c) => !c.ok)) {
285
- ui.warn(`${check.label} ${check.detail}`);
313
+ ui.warn(`${check.label}: ${check.detail}`);
286
314
  if (check.fix)
287
315
  ui.detail(`fix: ${check.fix}`);
288
316
  }
289
317
  verifySummary = { ok: verify.ok, passed, total: verify.checks.length };
290
318
  }
291
319
  catch (err) {
292
- sp.fail('Verify could not run (network?) try `sella doctor` later.');
320
+ sp.fail('Verify could not run (network?). Try `sella doctor` later.');
293
321
  verifySummary = { ok: false, error: err instanceof Error ? err.message : String(err) };
294
322
  }
295
323
  // Cache the agent instruction bundle alongside the credentials, so the agent reads its
@@ -312,7 +340,7 @@ async function cmdInit(ctx, flags, printer) {
312
340
  'Health check: sella doctor',
313
341
  ];
314
342
  if (awStatus === 'unavailable') {
315
- lines.push('AgentWallet pending (backend not configured) — re-run `sella pair` later.');
343
+ lines.push('AgentWallet pending (backend not configured). Re-run `sella pair` later.');
316
344
  }
317
345
  ui.note('Sella is connected', lines, flags.dryRun ? 'plain' : awStatus === 'unavailable' ? 'warn' : 'ok');
318
346
  // RFI: ready-to-send prompts for real agent tasks — the "now what?" answer.
@@ -320,9 +348,9 @@ async function cmdInit(ctx, flags, printer) {
320
348
  ui.bar();
321
349
  ui.step('Ideas to try with your agent (each is a ready-to-send prompt):');
322
350
  ui.rows([
323
- { tag: 'invest', text: `Validate a startup idea for $25 ${rfi}?uc=twenty-five-dollar-study`, tone: 'brand' },
324
- { tag: 'daily', text: `Get a daily morning brief ${rfi}?uc=morning-brief`, tone: 'ok' },
325
- { tag: 'free', text: `Test Sella without spending ${rfi}?uc=zero-dollar-demo`, tone: 'dim' },
351
+ { tag: 'invest', text: `Validate a startup idea for $25: ${rfi}?uc=twenty-five-dollar-study`, tone: 'brand' },
352
+ { tag: 'daily', text: `Get a daily morning brief: ${rfi}?uc=morning-brief`, tone: 'ok' },
353
+ { tag: 'free', text: `Test Sella without spending: ${rfi}?uc=zero-dollar-demo`, tone: 'dim' },
326
354
  ]);
327
355
  ui.detail(`Browse all ideas: ${rfi}`);
328
356
  // One-time telemetry choice: only a human at a TTY is ever asked, and only once.
@@ -336,10 +364,10 @@ async function cmdInit(ctx, flags, printer) {
336
364
  ui.detail(share === 'share' ? 'Thanks. Opt out anytime: SELLA_TELEMETRY=0' : 'Nothing will be sent. Opt in later: SELLA_TELEMETRY=1');
337
365
  }
338
366
  const took = Math.max(1, Math.round((Date.now() - startedAt) / 1000));
339
- ui.outro(flags.dryRun ? 'Dry run complete nothing was written.' : `Done in ${took}s your agents can now buy on Sella.`);
367
+ ui.outro(flags.dryRun ? 'Dry run complete. Nothing was written.' : `Done in ${took}s. Your agents can now buy on Sella.`);
340
368
  }
341
369
  else {
342
- ui.outro('Pairing incomplete fix the issue above, then re-run `sella init`.');
370
+ ui.outro('Pairing incomplete. Fix the issue above, then re-run `sella init`.');
343
371
  }
344
372
  printer.jsonOut({ installed: install.results, pairing: paired.summary, reinstalled, verify: verifySummary });
345
373
  return install.failed ? 1 : paired.code;
@@ -366,7 +394,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
366
394
  // --json/--yes runs — automation must not fall into an interactive flow.
367
395
  const interactive = io.isTTY && Boolean(process.stdin.isTTY) && !flags.json && !flags.yes;
368
396
  if (interactive && !loadStoredKey(ctx.env)) {
369
- printer.info('No Sella credentials on this machine yet starting onboarding (Ctrl+C to abort, `sella --help` for commands).');
397
+ printer.info('No Sella credentials on this machine yet. Starting onboarding (Ctrl+C to abort, `sella --help` for commands).');
370
398
  return await cmdInit(ctx, flags, printer);
371
399
  }
372
400
  io.stdout(HELP);
@@ -410,7 +438,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
410
438
  if (choice.email)
411
439
  ui.step(`Requesting a verification code for ${choice.email}…`);
412
440
  const paired = await runPair(ctx, flags, emit, { ...choice, ask: wizardAsk(ui, ctx) });
413
- ui.outro(paired.code === 0 ? 'Paired try `sella doctor` next.' : 'Pairing failed see above.');
441
+ ui.outro(paired.code === 0 ? 'Paired. Try `sella doctor` next.' : 'Pairing failed. See above.');
414
442
  printer.jsonOut(paired.summary || {});
415
443
  return paired.code;
416
444
  }
@@ -428,12 +456,12 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
428
456
  const total = result.datasets.length + result.apis.length;
429
457
  printer.info(`Sandbox results for "${query}" (no account, rate-limited):`);
430
458
  for (const d of result.datasets) {
431
- printer.info(` dataset ${d.title || d.id}${d.priceUSDC ? ` $${d.priceUSDC}/call` : ' free'}`);
459
+ printer.info(` dataset ${d.title || d.id}${d.priceUSDC ? `, $${d.priceUSDC}/call` : ', free'}`);
432
460
  }
433
461
  for (const a of result.apis) {
434
462
  printer.info(` api ${a.name || ''}${a.chains?.length ? ` [${a.chains.join('/')}]` : ''}`);
435
463
  }
436
- printer.info(total ? '\nPair to buy any of these: `sella init`.' : 'No matches try a broader query.');
464
+ printer.info(total ? '\nPair to buy any of these: `sella init`.' : 'No matches. Try a broader query.');
437
465
  }
438
466
  return 0;
439
467
  }
@@ -442,7 +470,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
442
470
  printer.jsonOut(info);
443
471
  if (!flags.json) {
444
472
  if (!info.paired) {
445
- printer.error('Not paired yet run `sella pair` first, then `sella fund`.');
473
+ printer.error('Not paired yet. Run `sella pair` first, then `sella fund`.');
446
474
  return 2;
447
475
  }
448
476
  printer.info('Fund your Sella agent wallet with USDC:\n');
@@ -465,14 +493,14 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
465
493
  printer.info('Sella doctor:');
466
494
  for (const check of result.checks) {
467
495
  if (check.ok)
468
- printer.ok(`${check.label} ${check.detail}`);
496
+ printer.ok(`${check.label}: ${check.detail}`);
469
497
  else {
470
- printer.error(`${check.label} ${check.detail}`);
498
+ printer.error(`${check.label}: ${check.detail}`);
471
499
  if (check.fix)
472
500
  printer.info(` ↳ ${check.fix}`);
473
501
  }
474
502
  }
475
- printer.info(result.ok ? '\nAll checks passed. Your agent is ready to buy.' : '\nSome checks failed see the fixes above.');
503
+ printer.info(result.ok ? '\nAll checks passed. Your agent is ready to buy.' : '\nSome checks failed. See the fixes above.');
476
504
  }
477
505
  return result.ok ? 0 : 1;
478
506
  }
@@ -481,7 +509,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
481
509
  printer.jsonOut(status);
482
510
  if (!flags.json) {
483
511
  const key = status.key;
484
- printer.info(key.present ? `API key: ${key.prefix}… (${key.source})` : 'API key: not paired run `sella pair`');
512
+ printer.info(key.present ? `API key: ${key.prefix}… (${key.source})` : 'API key: not paired. Run `sella pair`');
485
513
  const aw = status.agentWallet;
486
514
  if (aw?.username) {
487
515
  printer.info(`AgentWallet: ${aw.username}${aw.fundingStatus ? ` · ${aw.fundingStatus}` : ''}`);
@@ -605,7 +633,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
605
633
  if (sub === 'push') {
606
634
  const stored = loadStoredKey(ctx.env);
607
635
  if (!stored) {
608
- printer.error('Not paired run `sella pair` first, then `sella publish push`.');
636
+ printer.error('Not paired. Run `sella pair` first, then `sella publish push`.');
609
637
  printer.jsonOut({ ok: false, error: 'not_paired' });
610
638
  return 2;
611
639
  }
@@ -620,12 +648,12 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
620
648
  printer.error(` ${k}: ${v}`);
621
649
  }
622
650
  else {
623
- printer.ok(`Published — status: ${result.status}`);
651
+ printer.ok(`Published. Status: ${result.status}`);
624
652
  printer.info(` listing: ${result.listingUrl}`);
625
653
  if (result.status === 'manual_review')
626
654
  printer.info(' Sella is reviewing it; it goes live once approved.');
627
655
  else if (result.status === 'processing')
628
- printer.info(' Still scoring — re-check later with `sella status` or the dashboard.');
656
+ printer.info(' Still scoring. Re-check later with `sella status` or the dashboard.');
629
657
  }
630
658
  }
631
659
  return result.ok ? 0 : 1;
@@ -641,7 +669,7 @@ export async function runCli(argv, io = defaultIo(), env = defaultEnv()) {
641
669
  ctx.io.stderr(`ok Sella MCP bridge → ${ctx.mcpUrl} (key from ${stored.source})`);
642
670
  }
643
671
  else {
644
- ctx.io.stderr('warn No stored key bridging free/sandbox tools only; run `sella pair` to enable paid tools.');
672
+ ctx.io.stderr('warn No stored key. Bridging free/sandbox tools only; run `sella pair` to enable paid tools.');
645
673
  }
646
674
  return await runMcpBridge({ mcpUrl: ctx.mcpUrl, apiKey: stored?.apiKey });
647
675
  }
@@ -40,7 +40,7 @@ export async function forwardMessage(msg, opts) {
40
40
  });
41
41
  const text = await res.text();
42
42
  if (!res.ok) {
43
- const hint = res.status === 401 ? ' run `sella pair` to (re)authenticate this machine' : '';
43
+ const hint = res.status === 401 ? '. Run `sella pair` to (re)authenticate this machine' : '';
44
44
  return { jsonrpc: '2.0', id, error: { code: -32000, message: `Sella endpoint responded ${res.status}${hint}` } };
45
45
  }
46
46
  if (!text)
package/dist/publish.js CHANGED
@@ -33,7 +33,7 @@ export function precheckCsv(text) {
33
33
  warnings.push(`Duplicate header(s): ${[...new Set(dupes)].join(', ')}.`);
34
34
  const dataLines = lines.slice(1);
35
35
  if (dataLines.length === 0)
36
- warnings.push('No data rows only a header was found.');
36
+ warnings.push('No data rows. Only a header was found.');
37
37
  let emptyCells = 0;
38
38
  let ragged = 0;
39
39
  const nonEmptyPerColumn = new Array(columns.length).fill(0);
@@ -138,7 +138,7 @@ export async function pushDataset(opts) {
138
138
  });
139
139
  const json = await res.json().catch(() => ({}));
140
140
  if (res.status === 401)
141
- return { ok: false, error: 'Not authenticated run `sella pair` to (re)authenticate this machine.' };
141
+ return { ok: false, error: 'Not authenticated. Run `sella pair` to (re)authenticate this machine.' };
142
142
  if (res.status === 422)
143
143
  return { ok: false, error: 'The listing was rejected by validation.', fieldErrors: json.fieldErrors };
144
144
  if (!res.ok)
package/dist/ui.js CHANGED
@@ -78,7 +78,7 @@ export class Ui {
78
78
  if (this.quiet)
79
79
  return;
80
80
  if (!this.pretty) {
81
- this.out(`SELLA ${subtitle} (${meta})`);
81
+ this.out(`SELLA · ${subtitle} (${meta})`);
82
82
  return;
83
83
  }
84
84
  this.out('');
@@ -277,7 +277,7 @@ export class Ui {
277
277
  throw new Error(`Cannot prompt for "${label}" in a non-interactive run.`);
278
278
  if (!this.pretty) {
279
279
  this.out(label);
280
- options.forEach((o, idx) => this.out(` ${idx + 1}) ${o.label}${o.hint ? ` ${o.hint}` : ''}`));
280
+ options.forEach((o, idx) => this.out(` ${idx + 1}) ${o.label}${o.hint ? ` (${o.hint})` : ''}`));
281
281
  for (;;) {
282
282
  const answer = (await this.plainQuestion(`Choose 1-${options.length} (${initial + 1}): `)).trim();
283
283
  if (!answer)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sella-cli",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
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",