Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ implement, because they are distributed in their own right:
| `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 |
| `qc` | [`@profullstack/qryptchat`](https://qrypt.chat) — qrypt.chat in the terminal: end-to-end encrypted (ML-KEM-1024) chat client, CLI and MCP server |

And one group that is installed only when you ask for it, with
`cli-tools companions --install mobile`:
Expand All @@ -203,7 +204,7 @@ 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.

Seven come from npm. `bw` was the first companion that is nobody's but its
Eight 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
Expand Down
12 changes: 12 additions & 0 deletions src/companions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ export const COMPANIONS: readonly Companion[] = [
summary: 'Buy and wire phone numbers, send messages and drive calls on Telnyx',
home: 'https://github.com/team-telnyx/telnyx-api-cli',
},
{
name: 'qc',
// qrypt.chat in the terminal: bare `qc` is a full-screen hqtui chat client,
// `qc chats|read|send|listen` are for scripts and `qc mcp` is an MCP server.
// Messages are encrypted (ML-KEM-1024) on the machine running qc, so the
// keys live in ~/.config/qc after `qc login`, a browser handoff -- a front
// door like `myna`: nothing about the account lives here. The package is
// `@profullstack/qryptchat`; the binary is `qc`.
install: { kind: 'npm', package: '@profullstack/qryptchat' },
summary: 'qrypt.chat in the terminal: end-to-end encrypted chat client, CLI and MCP server',
home: 'https://qrypt.chat',
},
{
name: 'adb',
// The Android Debug Bridge, and `fastboot` out of the same archive: one
Expand Down
9 changes: 6 additions & 3 deletions test/companions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('the companion list', () => {
'devdb',
'kali',
'telnyx',
'qc',
'adb',
'expo',
'eas',
Expand Down Expand Up @@ -169,6 +170,7 @@ describe('statuses', () => {
['devdb', 'missing'],
['kali', 'missing'],
['telnyx', 'missing'],
['qc', 'missing'],
['adb', 'missing'],
['expo', 'missing'],
['eas', 'missing'],
Expand All @@ -184,7 +186,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', 'telnyx'),
onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx', 'qc'),
run: ({ display }) => {
calls.push(display);
return { status: 0 };
Expand All @@ -196,7 +198,7 @@ describe('ensure', () => {

it('installs only what is missing', () => {
const calls: string[] = [];
const installed = new Set<string>(['timer', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx']);
const installed = new Set<string>(['timer', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx', 'qc']);
ensure({
onPath: (name) => (installed.has(name) ? `/usr/local/bin/${name}` : null),
run: ({ display }) => {
Expand All @@ -211,7 +213,7 @@ describe('ensure', () => {
it('reinstalls everything at @latest when asked', () => {
const calls: string[] = [];
ensure({
onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx'),
onPath: present('timer', 'billing', 'bw', 'diskpush', 'myna', 'devdb', 'kali', 'telnyx', 'qc'),
run: ({ display }) => {
calls.push(display);
return { status: 0 };
Expand All @@ -229,6 +231,7 @@ describe('ensure', () => {
'go install github.com/terrablue/devdb@latest',
'npm install -g @profullstack/kali@latest',
'npm install -g @telnyx/api-cli@latest',
'npm install -g @profullstack/qryptchat@latest',
]);
});

Expand Down
Loading