toolaby 1.7.1 → 1.7.2

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.
Files changed (3) hide show
  1. package/README.md +5 -3
  2. package/bin.mjs +31 -29
  3. package/package.json +2 -3
package/README.md CHANGED
@@ -3,11 +3,13 @@
3
3
  The Toolaby command line. It puts the Wall — sign-in, a Free plan, paid plans, licences and subscriptions — into a Chrome extension you already have, or makes a new one for you.
4
4
 
5
5
  ```sh
6
- npm i -g toolaby # once (or run every command through `npx -y toolaby@latest …`); on Windows, type toolaby-cli
7
- toolaby wire <tool-id> # in your extension's folder, on Test; signs you in first if it must
8
- toolaby wire <tool-id> --live # the same, on Live: the store build
6
+ npm i -g toolaby # once; or run every command through `npx -y toolaby@latest …`
7
+ toolaby-cli wire <tool-id> # in your extension's folder, on Test; signs you in first if it must
8
+ toolaby-cli wire <tool-id> --live # the same, on Live: the store build
9
9
  ```
10
10
 
11
+ The command is `toolaby-cli`: on Windows, the Command Prompt runs a `toolaby.js` in the current folder before a command named `toolaby`, and every wired folder has one. Below, `toolaby <command>` names each command.
12
+
11
13
  In a repository you did not write, use the installed command: `npx` can run a `toolaby` the project carries, or fetch one from a registry the project's `.npmrc` names.
12
14
 
13
15
  Every command acts on the test Wall (`test.toolaby.app`) unless told `--live` (`toolaby.app`), as Stripe's command line does. `toolaby tools` lists your ids on either side.
package/bin.mjs CHANGED
@@ -44,7 +44,7 @@ import { runMcp } from './lib/mcp.js';
44
44
  import { runCheck } from './lib/check.js';
45
45
  import { inside, signInPage, devicePolling, opener, privateKind, privateContent, privateCopies, googleKey, projectRoot, gitDirectory, gitObject, gitObjects, gitFile, notAnImage, unpacked, COMPRESSED, publicLinks, privateLinks, oneLine, fetchBounded, fetchHere, readBounded, readText, SCAFFOLD_FILES } from './lib/safe.js';
46
46
 
47
- const VERSION = '1.7.1';
47
+ const VERSION = '1.7.2';
48
48
  const CLIENT_ID = 'toolaby-cli';
49
49
  const argv = process.argv.slice(2);
50
50
  // `--version` and `--help` are commands of their own; every other command is the first bare word.
@@ -167,11 +167,11 @@ async function login() {
167
167
  }
168
168
  const why = poll.json.error;
169
169
  if (why === 'slow_down') every += 5000;
170
- else if (why === 'expired_token') fail('The code expired before it was approved. Run `toolaby login` again.');
170
+ else if (why === 'expired_token') fail('The code expired before it was approved. Run `npx -y toolaby@latest login` again.');
171
171
  else if (why === 'access_denied') fail('The sign-in was denied in the browser. Nothing was signed in.');
172
172
  else if (why && why !== 'authorization_pending') fail(`The Wall answered "${oneLine(why)}"${poll.json.error_description ? `: ${oneLine(poll.json.error_description)}` : ''}.`);
173
173
  }
174
- fail('The code expired before it was approved. Run `toolaby login` again.');
174
+ fail('The code expired before it was approved. Run `npx -y toolaby@latest login` again.');
175
175
  }
176
176
 
177
177
  /** A token to act with: the stored one, else a sign-in right here — `wire` in a fresh terminal is one command, not two. */
