@nonbot/cli 0.10.16 → 0.10.17

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/CHANGELOG.md CHANGED
@@ -3,6 +3,13 @@
3
3
  What changed for the person running the CLI, newest first. Update with
4
4
  `npm i -g @nonbot/cli@latest`.
5
5
 
6
+ ## 0.10.17 (2026-11-11)
7
+
8
+ - Typing `nonbot` alone now shows who you're signed in as and whether the daemon is running (or "not signed in — start with: nonbot login"). The login row says "switch account" when you're already signed in.
9
+ - `nonbot help` and `nonbot -h` open with the gradient wordmark.
10
+ - Under the wordmark: "non.bot CLI v… · non.bot MCP v…" — both versions side by side (the MCP's is read from this machine, so the screen stays instant).
11
+ - Help and error messages say "To use" instead of "Usage", which read like a page of your account usage.
12
+
6
13
  ## 0.10.16 (2026-11-11)
7
14
 
8
15
  - New: `nonbot mcp` shows the non.bot MCP in one place: its version and what's new since, every Claude app and config file it's set up in (and duplicates), a live start with its tool count by group, how much of each conversation its tool list uses, which tools your apps switch off, the token it uses (last four characters only), whether that token is valid and what it may do, and which tools Claude runs without asking. `--quick` skips the live start.
@@ -73,7 +73,7 @@ export async function runLogsCommand(args = [], deps = {}) {
73
73
  const opts = parseArgs(args);
74
74
  if (opts.error) {
75
75
  errLog(statusRow('✗', 'nonbot logs', opts.error, { stream: process.stderr }) + '\n');
76
- errLog(' Usage: nonbot logs [--limit <n>] [--json] [--follow|-f]\n');
76
+ errLog(' To use: nonbot logs [--limit <n>] [--json] [--follow|-f]\n');
77
77
  return 1;
78
78
  }
79
79
  const entries = await readActivityLog(opts.limit);
@@ -16,7 +16,7 @@ export async function runRunCommand(args = [], deps = {}) {
16
16
  }
17
17
  const id = args.find((a) => !a.startsWith('-'));
18
18
  if (!id) {
19
- errLog('Usage: nonbot run <activation-id> [--headless]\n');
19
+ errLog('To use: nonbot run <activation-id> [--headless]\n');
20
20
  return 1;
21
21
  }
22
22
  const auth = await loader();
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import { runChoirCommand } from './commands/choir.js';
16
16
  import { runRunMcpCommand } from './commands/run-mcp.js';
17
17
  import { runRunPromptHookCommand } from './commands/run-prompt-hook.js';
18
18
  import { setActiveProfile } from './lib/auth.js';
19
+ import { localStatus, statusLine, localMcpLabel, versionsLine } from './lib/local-status.js';
19
20
  import { header, kvRow, ANSI, isTTY, wordmarkArt, WORDMARK_WIDTH } from './lib/output.js';
20
21
  const COMMANDS = [
21
22
  {
@@ -115,14 +116,26 @@ const COMMANDS = [
115
116
  function printVersion() {
116
117
  process.stdout.write(VERSION + '\n');
117
118
  }
118
- function printHelp() {
119
+ function roomForWordmark() {
120
+ const cols = process.stdout.columns ?? 0;
121
+ return cols === 0 || cols >= WORDMARK_WIDTH + 4;
122
+ }
123
+ function printHelp(opts = {}) {
119
124
  const tty = isTTY(process.stdout);
120
125
  const head = (t) => (tty ? ` ${ANSI.bold}${t}${ANSI.reset}` : ` ${t}`);
121
126
  const KEY = 18;
122
127
  const lines = [];
123
- lines.push(header('nonbot', `non.bot CLI · v${VERSION}`));
128
+ if (opts.wordmark !== false && roomForWordmark()) {
129
+ lines.push('');
130
+ lines.push(wordmarkArt({ indent: ' ' }));
131
+ lines.push('');
132
+ lines.push(kvRow('', versionsLine(VERSION, opts.mcpLabel ?? 'not checked'), { keyWidth: 8 }));
133
+ }
134
+ else {
135
+ lines.push(header('nonbot', `non.bot CLI · v${VERSION}`));
136
+ }
124
137
  lines.push('');
125
- lines.push(kvRow('Usage', 'nonbot <command> [args]', { keyWidth: KEY }));
138
+ lines.push(kvRow('To use', 'nonbot <command> [args]', { keyWidth: KEY }));
126
139
  const section = (title, group) => {
127
140
  lines.push('');
128
141
  lines.push(head(title));
@@ -151,19 +164,20 @@ async function printQuickStart() {
151
164
  const io = { stdin: process.stdin, stdout: process.stdout };
152
165
  const interactive = menuIsInteractive(io);
153
166
  const lines = [];
154
- const cols = process.stdout.columns ?? 0;
155
- if (cols === 0 || cols >= WORDMARK_WIDTH + 4) {
167
+ if (roomForWordmark()) {
156
168
  lines.push('');
157
169
  lines.push(wordmarkArt({ indent: ' ' }));
158
170
  lines.push('');
159
- lines.push(kvRow('', `the non.bot CLI · v${VERSION}`, { keyWidth: KEY }));
171
+ lines.push(kvRow('', versionsLine(VERSION, await localMcpLabel()), { keyWidth: KEY }));
160
172
  }
161
173
  else {
162
174
  lines.push(header('non.bot CLI', `v${VERSION}`));
163
175
  }
176
+ const status = await localStatus();
177
+ lines.push(statusLine(status, KEY));
164
178
  lines.push('');
165
- lines.push(kvRow('login', 'sign in', { keyWidth: KEY }));
166
- lines.push(kvRow('daemon', 'listen for runs — Ctrl-C stops it', { keyWidth: KEY }));
179
+ lines.push(kvRow('login', status.email ? 'switch account' : 'sign in', { keyWidth: KEY }));
180
+ lines.push(kvRow('daemon', status.daemon ? 'running · Ctrl-C in its window stops it' : 'listen for runs — Ctrl-C stops it', { keyWidth: KEY }));
167
181
  lines.push(kvRow('doctor', 'check that everything is set up', { keyWidth: KEY }));
168
182
  lines.push(kvRow('logout', 'sign out and stop the daemon', { keyWidth: KEY }));
169
183
  lines.push(kvRow('update', 'install the latest version', { keyWidth: KEY }));
@@ -178,7 +192,7 @@ async function printQuickStart() {
178
192
  return;
179
193
  const choice = await waitForMenuChoice(io, linesBelow(printed, HELP_MARK));
180
194
  if (choice === 'help')
181
- printHelp();
195
+ printHelp({ wordmark: false });
182
196
  }
183
197
  function extractProfileFlag(args) {
184
198
  let profile;
@@ -222,13 +236,13 @@ async function main(argv) {
222
236
  return 0;
223
237
  }
224
238
  if (first === '-h' || first === '--help' || first === 'help') {
225
- printHelp();
239
+ printHelp({ mcpLabel: await localMcpLabel() });
226
240
  return 0;
227
241
  }
228
242
  const cmd = COMMANDS.find((c) => c.name === first);
229
243
  if (!cmd) {
230
244
  process.stderr.write(`nonbot: unknown command "${first}"\n\n`);
231
- printHelp();
245
+ printHelp({ mcpLabel: await localMcpLabel() });
232
246
  return 1;
233
247
  }
234
248
  const result = await cmd.run(args.slice(1));
@@ -0,0 +1,54 @@
1
+ import { loadAuth } from './auth.js';
2
+ import { readPidFile } from './daemon-lifecycle.js';
3
+ import { ANSI, isTTY } from './output.js';
4
+ import { scanMcpConfigs } from './mcp-config.js';
5
+ import { installedMcpVersion } from './mcp-status.js';
6
+ export async function localMcpLabel(scan = () => scanMcpConfigs().nonbot, versionOf = (e) => installedMcpVersion(e)) {
7
+ let entries = [];
8
+ try {
9
+ entries = scan();
10
+ }
11
+ catch {
12
+ entries = [];
13
+ }
14
+ const primary = entries.find((e) => e.scope && e.scope !== 'desktop') ?? entries[0];
15
+ if (!primary)
16
+ return 'not set up';
17
+ if (primary.kind === 'remote')
18
+ return 'remote';
19
+ const v = await versionOf(primary).catch(() => null);
20
+ return v ? `v${v}` : 'set up';
21
+ }
22
+ export function versionsLine(cliVersion, mcpLabel) {
23
+ return `non.bot CLI v${cliVersion} · non.bot MCP ${mcpLabel}`;
24
+ }
25
+ export async function localStatus(deps = {}) {
26
+ let email = null;
27
+ try {
28
+ email = (await (deps.loadAuth ?? loadAuth)())?.email ?? null;
29
+ }
30
+ catch {
31
+ email = null;
32
+ }
33
+ const pid = (deps.readPid ?? (() => readPidFile()))();
34
+ const alive = deps.isAlive ??
35
+ ((p) => {
36
+ try {
37
+ process.kill(p, 0);
38
+ return true;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ });
44
+ return { email, daemon: pid !== null && alive(pid) };
45
+ }
46
+ export function statusLine(s, keyWidth, stream = process.stdout) {
47
+ const tty = isTTY(stream);
48
+ const pad = ' '.repeat(3 + keyWidth + 1);
49
+ const mark = (ok) => (tty ? (ok ? `${ANSI.green}✓${ANSI.reset}` : `${ANSI.dim}○${ANSI.reset}`) : ok ? '✓' : '○');
50
+ const dim = (t) => (tty ? `${ANSI.dim}${t}${ANSI.reset}` : t);
51
+ if (!s.email)
52
+ return `${pad}${mark(false)} ${dim('not signed in — start with: nonbot login')}`;
53
+ return `${pad}${mark(true)} ${dim(`signed in as ${s.email} · daemon ${s.daemon ? 'running' : 'not running'}`)}`;
54
+ }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.10.16';
1
+ export const VERSION = '0.10.17';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nonbot/cli",
3
- "version": "0.10.16",
3
+ "version": "0.10.17",
4
4
  "type": "module",
5
5
  "description": "The local host for non.bot ▶ Run — opens a terminal on your machine and starts the work in your linked repo.",
6
6
  "license": "SEE LICENSE IN LICENSE",