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
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2026-05-01

First stable release. This is a large release that overhauls authentication, command argument conventions, output formatting, and adds several new command groups. Key user-facing changes are summarised below; review the migration notes before upgrading.
Copy link
Copy Markdown
Contributor

@sacOO7 sacOO7 May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a question, we didn't include any points from proposed changelog entry at https://ably-real-time.slack.com/archives/C09M25LCZLP/p1777559095294669?thread_ts=1777545682.860959&cid=C09M25LCZLP , is this intentional?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that's for changelog.ably.com


### Added

- **OAuth Device Authorization login** — `ably login` now uses the OAuth 2.0 Device Authorization Grant for browser-based sign-in. Works in SSH sessions, containers, and headless CI without a localhost callback. Multi-account is built in: sign in once per account, switch contexts with `ably accounts switch`, and tokens refresh transparently in the background.
- **`--force` flag for destructive operations** — unified across delete/revoke/wipe commands. Interactive use prompts for confirmation; non-interactive use (scripts, agents) refuses to run unless `--force` is passed explicitly. Prevents accidental destruction by automation that has general CLI access.
- **Error hints** — fatal errors now include a `hint` field naming a specific next-step command (e.g. "run `ably login`" for auth errors). Surfaced in both human-readable output and the JSON error envelope, so agents can self-heal in fewer turns.
- **Chat message mutations** — `ably rooms messages update`, `delete`, and reactions/annotations support
- **Push notification publish** — `ably push publish` for sending push notifications via channels
- **Annotations** — new `ably channels annotations` command group with publish/subscribe/get/count/delete
- **Spaces commands** — expanded coverage including locks acquire/release, locations set, cursors set, members enter, and `get`/`get-all` queries
- **Integrations** — first-class command group for managing integration rules (`ably integrations list/get/create/update/delete`)
- **Channel rules for mutable messages** — flags for configuring update/delete/annotation policies on channel rules
- **Stats top-level command** — `ably stats` (moved out of `apps`)

### Changed

- **BREAKING: Auth flags removed** — `--api-key`, `--token`, and `--access-token` no longer accepted on commands. Use `ably login` or env vars `ABLY_API_KEY` / `ABLY_TOKEN` / `ABLY_ACCESS_TOKEN`.
- **BREAKING: Primary entity identifiers are now positional arguments** — flags like `--name`, `--channel`, `--location`, and `--key` that named the entity being acted on have been replaced with positional args (POSIX/docopt convention). Affects `apps`, `keys`, `queues`, `rules`, `push`, `channels`, `rooms`, `spaces locations`, and others.
- **BREAKING: Standardized argument naming** — argument names in errors and help output are snake_case; commands use camelCase identifiers consistently (`appId`, `keyName`, `channelName`).
- **BREAKING: Flexible name-or-ID lookup** — `apps`, `keys`, `queues`, and `rules` commands now resolve either name or ID. Behaviour for ambiguous lookups may differ from previous versions.
- **BREAKING: `auth revoke-token`** no longer accepts a `TOKEN` positional; pass `--client-id` or `--revocation-key`. Adds confirmation prompt and `--force`.
- **Unified JSON output envelope** — every command now emits `{type, command, success, ...}` with domain data nested under singular/plural domain keys. Streaming commands emit NDJSON with `status: "listening"` / `"holding"` signals and a final `status: "completed"` event.
- **Unified output helpers** — `logProgress`, `logSuccessMessage`, `logListening`, `logHolding`, `logWarning` replace ad-hoc `chalk` usage; non-JSON output uses labeled multi-line blocks (no ASCII tables).
- **Unified time-range flags** — `--start` / `--end` accept ISO 8601, Unix ms, or relative (`"1h"`, `"30m"`) across all history and stats commands.
- **Unified pagination** — cursor-based pagination with `formatPaginationLog` warnings when multiple pages are fetched, and `next` hints in JSON output.
- **Help theme** — colour-coded help via oclif theme (commands cyan, flags whiteBright, headers bold, defaults yellow, required red).
- **Error handling** — fatal errors now flow through a single `this.fail()` funnel that preserves Ably error codes/HTTP status and emits structured JSON error envelopes.

### Fixed

- Many fixes around JSON output consistency, timestamp formatting, error envelopes, billable message warnings, channel-rule handling, push message shape, batch publish, room messages subscribe across multiple rooms, presence flows, and exit codes.
- Web CLI: file-read security hardening, auto-connect detection with signed config, domain-scoped credential clearing.
- Spaces `enter` no longer triggers on read-only commands (subscribe/get are now passive observers).
- Duplicated "Press Ctrl+C to exit" suffixes removed from holding messages.

### Removed

- **BREAKING: Auth CLI flags** (see Changed section above)

### Migration Notes

If you have scripts targeting v0.x, the most likely breakages are:

1. **Replace `--api-key`/`--token`/`--access-token`** flags with environment variables (`ABLY_API_KEY`, `ABLY_TOKEN`, `ABLY_ACCESS_TOKEN`) or run `ably login` once on the host.
2. **Move primary entity identifiers from flags to positional args**, e.g.:
- `ably apps update --name my-app …` → `ably apps update my-app …`
- `ably channels publish --channel foo --message bar` → `ably channels publish foo bar`
- `ably spaces locations set --location ./path …` → `ably spaces locations set ./path …`
3. **Update JSON consumers** — top-level shape now includes `type`, `command`, and `success` fields, with payload nested under a domain key (`message`, `cursor`, `lock`, `rules`, etc.).
4. **Rename argument references** in any error-handling code that matched on previous arg names.
5. **`ably auth revoke-token <TOKEN>`** → `ably auth revoke-token --client-id <ID>` or `--revocation-key <KEY>` (the positional `TOKEN` arg is no longer accepted).

