diff --git a/.github/workflows/release-binaries.yaml b/.github/workflows/release-binaries.yaml new file mode 100644 index 0000000..970bf0d --- /dev/null +++ b/.github/workflows/release-binaries.yaml @@ -0,0 +1,87 @@ +name: Release Binaries + +# Build standalone `photon` binaries (no Bun runtime required) and +# attach them to the GitHub Release that the `release.yaml` workflow +# created. Runs on `release: created` so it stays decoupled from the +# npm publish flow — npm consumers get the Bun bundle, Release-page +# downloaders get a self-contained executable. + +on: + release: + types: [created] + workflow_dispatch: + inputs: + tag: + type: string + description: "Existing release tag to attach binaries to" + required: true + +permissions: + contents: write + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + target: bun-darwin-arm64 + asset: photon-darwin-arm64 + - os: macos-15-intel + target: bun-darwin-x64 + asset: photon-darwin-x64 + - os: ubuntu-latest + target: bun-linux-x64 + asset: photon-linux-x64 + - os: ubuntu-latest + target: bun-linux-arm64 + asset: photon-linux-arm64 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v5 + - uses: oven-sh/setup-bun@v2 + with: + # Pinned for reproducibility — matches the lower bound in + # package.json#engines.bun. Bump intentionally when upgrading. + bun-version: "1.3.13" + + - name: Install + run: bun install --frozen-lockfile + + - name: Compile binary + run: | + bun build ./src/index.ts \ + --compile \ + --target=${{ matrix.target }} \ + --outfile dist/${{ matrix.asset }} + + - name: Smoke test (native targets only) + if: matrix.target == 'bun-darwin-arm64' || matrix.target == 'bun-linux-x64' + run: ./dist/${{ matrix.asset }} --version + + - name: Compute SHA256 + run: | + if command -v shasum >/dev/null 2>&1; then + shasum -a 256 dist/${{ matrix.asset }} > dist/${{ matrix.asset }}.sha256 + else + sha256sum dist/${{ matrix.asset }} > dist/${{ matrix.asset }}.sha256 + fi + + - name: Resolve release tag + id: tag + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT" + fi + + - name: Upload to release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload "${{ steps.tag.outputs.tag }}" \ + "dist/${{ matrix.asset }}" \ + "dist/${{ matrix.asset }}.sha256" \ + --clobber diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..40e1143 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,33 @@ +name: Release + +# Mirrors the photon-hq pattern (see spectrum-ts, uri): push to main, +# let buildspace's PR-label gate look back at the merge commit and +# decide whether to actually release. `secrets: inherit` passes +# org-level OPENAI_API_KEY + NPM_TOKEN through automatically. + +on: + push: + branches: [main] + workflow_dispatch: + inputs: + release: + type: boolean + description: "Force release (skip the PR-label check)" + default: false + dry-run: + type: boolean + description: "Run without publishing" + default: false + +jobs: + release: + uses: photon-hq/buildspace/.github/workflows/typescript-service-release.yaml@main + permissions: + contents: write + pull-requests: read + with: + service-name: "@photon-ai/photon" + build-command: "bun run build" + release: ${{ github.event_name == 'workflow_dispatch' && inputs.release || false }} + dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs['dry-run'] || false }} + secrets: inherit diff --git a/README.md b/README.md index c6ffeaf..699a72d 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,214 @@ -# dashboard-cli +# Photon CLI -To install dependencies: +Typed terminal UI for the [Photon Dashboard](https://photon.codes). Replaces the web UI for everyday work — manage projects, Spectrum users / lines / platforms, billing, and your developer profile from a terminal. -```bash -bun install +```sh +bun add -g @photon-ai/photon +photon login +photon projects ls +``` + +> **Bun required.** This CLI ships as a Bun bundle. Install Bun: `curl -fsSL https://bun.sh/install | bash`. Standalone binaries (no Bun needed) are attached to each [GitHub Release](https://github.com/photon-hq/cli/releases) for macOS (arm64 / x64) and Linux (x64 / arm64). + +--- + +## Quickstart + +```sh +# 1. Install +bun add -g @photon-ai/photon + +# 2. Log in (opens a browser to approve the device) +photon login + +# 3. Link a project so future commands default to it +photon projects ls +photon link + +# 4. Off you go +photon projects show +photon spectrum users ls +photon billing show +``` + +`pho` is an alias for `photon` for high-frequency commands: + +```sh +pho ls # photon projects ls +pho whoami +``` + +Or run one-off commands without installing via `npx` / `bunx`: + +```sh +bunx @photon-ai/photon login +bunx @photon-ai/photon projects ls +npx @photon-ai/photon whoami # also works +``` + +--- + +## Concepts + +### Environments + +Every command operates against an **environment** (production by default). Built-ins: + +| Name | URL | +|---|---| +| `production` | `https://app.photon.codes` | +| `staging` | `https://staging-app.photon.codes` | +| `dev` | `http://localhost:3001` | + +```sh +photon env list # show all +photon env use staging # persist as default +photon env add my-test https://my.test.tld # add a custom env +photon projects ls --env staging # one-off override +PHOTON_ENV=staging photon projects ls # same, via env var +``` + +Credentials are stored **per environment** (`$PHOTON_CONFIG_DIR/credentials/.json` by default — see [config dir](#config-dir) below — mode 600), so you can be logged into prod and dev simultaneously. + +### Project linking + +Most commands operate on a single project. Rather than passing `--project ` every time, link a project for the current env: + +```sh +photon link abc123 # writes $PHOTON_CONFIG_DIR/links/.json +photon spectrum users ls # implicit project from link +photon projects show # same +photon link:status # see what's linked across envs +photon unlink # clear the link +``` + +Resolution order: `--project ` flag → `$PHOTON_PROJECT_ID` → linked project → friendly error. + +### CI / scripting + +Authenticate once locally, copy the token from your credentials file (under `$PHOTON_CONFIG_DIR/credentials/.json`), and use it in CI: + +```sh +photon projects ls --token "$PHOTON_TOKEN" +# or +PHOTON_TOKEN=… photon projects ls ``` -To run: +Pair with `--json` for machine-readable output: -```bash -bun run index.ts +```sh +photon projects ls --json | jq '.[] | .id' +photon billing show --json ``` -This project was created using `bun init` in bun v1.3.13. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. +`PHOTON_TOKEN` reuses the same access token issued by the device flow (default 7d expiry — re-run `photon login` when it expires). A long-lived API-key path is on the roadmap. + +--- + +## Command reference + +```text +photon +├── ping hit /api/health +├── env list/use/add/remove/current env management +├── login [--env] [--no-browser] device-auth login +├── logout [--env] clear creds +├── whoami [--env] who am I on this env +├── auth status login state across envs +├── config show dump active config +├── link link project for env +├── unlink clear link +├── link:status linked projects (all envs) +├── projects +│ ├── ls list projects +│ ├── show [id] project detail +│ ├── create [-n --location --spectrum ...] [--link] new project +│ ├── update [id] [...] rename / toggle flags +│ ├── delete [id] [-y] permanent delete +│ ├── regenerate-secret [id] [-y] rotate Spectrum secret +│ ├── open [id] open dashboard in browser +│ └── check-phone availability check +├── profile show / init / update developer / org profile +├── spectrum +│ ├── users ls / add / remove +│ ├── lines ls / add / remove +│ ├── platforms ls / enable / disable +│ ├── profile show / update +│ └── avatar upload +└── billing + ├── plans available plans + ├── show current subscription + ├── checkout --plan Stripe Checkout (browser) + └── manage Stripe Customer Portal +``` + +Run `photon --help` for the full flag list of any command. + +--- + +## Flags + +Only `--debug` is truly **program-level** (works in any position). Every other flag is **per-command** and must come after the subcommand: + +```sh +photon --debug projects ls --env staging --json # ✓ --debug global, others per-cmd +photon --env staging projects ls # ✗ won't work (--env is per-cmd) +``` + +| Flag | Env var | Scope | Effect | +|---|---|---|---| +| `--debug` | `PHOTON_DEBUG=1` | program | verbose HTTP logs to stderr | +| `-e, --env ` | `PHOTON_ENV` | per-cmd | override active env | +| `-p, --project ` | `PHOTON_PROJECT_ID` | per-cmd | override linked project | +| `-t, --token ` | `PHOTON_TOKEN` | per-cmd | bypass stored creds (CI) | +| `--json` | — | per-cmd | structured output (opt-in) | +| `--yes`, `-y` | — | per-cmd | skip destructive-action confirmation | +| `--no-browser` | — | per-cmd | don't auto-open browser (login, billing, projects open) | +| `--no-color` | `NO_COLOR=1`, `PHOTON_NO_COLOR=1` | program (env-driven) | disable colors (NO_COLOR standard) | + +### config dir + +The CLI's config root is resolved in this order: + +1. `$PHOTON_CONFIG_DIR` (explicit override) +2. `$XDG_CONFIG_HOME/photon` (XDG standard) +3. `~/.config/photon/` (default) + +If a legacy `~/.config/photon-dashboard/` directory exists from a prior pre-rename install, it migrates automatically to the new path on first run. + +Other env vars: `PHOTON_TYPES_SRC` (maintainer-only, for `bun run sync:api`), `PHOTON_NO_UPDATE_NOTIFIER=1` (mute update prompt). + +--- + +## Development + +```sh +git clone https://github.com/photon-hq/cli +cd cli +bun install + +# Run from source +bun run src/index.ts --help + +# Watch +bun run dev + +# Typecheck +bun run typecheck + +# Build (produces dist/photon.js) +bun run build + +# Sync API types from a sibling `dashboard` checkout (maintainer) +bun run sync:api +``` + +The CLI's API contract comes from the `@photon-ai/api-public` type bundle, vendored at `types/api.d.ts`. To refresh after the dashboard's API surface changes, run `bun run sync:api` (looks for the sibling checkout by default; set `PHOTON_TYPES_SRC` to override). + +See [`docs/cli-design.md`](docs/cli-design.md) and [`docs/cli-build-plan.md`](docs/cli-build-plan.md) for the full architecture notes. + +--- + +## Releases + +Tagged via PR labels. Add the `release` label to any PR; on merge to `main`, the [Release workflow](.github/workflows/release.yaml) (a thin caller of [`photon-hq/buildspace`'s `typescript-service-release`](https://github.com/photon-hq/buildspace)) generates a version + notes, bumps `package.json`, creates a GitHub Release, and publishes to npm. Standalone binaries are uploaded by [`release-binaries.yaml`](.github/workflows/release-binaries.yaml) on each release. diff --git a/package.json b/package.json index d77795b..e75f7f6 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,53 @@ { - "name": "dashboard-cli", + "name": "@photon-ai/photon", "version": "0.0.1", "description": "Photon CLI — typed terminal UI for the Photon Dashboard. Binary: `photon` (alias `pho`).", + "keywords": [ + "photon", + "cli", + "dashboard", + "spectrum", + "messaging", + "imessage", + "developer-tools" + ], + "author": "Photon", + "homepage": "https://github.com/photon-hq/cli#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/photon-hq/cli.git" + }, + "bugs": { + "url": "https://github.com/photon-hq/cli/issues" + }, "type": "module", - "private": true, "bin": { - "photon": "./src/index.ts", - "pho": "./src/index.ts" + "photon": "./dist/photon.js", + "pho": "./dist/photon.js" + }, + "files": [ + "dist", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "engines": { + "bun": ">=1.3.0" }, "scripts": { "start": "bun run src/index.ts", "dev": "bun run --watch src/index.ts", - "build": "bun build ./src/index.ts --outfile dist/photon.js --target bun --minify", + "build": "bun build ./src/index.ts --outfile dist/photon.js --target bun --minify && chmod +x dist/photon.js", "compile": "bun build ./src/index.ts --compile --outfile dist/photon", "typecheck": "tsc --noEmit", - "sync:api": "bun run scripts/sync-api-types.ts" + "sync:api": "bun run scripts/sync-api-types.ts", + "prepublishOnly": "bun run typecheck && bun run build" }, "devDependencies": { "@types/bun": "latest", "@types/update-notifier": "^6.0.8", - "elysia": "1.4.28" - }, - "peerDependencies": { + "elysia": "1.4.28", "typescript": "^5" }, "dependencies": {