Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
85 changes: 85 additions & 0 deletions .github/workflows/release-binaries.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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-13
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
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:
bun-version: latest
Comment thread
lcandy2 marked this conversation as resolved.
Outdated

- 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

on:
pull_request:
types: [closed]
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:
# Only fire when the PR was actually merged (not just closed).
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true }}
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-cli
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 }}
Comment thread
lcandy2 marked this conversation as resolved.
Outdated
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Photon

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
196 changes: 188 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,195 @@
# 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/cli
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/cli

# 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
```

---

## 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 --env staging projects ls # one-off override
PHOTON_ENV=staging photon projects ls # same, via env var
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
```

Credentials are stored **per environment** (`~/.config/photon/credentials/<env>.json`, mode 600), so you can be logged into prod and dev simultaneously.
Comment thread
lcandy2 marked this conversation as resolved.
Outdated
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

### 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 ~/.config/photon/links/<env>.json
Comment thread
lcandy2 marked this conversation as resolved.
Outdated
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 `~/.config/photon/credentials/<env>.json`, and use it in CI:

```sh
photon --token "$PHOTON_TOKEN" projects ls
# or
PHOTON_TOKEN=… photon projects ls
```

Pair with `--json` for machine-readable output:

```sh
photon projects ls --json | jq '.[] | .id'
photon billing show --json
```

`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
```

To run:
Run `photon <cmd> --help` for the full flag list of any command.

---

## Global flags

| Flag | Env var | Effect |
|---|---|---|
| `-e, --env <name>` | `PHOTON_ENV` | override active env |
| `-p, --project <id>` | `PHOTON_PROJECT_ID` | override linked project (per-command) |
| `-t, --token <token>` | `PHOTON_TOKEN` | bypass stored creds (CI) |
| `--json` | — | structured output (per-command, opt-in) |
| `--yes`, `-y` | — | skip destructive-action confirmation |
| `--no-browser` | — | don't auto-open browser (login, billing, projects open) |
| `--no-color` | `NO_COLOR=1`, `PHOTON_NO_COLOR=1` | disable colors (NO_COLOR standard) |
| `--debug` | `PHOTON_DEBUG=1` | verbose HTTP logs to stderr |

Other env vars: `PHOTON_CONFIG_DIR` (defaults to `~/.config/photon/`), `PHOTON_TYPES_SRC` (maintainer-only, for `bun run sync:api`), `PHOTON_NO_UPDATE_NOTIFIER=1` (mute update prompt).

---

```bash
bun run index.ts
## 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
```

This project was created using `bun init` in bun v1.3.13. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
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, 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.

---

## License

[MIT](./LICENSE).
Loading