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
154 changes: 112 additions & 42 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,134 @@
# Contributing to Aether Agent

Thanks for helping out. Aether Agent is a small, focused TypeScript client — easy
to read end to end in an afternoon.
Aether Agent is a TypeScript CLI for Node.js 24 or newer. Keep changes focused,
fail closed at security boundaries, and avoid runtime dependencies unless the
benefit and review plan are explicit.

## Setup
## Set up a development checkout

```bash
git clone https://github.com/AetherAI3/aether-agent
```sh
git clone https://github.com/AetherAI3/aether-agent.git
cd aether-agent
npm install
npm ci --ignore-scripts
npm run build
```

Use `npm ci --ignore-scripts`, not `npm install`, for a reproducible checkout.
The package intentionally has zero runtime dependencies.

## Repository map

```text
src/main.ts executable entry and top-level dispatch
src/commands/ shell/slash commands and command manifest
src/core/ transport, auth, brains, tools, policy, diagnostics
src/ui/ terminal rendering and interaction
src/skills/builtin/ packaged built-in skills and eval cases
scripts/ docs, production, release-truth, and demo tooling
test/ node:test unit, integration, CLI, and policy tests
docs/generated/ manifest/catalogue outputs; do not hand-edit
docs/model-catalogue/ verified Cloud public-projection snapshot
install.sh / install.ps1 POSIX and Windows installers
```

`src/core/client.ts` is the shared client route. Public command metadata lives
in `src/commands/command_manifest_data.ts`; executable loaders remain separate.
Regenerate derived documentation after changing the manifest.

## Local verification

Run the narrow tests for your change while developing, then run the full gates:

```sh
npm run build
npm run typecheck
npm run lint
npm test
npm run smoke
npm run docs:check
npm run verify:production
npm run release:truth
npm pack --dry-run
```

Node ≥ 24. Zero runtime dependencies — the client uses only Node built-ins, and
that's a feature we'd like to keep. Please don't add a runtime dep without a very
good reason and a maintainer's nod.
`npm run lint` is the dependency-free strict TypeScript lint gate. `npm test`
builds first, then runs the repository's unit and integration tests from
`dist/test`. The smoke harness is environment-aware: signed-in Cloud and local
Ollama checks can report skips when those services are not configured, but a
real failure must not be relabeled as a skip.

## Layout
Useful installed-CLI smoke checks after `npm run build` are:

```sh
node dist/src/main.js --version
node dist/src/main.js --help
node dist/src/main.js auth status
node dist/src/main.js doctor
node dist/src/main.js doctor --live --no-ui
```
src/
main.ts CLI entry + arg parsing + command dispatch
index.ts public library API (createClient)
core/ the universal route — transport, stream, client, auth, ...
commands/ one file per command (chat, models, login, audit, ...)
test/ node:test unit tests

Use a temporary `AETHER_CONFIG_DIR` when testing first-run or authentication
states. Never commit a token, config directory, support bundle, or live receipt.

## Generated and public truth

- Run `npm run docs:generate` only when the command manifest or verified public
catalogue projection changed; commit every resulting generated file.
- `npm run docs:check` must be clean. Do not hand-edit `docs/generated/**` or
generated catalogue outputs.
- Runtime `aether models` is authoritative for account-scoped model
availability. Catalogue refreshes must come through the canonical Cloud
public-projection and digest verification path.
- `npm run verify:production` checks package contents, installers, workflows,
exact-tarball installation, and public-document policy.
- `npm run release:truth` performs the public/release truth checks, including
live registry evidence when available. An unavailable required probe is not
a pass.

## Installer syntax checks

On macOS, Linux, or WSL:

```sh
sh -n install.sh
bash -n install.sh
```

The keystone is `src/core/client.ts` — the one chat route every surface shares.
Most features touch a `core/` module + a `commands/` file.
On Windows PowerShell:

## Ground rules
```powershell
$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile(
(Resolve-Path .\install.ps1),
[ref]$tokens,
[ref]$errors
) > $null
if ($errors) { $errors; exit 1 }
```

- **Tests pass.** `npm test` is green before you open a PR. Add tests for new
logic (the stream decoder, catalog parsing, and arg resolution are all unit-
tested — match that bar).
- **Types pass.** `npm run typecheck` uses the repository's pinned TypeScript 7
compiler and strict project settings.
- **Production policy passes.** `npm run verify:production` checks the npm
package allowlist, pinned CI actions, bounded jobs, and installer safety.
- **Types are honest.** No `any` in application code; narrow `unknown`.
- **Small files, one job each.** If a file grows past ~300 lines it's probably
doing too much.
- **Comments explain *why*.** The code says what.
- **No secrets, ever.** No tokens, keys, or internal hostnames in code, tests,
comments, or fixtures. Aether Agent talks to the public Aether API and nothing
else.
Installers must keep npm lifecycle scripts disabled and must not recommend a
mutable-main `curl | sh` flow. Test permission, PATH, unsupported-Node, and
headless-browser failures without weakening TLS or authentication.

## What makes a great PR
## Pull request expectations

- A clear title and a one-paragraph "why".
- Focused scope — one change per PR.
- Tests for the behavior you added or fixed.
- A note in the PR if you changed the public library API.
- Explain the user-visible problem and why the change is scoped to it.
- Add regression coverage for success, refusal, and actionable failure output.
- Keep generated files in sync and list the exact verification commands run.
- Call out platform coverage and anything not exercised live.
- Include `npm pack --dry-run` evidence for package/runtime changes.
- Do not version-bump, tag, publish, or edit release evidence in a feature PR.
- Do not mix unrelated cleanup into the change.

## Reporting bugs / ideas
## Security boundaries

Open an [issue](https://github.com/AetherAI3/aether-agent/issues). For security
reports, **do not** open a public issue — see [`SECURITY.md`](SECURITY.md).
Never weaken TLS enforcement, credential handling, secret redaction,
confirmation gates, sandbox/workspace confinement, tool permissions, or local
authority checks to make a test pass. Do not add internal hosts, private model
routes, tokens, keys, or real account data to source, fixtures, logs, docs, or
PR text. Security reports belong in the private process described in
[`SECURITY.md`](SECURITY.md), not a public issue.

By contributing you agree your contributions are licensed under Apache-2.0.
By contributing, you agree that your contributions are licensed under
Apache-2.0.
2 changes: 1 addition & 1 deletion docs/generated/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This reference is generated from the validated, versioned command manifest. Avai

Global shell flags accepted by the manifest:

`--agent`, `--all`, `--apply`, `--audit`, `--available`, `--ci`, `--cwd`, `--effort`, `--help`, `--interactive`, `--json`, `--junit`, `--license-key`, `--local`, `--model`, `--no-browser`, `--no-log`, `--no-skills`, `--out`, `--password`, `--pool`, `--quiet`, `--repo`, `--resume`, `--scope`, `--skill`, `--swarm`, `--test-cmd`, `--token`, `--username`, `--version`, `--with-token`, `--worktree`, `--yes`
`--agent`, `--all`, `--apply`, `--audit`, `--available`, `--ci`, `--cwd`, `--effort`, `--help`, `--interactive`, `--json`, `--junit`, `--license-key`, `--local`, `--model`, `--no-browser`, `--no-log`, `--no-skills`, `--out`, `--password`, `--pool`, `--quiet`, `--repo`, `--resume`, `--scope`, `--skill`, `--test-cmd`, `--token`, `--username`, `--version`, `--with-token`, `--worktree`, `--yes`

## Shell commands

Expand Down
156 changes: 47 additions & 109 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Aether Agent installer — Windows (PowerShell).
# Aether Agent installer - Windows (PowerShell).
#
# Download, inspect, then run this file with: .\install.ps1
#
Expand All @@ -16,69 +16,27 @@ if ($Version -notmatch '^[0-9A-Za-z.+-]+$') {
throw "Invalid Version: use latest, a dist-tag, or a semver."
}

# ── Color helpers ──
$cyan = 11 # BrightCyan (ANSI 44 ≈ #1aa6b7)
$ice = 12 # BrightBlue (ANSI 117 ≈ #87d7ff)
# Color helpers
$cyan = 11 # BrightCyan
$green = 10 # BrightGreen
$red = 12 # Red (error — redefined below)
$dim = 8 # DarkGray

$red_error = 12
$green_ok = 10

function Write-Header($msg) { Write-Host $msg -ForegroundColor $cyan }
function Write-Success($msg) { Write-Host " ✓ " -NoNewline -ForegroundColor $green_ok; Write-Host $msg -ForegroundColor $dim }
function Write-ErrorMsg($msg) { Write-Host " ✗ " -NoNewline -ForegroundColor $red_error; Write-Host $msg }
function Write-Success($msg) { Write-Host " [ok] " -NoNewline -ForegroundColor $green_ok; Write-Host $msg -ForegroundColor $dim }
function Write-ErrorMsg($msg) { Write-Host " [error] " -NoNewline -ForegroundColor $red_error; Write-Host $msg }
function Write-Info($msg) { Write-Host " $msg" -ForegroundColor $dim }
function Write-Step($msg) { Write-Host "$msg... " -NoNewline -ForegroundColor $dim }

# ── Cloud glyph ──
function Write-Cloud {
Write-Host " ▄▄███▄▄ " -ForegroundColor $ice
Write-Host " ▄█████████▄ " -ForegroundColor $ice
Write-Host " ███▄███▄███ " -ForegroundColor $ice
Write-Host " ▀████▄████▀ " -ForegroundColor $ice
Write-Host " ▀ ▀ ▀ ▀ " -ForegroundColor $ice
}

# ── Box drawing helper (PowerShell terminal supports Unicode box-drawing) ──
function Write-BoxTop($width = 62) {
$h = "─" * ($width - 2)
Write-Host "┌${h}┐" -ForegroundColor $cyan
}
function Write-BoxBottom($width = 62) {
$h = "─" * ($width - 2)
Write-Host "└${h}┘" -ForegroundColor $cyan
}
function Write-BoxLine($text, $width = 62) {
$inner = $width - 6
$pad = [Math]::Max(0, $inner - $text.Length)
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " ${text}" -NoNewline
Write-Host (" " * $pad + " ") -NoNewline
Write-Host "│" -ForegroundColor $cyan
}
function Write-BoxEmpty($width = 62) {
Write-BoxLine "" $width
}

# ── Banner ──
# Banner
Write-Host ""
Write-Cloud
Write-Host ""
Write-BoxTop
Write-BoxEmpty
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " ☁ Aether Agent — Terminal Coding Agent Installer " -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " npm release $Version · aethersystems.net " -NoNewline -ForegroundColor $dim
Write-Host "│" -ForegroundColor $cyan
Write-BoxEmpty
Write-BoxBottom
Write-Header "Aether Agent - Terminal Coding Agent Installer"
Write-Info "npm release $Version | aethersystems.net"
Write-Host ""

# ── Check Node.js ──
# Check Node.js
if (-not $SkipNodeCheck) {
Write-Step "Checking Node.js"
$nodePath = Get-Command node -ErrorAction SilentlyContinue
Expand All @@ -102,7 +60,7 @@ if (-not $SkipNodeCheck) {
}
}

# ── Check npm ──
# Check npm
Write-Step "Checking npm"
$npmPath = Get-Command npm -ErrorAction SilentlyContinue
if (-not $npmPath) {
Expand All @@ -113,15 +71,15 @@ if (-not $npmPath) {
$npmVersion = npm -v 2>$null
Write-Success "npm v${npmVersion}"

# ── Check if already installed ──
# Check if already installed
$alreadyInstalled = $false
$aetherPath = Get-Command aether -ErrorAction SilentlyContinue
if ($aetherPath) {
$alreadyInstalled = $true
Write-Info "aether-agent already installed — will install $Version."
Write-Info "aether-agent already installed - will install $Version."
}

# ── Install ──
# Install
Write-Host ""
if ($alreadyInstalled) {
Write-Step "Updating aether-agent"
Expand All @@ -136,67 +94,47 @@ if ($alreadyInstalled) {
if ($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne $null) {
Write-ErrorMsg "Install failed. Check your network and npm permissions."
Write-Host ""
Write-Info "If you see EACCES or permission errors:"
Write-Info " 1. Run PowerShell as Administrator"
Write-Info " 2. Or configure npm prefix: npm config set prefix $env:APPDATA\`npm"
if ($Version -ne "latest") {
Write-Info "If npm reports 'No matching version found', $Version is not published."
Write-Info "Published versions: npm view aether-agents versions"
}
$userPrefix = Join-Path $env:LOCALAPPDATA "npm"
Write-Info "For EACCES or permission errors, use a per-user prefix:"
Write-Info (' npm install -g "aether-agents@{0}" --ignore-scripts --prefix "{1}"' -f $Version, $userPrefix)
Write-Info ("Then add $userPrefix to your user PATH and reopen PowerShell.")
exit 1
}

$aetherPath = Get-Command aether -ErrorAction SilentlyContinue
$aetherVersion = "unknown"
if ($aetherPath) {
try { $aetherVersion = (aether --version 2>$null) } catch {}
}
Write-Success "Aether Agent ${aetherVersion} installed!"

# ── Verify ──
if (-not (Get-Command aether -ErrorAction SilentlyContinue)) {
# Verify
if (-not $aetherPath) {
$npmPrefix = (npm config get prefix 2>$null | Select-Object -First 1)
Write-ErrorMsg "aether command not found on PATH after install."
Write-Info "npm global prefix: $(npm config get prefix)"
Write-Info "Add $(npm config get prefix) to your PATH, or reinstall Node."
Write-Info "npm global prefix: $npmPrefix"
Write-Info "Add that directory to your user PATH, reopen PowerShell, then run:"
Write-Info " aether --version"
exit 1
}

# ── Next steps box ──
$aetherVersion = "unknown"
try { $aetherVersion = (aether --version 2>$null) } catch {}
Write-Success "Aether Agent ${aetherVersion} installed!"

# Next steps
Write-Host ""
Write-Header "Ready - hosted first run"
Write-Host ' aether --version'
Write-Host ' aether auth login'
Write-Host ' aether auth status'
Write-Host ' aether models'
Write-Host ' aether agent "explain this repository"'
Write-Host ' aether doctor'
Write-Host ' aether doctor --live'
Write-Info "No browser: aether auth login --no-browser"
Write-Host ""
Write-BoxTop
Write-BoxEmpty
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " ✓ " -NoNewline -ForegroundColor $green_ok
Write-Host "Ready! Next: sign in to unlock the full model fleet. " -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-BoxEmpty
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " " -NoNewline
Write-Host "aether auth login" -NoNewline -ForegroundColor $cyan
Write-Host (" " * 42) -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-BoxEmpty
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " Opens aethersystems.net/platform in your browser. " -NoNewline -ForegroundColor $dim
Write-Host "│" -ForegroundColor $cyan
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " → click Approve → you're in. " -NoNewline -ForegroundColor $dim
Write-Host "│" -ForegroundColor $cyan
Write-BoxEmpty
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " Then start coding: " -NoNewline -ForegroundColor $dim
Write-Host "│" -ForegroundColor $cyan
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " " -NoNewline
Write-Host "aether `"explain src/router.ts`"" -NoNewline -ForegroundColor $dim
Write-Host (" " * 28) -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " " -NoNewline
Write-Host "aether agent `"fix the failing tests`"" -NoNewline -ForegroundColor $dim
Write-Host (" " * 23) -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-Host "│" -NoNewline -ForegroundColor $cyan
Write-Host " " -NoNewline
Write-Host "aether agent --local `"same, fully offline`"" -NoNewline -ForegroundColor $dim
Write-Host (" " * 19) -NoNewline
Write-Host "│" -ForegroundColor $cyan
Write-BoxEmpty
Write-BoxBottom
Write-Header "Optional local Ollama path"
Write-Host ' aether setup --local'
Write-Host ' aether local pull qwen2.5-coder:7b --yes'
Write-Host ' aether agent --local "explain this repository"'
Write-Info "Ollama must be installed and running before the local steps."
Write-Host ""
Loading