From c3de13edc5613bf609d48bea56f1d7b438c0d642 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 8 Sep 2026 21:46:56 +0000 Subject: [PATCH] telnyx, because a number bought by clicking is not reproducible Phone numbers, messages and calls from the terminal. The alternative is the Mission Control portal, and what you do there leaves no trace a script can repeat: `telnyx number search --type toll_free`, `telnyx number order`, `telnyx call dial` are the same work as commands. Which package matters here. Telnyx publishes two CLIs and both put `telnyx` on PATH, so this is a choice about which rather than a chance to have both. `@telnyx/cli` is generated from their OpenAPI spec over the whole API surface, and its own repository documents `go install` as the way to get it. `@telnyx/api-cli` is the curated Node one, published to npm as a first-class artifact, and its commands read like a person's. A front door like `myna` and `eas`: `telnyx auth setup` writes the key to ~/.config/telnyx, TELNYX_API_KEY covers a box where an interactive prompt is not on offer, and nothing about the account lives here. In the default set rather than a group. It is one small npm package with no runtime precondition, which is the line `mobile` exists on the other side of. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011tD9KQt1jzufSt6DZGUGXP --- README.md | 19 +++++++++++++++++-- src/companions.ts | 22 ++++++++++++++++++++++ test/companions.test.ts | 9 ++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0d41ecd..1af9e7d 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ implement, because they are distributed in their own right: | `myna` | [mynaposter.com](https://mynaposter.com) — post, schedule and read across 25 social networks from a TUI | | `devdb` | [terrablue/devdb](https://github.com/terrablue/devdb) — spin up a throwaway local database for development or testing | | `kali` | [`@profullstack/kali`](https://github.com/profullstack/kali) — install a Kali-style web pentesting toolbelt on Debian/Ubuntu | +| `telnyx` | [`@telnyx/api-cli`](https://github.com/team-telnyx/telnyx-api-cli) — buy and wire phone numbers, send messages and drive calls | And one group that is installed only when you ask for it, with `cli-tools companions --install mobile`: @@ -118,8 +119,8 @@ under any agentic CLI, from a Dockerfile, on a box that has never heard of this repository. Vendoring them to make one list tidier would cost them all of that. So `cli-tools` is their front door, not their implementation. -Six come from npm. `bw` was the first companion that is nobody's but its -vendor's — `adb`, `expo` and `eas` are the others — and it earns the place on +Seven come from npm. `bw` was the first companion that is nobody's but its +vendor's — `adb`, `expo`, `eas` and `telnyx` are the others — and it earns the place on the same terms as the rest: published, self-installing, useful on a box with no checkout. It covers the secrets `cli-tools` deliberately does not — the `vault` helpers read a logicsrc team vault of shared API keys, which is a different thing from one person's @@ -157,6 +158,20 @@ tool, so there is no need to run Kali itself. The tools are dual-use, which is the point of keeping it a front door: it equips a box you are authorized to test, and nothing about a target lives in this repository. +`telnyx` is here because the alternative is a web portal, and a phone number +bought by clicking is a number nobody can reproduce. `telnyx number search +--type toll_free`, `telnyx number order`, `telnyx call dial` — standing a +number up, and wiring it to something, as commands you can put in a script. +Note which package it is: Telnyx publishes two CLIs and both put `telnyx` on +PATH, so this is a choice about which rather than a chance to have both. +`@telnyx/cli` is generated from their OpenAPI spec over the whole API surface +and its own repository documents `go install` as the way to get it; +`@telnyx/api-cli` is the curated Node one, published to npm as a first-class +artifact, and its commands read like a person's. Like `myna` and `eas` it stays +a front door: `telnyx auth setup` writes the key to `~/.config/telnyx`, +`TELNYX_API_KEY` covers a box where an interactive prompt is not on offer, and +nothing about the account lives here. + `adb` is the odd one, and the reason there is a fourth kind of install. It is not on npm — what is published under those names is either a Node reimplementation of the wire protocol or somebody's mirror of Google's zip, and diff --git a/src/companions.ts b/src/companions.ts index ae01525..c2f4d5c 100644 --- a/src/companions.ts +++ b/src/companions.ts @@ -156,6 +156,28 @@ export const COMPANIONS: readonly Companion[] = [ summary: 'Install a Kali-style web pentesting toolbelt on Debian/Ubuntu', home: 'https://github.com/profullstack/kali', }, + { + name: 'telnyx', + // Phone numbers, messages and calls from the terminal, which is the point: + // the alternative is the Mission Control portal, and a number bought by + // clicking is a number nobody can reproduce. `telnyx number search + // --type toll_free`, `telnyx number order`, `telnyx call dial` -- the + // things you actually do to stand a phone number up. + // + // `@telnyx/api-cli`, not `@telnyx/cli`, and they are both Telnyx's. The + // latter is Stainless-generated over the whole API surface and its own + // repository documents `go install` as the way to get it; this one is the + // curated Node CLI, published to npm as a first-class artifact, and it is + // the one whose commands read like a person's. Both put `telnyx` on PATH, + // so this is a choice about which, not a chance to have both. + // + // A front door like `myna` and `eas`: `telnyx auth setup` writes the key + // to ~/.config/telnyx, and TELNYX_API_KEY works for a box where an + // interactive prompt is not on offer. Nothing about the account lives here. + install: { kind: 'npm', package: '@telnyx/api-cli' }, + summary: 'Buy and wire phone numbers, send messages and drive calls on Telnyx', + home: 'https://github.com/team-telnyx/telnyx-api-cli', + }, { name: 'adb', // The Android Debug Bridge, and `fastboot` out of the same archive: one diff --git a/test/companions.test.ts b/test/companions.test.ts index cdc269f..773bd1f 100644 --- a/test/companions.test.ts +++ b/test/companions.test.ts @@ -32,6 +32,7 @@ describe('the companion list', () => { 'myna', 'devdb', 'kali', + 'telnyx', 'adb', 'expo', 'eas', @@ -167,6 +168,7 @@ describe('statuses', () => { ['myna', 'missing'], ['devdb', 'missing'], ['kali', 'missing'], + ['telnyx', 'missing'], ['adb', 'missing'], ['expo', 'missing'], ['eas', 'missing'], @@ -182,7 +184,7 @@ describe('ensure', () => { // Reinstalling over it is the surprise `link` refuses for symlinks. const calls: string[] = []; const results = ensure({ - onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali'), + onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx'), run: ({ display }) => { calls.push(display); return { status: 0 }; @@ -194,7 +196,7 @@ describe('ensure', () => { it('installs only what is missing', () => { const calls: string[] = []; - const installed = new Set(['timer', 'bw', 'diskpush', 'myna', 'devdb', 'kali']); + const installed = new Set(['timer', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx']); ensure({ onPath: (name) => (installed.has(name) ? `/usr/local/bin/${name}` : null), run: ({ display }) => { @@ -209,7 +211,7 @@ describe('ensure', () => { it('reinstalls everything at @latest when asked', () => { const calls: string[] = []; ensure({ - onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali'), + onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx'), run: ({ display }) => { calls.push(display); return { status: 0 }; @@ -226,6 +228,7 @@ describe('ensure', () => { // Same reason, one step further: `go install` has no bare form to add to. 'go install github.com/terrablue/devdb@latest', 'npm install -g @profullstack/kali@latest', + 'npm install -g @telnyx/api-cli@latest', ]); });