@@ -183,9 +183,9 @@ async function tokenOrLogin() {
183
183
 
184
184
  async function whoami() {
185
185
  const token = storedToken();
186
- if (!token) fail(`Not signed in to ${side} (${wall}). Run \`toolaby login${live ? ' --live' : ''}\`.${envElsewhere()}`);
186
+ if (!token) fail(`Not signed in to ${side} (${wall}). Run \`npx -y toolaby@latest login${live ? ' --live' : ''}\`.${envElsewhere()}`);
187
187
  const me = await api('/api/cli/me', { token });
188
- if (me.status === 401) fail(`The session for ${wall} is no longer valid. Run \`toolaby login\`.`);
188
+ if (me.status === 401) fail(`The session for ${wall} is no longer valid. Run \`npx -y toolaby@latest login\`.`);
189
189
  if (!me.ok) fail(`The Wall answered HTTP ${me.status}.`);
190
190
  out(`\n ${oneLine(me.json.email)} · ${side} · ${wall}\n`);
191
191
  for (const w of me.json.workspaces) out(` ${oneLine(w.name)} (${oneLine(w.slug)}, ${oneLine(w.role)}) ${oneLine(w.site)}`);
@@ -207,7 +207,7 @@ async function logout() {
207
207
  async function tools() {
208
208
  const token = await tokenOrLogin();
209
209
  const res = await api('/api/cli/tools', { token });
210
- if (res.status === 401) fail(`The session for ${side} is no longer valid. Run \`toolaby login${live ? ' --live' : ''}\`.`);
210
+ if (res.status === 401) fail(`The session for ${side} is no longer valid. Run \`npx -y toolaby@latest login${live ? ' --live' : ''}\`.`);
211
211
  if (!res.ok) fail(`The Wall answered HTTP ${res.status}.`);
212
212
  if (!res.json.tools.length) { out(`\n No tools on ${side} yet. Make one in the dashboard, then \`toolaby wire <tool-id>${live ? ' --live' : ''}\` in your extension's folder.\n`); return; }
213
213
  out(`\n ${side}\n`);
@@ -276,7 +276,7 @@ async function filesFor(slug, scaffold, manifestKey = null, surfaces = null) {
276
276
 
277
277
  async function wire() {
278
278
  const slug = positional[0];
279
- if (!isId(slug)) fail(command === 'upgrade' ? 'usage: toolaby upgrade <tool-id> [--into <folder>] — `toolaby tools` lists your ids' : 'usage: toolaby wire <tool-id> [--into <folder>] [--force] [--adopt-key] — `toolaby tools` lists your ids');
279
+ if (!isId(slug)) fail(command === 'upgrade' ? 'usage: npx -y toolaby@latest upgrade <tool-id> [--into <folder>] — `npx -y toolaby@latest tools` lists your ids' : 'usage: npx -y toolaby@latest wire <tool-id> [--into <folder>] [--force] [--adopt-key] — `npx -y toolaby@latest tools` lists your ids');
280
280
  const dir = resolve(opt('--into') ?? '.');
281
281
  if (!existsSync(dir)) fail(`${dir} does not exist`);
282
282
  const tree = listTree(dir, 3);
@@ -371,7 +371,7 @@ async function wire() {
371
371
 
372
372
  async function create() {
373
373
  const slug = positional[0];
374
- if (!isId(slug)) fail('usage: toolaby create <tool-id> [--dir <folder>] — `toolaby tools` lists your ids');
374
+ if (!isId(slug)) fail('usage: npx -y toolaby@latest create <tool-id> [--dir <folder>] — `npx -y toolaby@latest tools` lists your ids');
375
375
  const dir = resolve(opt('--dir') ?? slug);
376
376
  if (there(dir)) fail(`${dir} already exists`);
377
377
  // Which surfaces this extension is made with, asked first: the files for coding agents name only what is written.
@@ -442,7 +442,7 @@ function devSecret() {
442
442
  }
443
443
  async function catalogue() {
444
444
  const res = await api('/api/cli/webhooks/events', { token: await tokenOrLogin() });
445
- if (res.status === 401) fail(`The session for ${side} is no longer valid. Run \`toolaby login${live ? ' --live' : ''}\`.`);
445
+ if (res.status === 401) fail(`The session for ${side} is no longer valid. Run \`npx -y toolaby@latest login${live ? ' --live' : ''}\`.`);
446
446
  if (!res.ok) fail(`The Wall answered HTTP ${res.status}.`);
447
447
  return res.json.events;
448
448
  }
@@ -462,7 +462,7 @@ async function webhooks() {
462
462
  }
463
463
  if (sub === 'trigger') {
464
464
  const type = positional[1];
465
- if (!type) fail('usage: toolaby webhooks trigger <event> [--to <url>] [--secret <whsec_…>] — `toolaby webhooks events` lists them');
465
+ if (!type) fail('usage: npx -y toolaby@latest webhooks trigger <event> [--to <url>] [--secret <whsec_…>] — `npx -y toolaby@latest webhooks events` lists them');
466
466
  const to = opt('--to');
467
467
  if (!to) {
468
468
  const res = await api('/api/cli/webhooks/trigger', { method: 'POST', body: { type, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
@@ -472,7 +472,7 @@ async function webhooks() {
472
472
  }
473
473
  const events = await catalogue();
474
474
  const event = events.find((e) => e.type === type);
475
- if (!event) fail(`No event "${type}". \`toolaby webhooks events\` lists them.`);
475
+ if (!event) fail(`No event "${type}". \`npx -y toolaby@latest webhooks events\` lists them.`);
476
476
  const secret = opt('--secret') ?? devSecret();
477
477
  if (!/^whsec_[A-Za-z0-9+/=]+$/.test(secret)) fail('--secret must be a Standard Webhooks secret: whsec_ followed by base64.');
478
478
  const id = `msg_${randomBytes(12).toString('base64url')}`;
@@ -494,14 +494,14 @@ async function webhooks() {
494
494
  const res = await api(`/api/cli/webhooks/endpoints${ws ? `?workspace=${encodeURIComponent(ws)}` : ''}`, { token: await tokenOrLogin() });
495
495
  if (!res.ok) fail(oneLine(res.json.message ?? `The Wall answered HTTP ${res.status}.`));
496
496
  out(`\n ${oneLine(res.json.workspace)} · ${side}\n`);
497
- if (res.json.endpoints.length === 0) out(' None yet. `toolaby webhooks add <url>` registers one.');
497
+ if (res.json.endpoints.length === 0) out(' None yet. `npx -y toolaby@latest webhooks add <url>` registers one.');
498
498
  for (const e of res.json.endpoints) out(` ${oneLine(e.id)} ${e.disabled ? 'paused ' : 'on '} ${oneLine(e.url)}${e.description ? ` — ${oneLine(e.description)}` : ''}${e.events.length ? ` (${oneLine(e.events.join(', '))})` : ''}`);
499
499
  out();
500
500
  return;
501
501
  }
502
502
  if (sub === 'add') {
503
503
  const url = positional[1];
504
- if (!url) fail('usage: toolaby webhooks add <url> [--description <text>] [--events a.b,c.d] [--workspace <slug>]');
504
+ if (!url) fail('usage: npx -y toolaby@latest webhooks add <url> [--description <text>] [--events a.b,c.d] [--workspace <slug>]');
505
505
  const events = (opt('--events') ?? '').split(',').map((e) => e.trim()).filter(Boolean);
506
506
  const res = await api('/api/cli/webhooks/endpoints', { method: 'POST', body: { url, description: opt('--description') ?? '', events, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
507
507
  if (!res.ok) fail(oneLine(res.json.message ?? `The Wall answered HTTP ${res.status}.`));
@@ -510,13 +510,13 @@ async function webhooks() {
510
510
  }
511
511
  if (sub === 'remove') {
512
512
  const id = positional[1];
513
- if (!id) fail('usage: toolaby webhooks remove <ep_…> [--workspace <slug>] — `toolaby webhooks endpoints` lists them');
513
+ if (!id) fail('usage: npx -y toolaby@latest webhooks remove <ep_…> [--workspace <slug>] — `npx -y toolaby@latest webhooks endpoints` lists them');
514
514
  const res = await api('/api/cli/webhooks/endpoints', { method: 'DELETE', body: { id, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
515
515
  if (!res.ok) fail(oneLine(res.json.message ?? `The Wall answered HTTP ${res.status}.`));
516
516
  out(`\n Removed ${oneLine(res.json.removed)} · ${oneLine(res.json.workspace)} · ${side}. Deliveries to it stop at once.\n`);
517
517
  return;
518
518
  }
519
- fail('usage: toolaby webhooks events | trigger <event> [--to <url>] | endpoints | add <url> | remove <id>');
519
+ fail('usage: npx -y toolaby@latest webhooks events | trigger <event> [--to <url>] | endpoints | add <url> | remove <id>');
520
520
  }
521
521
 
522
522
  // ── pack: the zip the Chrome Web Store takes ──────────────────────────────────────────────────────────────────────────
@@ -784,35 +784,37 @@ function help() {
784
784
  out(`
785
785
  toolaby — the Toolaby command line (${VERSION})
786
786
 
787
- toolaby wire <tool-id> wire the extension in this folder to your tool, on Test
788
- toolaby wire <tool-id> --live the same, on Live: the store build
787
+ npx -y toolaby@latest <command>, or installed (npm i -g toolaby): toolaby-cli <command>
788
+
789
+ wire <tool-id> wire the extension in this folder to your tool, on Test
790
+ wire <tool-id> --live the same, on Live: the store build
789
791
  --into <folder> another folder --force replace the platform's files
790
792
  --own-popup keep your popup in front (the Wall's opens from toolaby.showPaywall())
791
- toolaby upgrade <tool-id> the platform's files replaced with the current ones — the popup, the client — yours untouched
792
- toolaby create <tool-id> a new, minimal extension for your tool, in <tool-id>/ --dir <folder>
793
+ upgrade <tool-id> the platform's files replaced with the current ones — the popup, the client — yours untouched
794
+ create <tool-id> a new, minimal extension for your tool, in <tool-id>/ --dir <folder>
793
795
  --surfaces both|popup|side-panel|none what it opens (default: both)
794
- toolaby tools your tools, with their ids
795
- toolaby pack [folder] the zip for the Chrome Web Store: the built extension, its manifest's "key" left out;
796
+ tools your tools, with their ids
797
+ pack [folder] the zip for the Chrome Web Store: the built extension, its manifest's "key" left out;
796
798
  refuses a Test key or localhost inside --out <file.zip>
797
799
  leaves out keys, certificates, .env and credential files, source maps, secrets,
798
800
  git's files, a build's copy of a private file (compressed, UTF-16 or base64),
799
801
  an image that is none; refuses a build if one is a file the manifest names
800
802
  --allow-private packs them
801
- toolaby check [folder] whether the extension here is wired right: files, key, manifest, client, features;
803
+ check [folder] whether the extension here is wired right: files, key, manifest, client, features;
802
804
  --browser loads it in Chromium (needs Playwright in the project)
803
- toolaby mcp the Wall for coding agents, an MCP server on stdio:
805
+ mcp the Wall for coding agents, an MCP server on stdio:
804
806
  claude mcp add toolaby -- npx -y toolaby@latest mcp
805
- toolaby webhooks events the six events, with an example of each
806
- toolaby webhooks trigger <event> an example delivery to your endpoints; --to <url> sends it to a local server instead
807
- toolaby webhooks endpoints your endpoints; add <url> registers one (secret shown once), remove <id> removes one
808
- toolaby login · whoami · logout the session, per side; a command that needs one signs you in itself
807
+ webhooks events the six events, with an example of each
808
+ webhooks trigger <event> an example delivery to your endpoints; --to <url> sends it to a local server instead
809
+ webhooks endpoints your endpoints; add <url> registers one (secret shown once), remove <id> removes one
810
+ login · whoami · logout the session, per side; a command that needs one signs you in itself
809
811
 
810
812
  Every command acts on Test (test.toolaby.app) unless told --live (toolaby.app).
811
813
  --wall <url> or TOOLABY_WALL names any other Wall; TOOLABY_TOKEN a session, for CI —
812
814
  sent to Live alone, or to the one Wall TOOLABY_TOKEN_WALL names (https://test.toolaby.app for Test).
813
815
 
814
- Not installed: npx -y toolaby@latest <command>. In a repository you did not write, install it (npm i -g toolaby)
815
- and type toolaby: npx can run a toolaby the project carries, or fetch one from a registry its .npmrc names.
816
+ In a repository you did not write, install it (npm i -g toolaby) and type toolaby-cli: npx can run a toolaby
817
+ the project carries, or fetch one from a registry its .npmrc names.
816
818
  `);
817
819
  }
818
820
 
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "toolaby",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "description": "The Toolaby command line: sign in once, then wire any Chrome extension to your tool on the Wall — sign-in, the Free plan, licences and subscriptions — or start a new one; check it, and give coding agents the Wall as an MCP server.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "toolaby-cli": "bin.mjs",
8
- "toolaby": "bin.mjs"
7
+ "toolaby-cli": "bin.mjs"
9
8
  },
10
9
  "files": [
11
10
  "bin.mjs",