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
87 changes: 87 additions & 0 deletions .github/workflows/release-binaries.yaml
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -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
Comment thread
lcandy2 marked this conversation as resolved.
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
215 changes: 207 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 <project-id>

# 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/<env>.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 <id>` every time, link a project for the current env:

```sh
photon link abc123 # writes $PHOTON_CONFIG_DIR/links/<env>.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 <id>` 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/<env>.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 <id> 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 <number> 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 <file>
└── billing
├── plans available plans
├── show current subscription
├── checkout --plan <price-id> Stripe Checkout (browser)
└── manage Stripe Customer Portal
```

Run `photon <cmd> --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 <name>` | `PHOTON_ENV` | per-cmd | override active env |
| `-p, --project <id>` | `PHOTON_PROJECT_ID` | per-cmd | override linked project |
| `-t, --token <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.
Loading