## [0.17.0] - 2026-03-08

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ably/cli",
"version": "0.17.0",
"version": "1.0.0",
"description": "Ably CLI for Pub/Sub, Chat and Spaces",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-web-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ably/react-web-cli",
"version": "0.17.0",
"version": "1.0.0",
"description": "React component for embedding the Ably CLI in a web terminal",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
4 changes: 1 addition & 3 deletions src/commands/interactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { fileURLToPath } from "node:url";
import chalk from "chalk";
import { HistoryManager } from "../services/history-manager.js";
import { displayLogo } from "../utils/logo.js";
import { formatReleaseStatus } from "../utils/version.js";
import {
WEB_CLI_RESTRICTED_COMMANDS,
WEB_CLI_ANONYMOUS_RESTRICTED_COMMANDS,
Expand Down Expand Up @@ -137,8 +136,7 @@ export default class Interactive extends Command {
// Display logo
displayLogo(console.log);

// Show release status
console.log(` ${formatReleaseStatus(this.config.version, true)}\n`);
console.log(` ${chalk.dim(`Version ${this.config.version}`)}\n`);

// Show appropriate tagline based on mode
let tagline = "ably.com ";
Expand Down
8 changes: 1 addition & 7 deletions src/commands/version.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { AblyBaseCommand } from "../base-command.js";
import { coreGlobalFlags } from "../flags.js";
import {
getVersionInfo,
formatVersionString,
formatReleaseStatus,
} from "../utils/version.js";
import { getVersionInfo, formatVersionString } from "../utils/version.js";

export default class Version extends AblyBaseCommand {
static description = "Display CLI version information";
Expand All @@ -31,9 +27,7 @@ export default class Version extends AblyBaseCommand {
if (this.shouldOutputJson(flags)) {
this.logJsonResult({ version: versionInfo }, flags);
} else {
// Use shared string formatting and display release status
this.log(formatVersionString(this.config));
this.log(formatReleaseStatus(this.config.version, true));
}
}
}
5 changes: 2 additions & 3 deletions src/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
createConfigManager,
} from "./services/config-manager.js";
import { displayLogo } from "./utils/logo.js";
import { formatReleaseStatus } from "./utils/version.js";

/** Convert camelCase arg name to snake_case so oclif's toUpperCase() produces UPPER_SNAKE_CASE */
export function camelToSnake(name: string): string {
Expand Down Expand Up @@ -229,7 +228,7 @@ export default class CustomHelp extends Help {
const headerLines = [
chalk.bold(titleText),
"",
formatReleaseStatus(config.version, true),
chalk.dim(`Version ${config.version}`),
"",
`${chalk.bold("USAGE")}`,
` ${this.interactiveMode ? "ably> " : chalk.green("$") + " " + chalk.cyan(config.bin) + " "}[COMMAND]`,
Expand Down Expand Up @@ -325,7 +324,7 @@ export default class CustomHelp extends Help {
lines.push(
chalk.bold("ably.com browser-based CLI for Pub/Sub, Chat and Spaces"),
"",
formatReleaseStatus(this.config.version, true),
chalk.dim(`Version ${this.config.version}`),
"",
);

Expand Down
8 changes: 1 addition & 7 deletions src/hooks/init/version-flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import {
JsonRecordType,
formatJsonString,
} from "../../utils/output.js";
import {
getVersionInfo,
formatVersionString,
formatReleaseStatus,
} from "../../utils/version.js";
import { getVersionInfo, formatVersionString } from "../../utils/version.js";

/**
* Helper function to handle exit or throw based on interactive mode
Expand Down Expand Up @@ -61,9 +57,7 @@ const hook: Hook<"init"> = async function (opts) {
console.log(jsonOutput);
handleVersionExit();
} else {
// Non-JSON output: show standard version string and release status
console.log(formatVersionString(config));
console.log(formatReleaseStatus(config.version, true));
handleVersionExit();
}
}
Expand Down
9 changes: 0 additions & 9 deletions src/utils/version.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/**
* Common utilities for version-related functionality
*/
import chalk from "chalk";
// Import package.json directly - TypeScript will resolve this at compile time
import packageJson from "../../package.json" with { type: "json" };
import isWebCliMode from "./web-mode.js";
Expand Down Expand Up @@ -46,14 +45,6 @@ export function getVersionInfo(config: {
};
}

/**
* Format release status with version number
*/
export function formatReleaseStatus(version: string, colored = false): string {
const status = `Public Preview - Version ${version}`;
return colored ? chalk.yellow(status) : status;
}

/**
* Format version info as a standard string
*/
Expand Down
6 changes: 3 additions & 3 deletions test/unit/commands/version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ describe("version command", () => {
expect(stdout).toContain(process.version);
});

it("should display Public Preview status", async () => {
it("should display version info without Public Preview text", async () => {
const { stdout } = await runCommand(["version"], import.meta.url);

expect(stdout).toContain("Public Preview");
expect(stdout).toContain("Version");
expect(stdout).not.toContain("Public Preview");
expect(stdout).toContain("@ably/cli");
});

it("should output JSON when --json flag is used", async () => {
Expand Down
Loading