diff --git a/CHANGELOG.md b/CHANGELOG.md index fd7f9c2..3cda18d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ byte-for-byte unchanged apart from the `cli_version` field. and `Looked in:` paths now print home-relative (`~/.claude/skills`) - Fixed `NO_COLOR=''` (empty value) not being treated as "set" — the no-color.org standard disables color on presence, not truthiness +- Sync messaging: CLI description, error output, and README now say the + hosted service is retired, not paused/rebuilt ## [0.2.0] diff --git a/README.md b/README.md index 5a90632..ad0886d 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ npx devcat-cli --json | jq '.clients[] | {label, total}' | `devcat` | Scan and print your stack. Same as `devcat report`. | | `devcat report --markdown` | Print the shareable "My AI stack" snippet instead. | | `devcat report --json` | Print the scan as one JSON object. | -| `devcat sync` | Push your manifest to devcat.dev. **Paused** — see [Profile sync](#profile-sync). | +| `devcat sync` | Push your manifest to devcat.dev. **Retired** — see [Profile sync](#profile-sync). | | `devcat logout` | Clear local DevCat credentials. | | `devcat --version` / `--help` | Version, help. | @@ -178,7 +178,7 @@ devcat |---|---|---| | `NO_COLOR` | unset | Disable color output ([no-color.org](https://no-color.org/) standard). | -The four other variables the CLI reads take effect only on `devcat sync`, which is paused — they are documented under [Profile sync](#profile-sync). +The four other variables the CLI reads take effect only on `devcat sync`, whose hosted default is retired — they are documented under [Profile sync](#profile-sync). ## Security @@ -198,19 +198,19 @@ The four other variables the CLI reads take effect only on `devcat sync`, which -## Profile sync — paused while devcat.dev is rebuilt +## Profile sync — retired -Every other command in this README works offline and needs no account. This section covers `devcat sync` — the only command that talks to a server, and the only part of the CLI currently unavailable. +Every other command in this README works offline and needs no account. This section covers `devcat sync` — the only command that talks to a server, and the only one whose hosted default is retired. -`devcat sync` pushes your manifest to a devcat.dev profile. **That site is being rebuilt, so sync is paused** — it stops immediately with one line rather than starting a sign-in it can't finish: +`devcat sync` pushed your manifest to a devcat.dev profile. **devcat.dev no longer hosts profiles — the hosted service is retired.** By default, `sync` now stops immediately with one line rather than starting a sign-in it can't finish: ``` -✗ Profile sync is paused while devcat.dev is rebuilt. Your local stack report still works — run `npx devcat-cli`. +✗ Profile sync is retired — devcat.dev no longer hosts profiles. Your local stack report still works — run `npx devcat-cli`. ``` -Nothing else is affected: the scan, `--markdown`, and `logout` all work offline as normal. Sync returns with the site. +Nothing else is affected: the scan, `--markdown`, and `logout` all work offline as normal. -The sync path itself is intact — [RFC 8628 device authorization](https://datatracker.ietf.org/doc/html/rfc8628), tokens in your OS keychain via [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring), no plaintext token on disk. If you run your own instance, point `DEVCAT_API_URL` at it and set `DEVCAT_SYNC_ENABLED=1` to run the full flow. +The sync path itself is intact — [RFC 8628 device authorization](https://datatracker.ietf.org/doc/html/rfc8628), tokens in your OS keychain via [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring), no plaintext token on disk. The hosted service is retired, but the self-host path remains: if you run your own instance, point `DEVCAT_API_URL` at it and set `DEVCAT_SYNC_ENABLED=1` to run the full flow. Sync sends MCP servers and plugins only. Skills and subagents are local report detections — they are folders on your machine with no catalog entry behind them, and they never enter the sync payload. @@ -220,7 +220,7 @@ These four are read only on the sync and sign-in paths; none of them changes wha | Variable | Default | Purpose | |---|---|---| -| `DEVCAT_SYNC_ENABLED` | unset | Set to `1` to run `devcat sync` against a live API instead of stopping at the paused message. | +| `DEVCAT_SYNC_ENABLED` | unset | Set to `1` to run `devcat sync` against a live API instead of stopping at the retired message. | | `DEVCAT_API_URL` | `https://devcat.dev` | Override the API base URL (staging / self-hosted). HTTPS required except `http://localhost:*`. | | `DEVCAT_TOKEN` | unset | CI escape hatch — bypass keychain and use this access token directly. | | `DEVCAT_DEBUG` | unset | Verbose logging without the `--verbose` flag. | diff --git a/src/cli.ts b/src/cli.ts index c9ab532..274051d 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -55,7 +55,7 @@ export function buildProgram(sink: ExitCodeSink): Command { program .command('sync') - .description('Push your AI tool manifest to devcat.dev (paused while the site is rebuilt)') + .description('Push your AI tool manifest to devcat.dev (hosted sync retired)') .option('--no-open', 'do not auto-open the browser at the verification URL') .option('--json', 'emit machine-readable JSON event stream (for CI)') .option('-v, --verbose', 'emit redacted HTTP trace to stderr') diff --git a/src/commands/sync.ts b/src/commands/sync.ts index 75e6c60..e92c9eb 100644 --- a/src/commands/sync.ts +++ b/src/commands/sync.ts @@ -47,17 +47,18 @@ export interface SyncOptions { } /** - * devcat.dev is being rebuilt, so the hosted sync endpoint is not answering. - * Sync stops on the one line below instead of running the device flow and - * failing deep inside an HTTP call — no browser, no polling, no retries. + * The hosted devcat.dev sync endpoint is retired — devcat.dev no longer + * accepts profile syncs. Sync stops on the one line below instead of + * running the device flow and failing deep inside an HTTP call — no + * browser, no polling, no retries. * * The whole sync path underneath is untouched and still compiles. Set - * DEVCAT_SYNC_ENABLED=1 to run it anyway (integration tests do this, as does - * anyone pointing DEVCAT_API_URL at their own host). Delete this gate when - * devcat.dev is back. + * DEVCAT_SYNC_ENABLED=1 to run it anyway against a self-hosted instance — + * point DEVCAT_API_URL at it first. This gate is permanent for the hosted + * default, not a flag to delete once devcat.dev "comes back." */ const SYNC_PAUSED_MESSAGE = - 'Profile sync is paused while devcat.dev is rebuilt. Your local stack report still works — run `npx devcat-cli`.'; + 'Profile sync is retired — devcat.dev no longer hosts profiles. Your local stack report still works — run `npx devcat-cli`.'; function isSyncPaused(): boolean { return process.env.DEVCAT_SYNC_ENABLED !== '1'; diff --git a/test/integration/sync.paused.test.ts b/test/integration/sync.paused.test.ts index c0b0c31..435a026 100644 --- a/test/integration/sync.paused.test.ts +++ b/test/integration/sync.paused.test.ts @@ -1,10 +1,10 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; /** - * devcat.dev is being rebuilt, so `devcat sync` stops on one line instead of - * starting a device flow that cannot finish. This suite deliberately does NOT - * set DEVCAT_SYNC_ENABLED — it covers the paused path the other sync - * integration suites opt out of. + * devcat.dev's hosted sync is retired, so `devcat sync` stops on one line + * instead of starting a device flow that cannot finish. This suite + * deliberately does NOT set DEVCAT_SYNC_ENABLED — it covers the retired + * path the other sync integration suites opt out of. */ process.env.NO_COLOR = '1'; @@ -19,7 +19,7 @@ afterEach(() => { else process.env.DEVCAT_SYNC_ENABLED = originalFlag; }); -describe('sync — paused while devcat.dev is down', () => { +describe('sync — retired (devcat.dev no longer hosts profiles)', () => { it('prints exactly one line, opens no browser, makes no request, exits 1', async () => { const stderr: string[] = []; const stdout: string[] = []; @@ -50,7 +50,7 @@ describe('sync — paused while devcat.dev is down', () => { const err = stderr.join(''); expect(err.trimEnd().split('\n')).toHaveLength(1); - expect(err).toContain('Profile sync is paused while devcat.dev is rebuilt.'); + expect(err).toContain('Profile sync is retired — devcat.dev no longer hosts profiles.'); expect(err).toContain('npx devcat-cli'); // No stack trace, no retry noise. expect(err).not.toContain('at ');