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
17 changes: 17 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Checkout with LF everywhere; Windows runners default to core.autocrlf=true,
# which makes oxfmt/cargo fmt see every file as unformatted.
* text=auto eol=lf

# Batch files need CRLF for goto/label parsing.
*.bat text eol=crlf
*.cmd text eol=crlf

*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.ttf binary
*.woff binary
*.woff2 binary
*.vsix binary
47 changes: 46 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ jobs:
with:
bun-version: 1.3.14

# oxfmt/oxlint are installed once at the repo root and cover every hand-written JS/TS subproject.
# The type-aware lints resolve each subproject's own node_modules and
# copy-types output, so those have to exist before oxlint runs
- name: Install frontend dependencies
run: |
bun install --frozen-lockfile
(cd webcomponents && bun install --frozen-lockfile && bun run copy-types)
(cd ui && bun install --frozen-lockfile)
(cd vscode-extension && npm ci && npm run copy-types)

- name: Format and lint frontend
run: |
bun run fmt:check
bun run lint:ui
bun run lint:webcomponents
bun run lint:vscode
bun run lint:agnt
bun run lint:coder-module

- name: Lint shell scripts
run: shellcheck -S warning scripts/*.sh scripts/ci/*.sh .githooks/*

- name: Build shared web components
run: |
cd webcomponents
Expand All @@ -87,7 +109,7 @@ jobs:
fi

- name: Check formatting
run: cargo fmt -- --check
run: cargo fmt --all -- --check

- name: Clippy
run: cargo clippy --locked --all-targets --all-features -- -D warnings
Expand All @@ -102,6 +124,22 @@ jobs:
arguments: --all-features
command: check

# crates/relay has its own Cargo.lock and is not a workspace member, so
# the root fmt/clippy/deny above never reach it.
- name: crates/relay
run: |
cd crates/relay
cargo fmt -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-features

- name: cargo-deny (crates/relay)
uses: EmbarkStudios/cargo-deny-action@v2
with:
manifest-path: crates/relay/Cargo.toml
arguments: --all-features
command: check

- name: Set up Helm
uses: azure/setup-helm@v5.0.1

Expand Down Expand Up @@ -549,6 +587,12 @@ jobs:
run: |
sed -i "s/const VERSION = '[^']*'/const VERSION = '${{ needs.version.outputs.version }}'/" vscode-extension/src/webhook-server.ts

# Pinned by tests/version_parity.rs; the range keeps the sed inside the
# install_version block so sibling variable defaults are untouched.
- name: Update coder-module install_version default
run: |
sed -i '/variable "install_version"/,/^}/ s/^\( default *= *\)"[^"]*"/\1"${{ needs.version.outputs.version }}"/' coder-module/main.tf

# openapi.json's version is code-derived (env!("CARGO_PKG_VERSION")); the
# already-built linux binary embeds the new version, so regenerate the
# committed spec from it instead of recompiling.
Expand All @@ -570,6 +614,7 @@ jobs:
opr8r/Cargo.toml opr8r/Cargo.lock \
zed-extension/Cargo.toml zed-extension/extension.toml zed-extension/Cargo.lock \
agnt-plugin/package.json agnt-plugin/manifest.json \
coder-module/main.tf \
docs/schemas/openapi.json
git commit -m "chore: bump version to v${{ needs.version.outputs.version }} [skip ci]"
git push
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/coder-module.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,14 @@ jobs:
- name: Shell-check the rendered startup script
run: ../scripts/ci/check-coder-module.sh

# The .ts harness is linted/formatted from the repo root, where oxlint
# and oxfmt (and their configs) live.
- name: Lint and format TypeScript harness
working-directory: .
run: |
bun install --frozen-lockfile
bun run lint:coder-module
bun run fmt:check

- name: Test
run: bun test
3 changes: 3 additions & 0 deletions .github/workflows/vscode-extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ jobs:
- name: Lint
run: npm run lint

- name: Check formatting
run: npm run fmt:check

- name: Compile
run: npm run compile

Expand Down
8 changes: 8 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"ignorePatterns": [
"**/generated/**",
"bindings/**",
"shared/types.ts",
"vscode-extension/shared/**"
]
}
20 changes: 17 additions & 3 deletions .oxlintrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,8 @@
"target/**",
"docs/_site/**",
"docs/assets/js/**",
"agnt-plugin/**",
"coder-module/**",
"bindings/**",
"shared/**",
"shared/types.ts",
"scripts/**",
"zed-extension/**",
"opr8r/**"
Expand Down Expand Up @@ -223,6 +221,22 @@
"typescript/no-misused-promises": "off"
}
},
{
"files": ["agnt-plugin/**/*.js"],
"env": { "node": true, "es2022": true }
},
{
"files": ["coder-module/*.ts"],
"env": { "node": true, "es2022": true },
"globals": { "Bun": "readonly" },
"rules": {
// Terraform state attributes are arbitrary JSON; the helper mirrors the
// upstream Coder signature and tests index into it (app.healthcheck[0]).
"typescript/no-explicit-any": "off",
// Per-case async closures passed to expect().toThrow() read better local.
"unicorn/consistent-function-scoping": "off"
}
},
{
"files": [
"webcomponents/scripts/**",
Expand Down
21 changes: 18 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
- **Config**: config crate (TOML); **File Watching**: notify crate

## Code Style
Aim for functional software development with a focus on stateless, single responsibility focus.
Aim for functional software development with a focus on stateless, single responsibility testable functions.
Minimize use of comments entirely; they should be terse and used judiciously, ideally one line tops.
Data types come from rust; typescript and docs binds are generated from low-level rust types annotated with comments that embed as descriptions into configuration and reference files.
Favor falsey defaults ; lets aim not to enforce `default=true` or some other javascript-truthy default value.
Expand Down Expand Up @@ -45,8 +45,21 @@ make check
cargo fmt --all -- --check # Format check
cargo clippy --locked --all-targets --all-features -- -D warnings # Lint (warnings are errors)
cargo test --locked # Run all tests
make relay # crates/relay (not a workspace member)
make fmt-ts # oxfmt --check, every JS/TS subproject
make lint-ts # oxlint, every JS/TS subproject
make lint-shell # shellcheck -S warning
```

Formatting and linting are enforced for every subproject, not just the main
crate. Rust uses `cargo fmt`/`clippy` (root, `crates/relay`, `opr8r`,
`zed-extension`), JS/TS uses root-installed `oxfmt` + `oxlint` (`ui`,
`webcomponents`, `vscode-extension`, `agnt-plugin`, the `coder-module` test
harness), Terraform uses `terraform fmt`, charts use `helm lint`, and shell
scripts use `shellcheck`. `bun run fmt` rewrites; `bun run fmt:check` reports.
Generated output (`bindings/`, `shared/types.ts`, each `*/generated/`) is
excluded by `.oxfmtrc.json` / `.oxlintrc.jsonc` and must never be reformatted.

> The `--locked --all-targets --all-features` flags matter: plain
> `cargo clippy` misses test-target and feature-gated lints (e.g. a dependency
> deprecation that only surfaces under `--all-targets`), which is how a clippy
Expand Down Expand Up @@ -78,7 +91,7 @@ cargo run

**vscode-extension** (TypeScript/npm):
```bash
cd vscode-extension && npm run lint && npm run compile
cd vscode-extension && npm run lint && npm run fmt:check && npm run compile
```

### Test-Driven Development (TDD)
Expand Down Expand Up @@ -114,7 +127,9 @@ make check
## Quick Reference

```bash
make check # Full CI-parity gate (fmt + clippy + test)
make check # Full CI-parity gate (Rust + relay + JS/TS + shell)
bun run fmt # Format every JS/TS subproject in place
bun run lint # oxlint across every JS/TS subproject
make install-hooks # Install the lint-only pre-push hook (once per clone)
cargo fmt # Format code
cargo clippy --locked --all-targets --all-features -- -D warnings # Lint (CI parity)
Expand Down
8 changes: 2 additions & 6 deletions Dockerfile.local
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# --- Stage 1: embedded web UI ---------------------------------------------
# Cargo.toml sets default = ["embed-ui"], and build.rs silently substitutes a
# placeholder index.html when ui/dist is missing, which would produce an image
# with no dashboard. Building the SPA here is required, not optional.
Expand Down Expand Up @@ -30,10 +29,8 @@ COPY docs/assets/css/ ./docs/assets/css/
COPY ui/ ./ui/
RUN cd ui && bun install --frozen-lockfile && bun run build

# --- Stage 2: Rust binaries -----------------------------------------------
# The full image rather than -slim: rusqlite is features = ["bundled"], so a C
# toolchain is required.
FROM rust:1.95 AS build
# rusqlite is features = ["bundled"], so a C toolchain is required.
FROM rust:1.98 AS build

WORKDIR /src
COPY . .
Expand All @@ -45,7 +42,6 @@ RUN cargo build --release --locked --bin operator
# member, so it needs its own invocation.
RUN cd opr8r && cargo build --release --locked

# --- Stage 3: runtime ------------------------------------------------------
# Mirrors Dockerfile; only the operator/opr8r binary source differs.
# glibc 2.41 >= the ubuntu-24.04 build runners' 2.39, so the GNU binary runs.
FROM debian:trixie-slim@sha256:d7e12182ce18b85b93007c1dedf31f2d29e01ccf3182cc4017c709b6259bc132
Expand Down
28 changes: 26 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
# a clean CI run. `make install-hooks` wires the committed pre-push hook, which
# runs the fast lint gate (fmt + clippy, no tests) before every push.

.PHONY: check fmt clippy test build run install-hooks bindings webcomponents ui docs
.PHONY: check fmt clippy test build run install-hooks bindings webcomponents ui docs \
fmt-ts lint-ts lint-shell relay

# Full CI-parity gate. Keep these commands byte-identical to
# .github/workflows/build.yaml so local and CI never disagree.
check: fmt clippy test
check: fmt clippy test relay fmt-ts lint-ts lint-shell

fmt:
cargo fmt --all -- --check
Expand All @@ -19,6 +20,29 @@ clippy:
test:
cargo test --locked

# crates/relay has its own Cargo.lock and is not a workspace member, so the
# targets above never reach it.
relay:
cd crates/relay && cargo fmt -- --check
cd crates/relay && cargo clippy --locked --all-targets --all-features -- -D warnings
cd crates/relay && cargo test --locked --all-features

# oxfmt/oxlint are installed once at the repo root and cover every hand-written
# JS/TS subproject. `bun run fmt` (no :check) rewrites instead of reporting.
fmt-ts:
bun install --frozen-lockfile
bun run fmt:check

lint-ts:
bun run lint:ui
bun run lint:webcomponents
bun run lint:vscode
bun run lint:agnt
bun run lint:coder-module

lint-shell:
shellcheck -S warning scripts/*.sh scripts/ci/*.sh .githooks/*

# Optimized release binary at target/release/operator.
build:
cargo build --release
Expand Down
2 changes: 1 addition & 1 deletion agnt-plugin/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class AlertTool {
this.name = "operator-alert";
}
async execute(params, _inputData, _workflowEngine) {
if (!params || !params.message) {
if (!params?.message) {
return { success: false, result: null, error: "missing required param: message" };
}
return callOperator({
Expand Down
2 changes: 1 addition & 1 deletion agnt-plugin/create-ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class CreateTicketTool {
this.name = "operator-create-ticket";
}
async execute(params, _inputData, _workflowEngine) {
if (!params || !params.template) {
if (!params?.template) {
return { success: false, result: null, error: "missing required param: template" };
}
return callOperator({
Expand Down
2 changes: 1 addition & 1 deletion agnt-plugin/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ExportWorkflowTool {
this.name = "operator-export-workflow";
}
async execute(params, _inputData, _workflowEngine) {
if (!params || !params.id) {
if (!params?.id) {
return { success: false, result: null, error: "missing required param: id" };
}
const format = params.format || "agnt";
Expand Down
2 changes: 1 addition & 1 deletion agnt-plugin/launch.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class LaunchAgentTool {
this.name = "operator-launch-agent";
}
async execute(params, _inputData, _workflowEngine) {
if (!params || !params.id) {
if (!params?.id) {
return { success: false, result: null, error: "missing required param: id" };
}
return callOperator({
Expand Down
10 changes: 3 additions & 7 deletions agnt-plugin/lib/operator-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ const DEFAULT_BASE_URL = "http://localhost:7008";
* Resolve the Operator REST base URL from params, env, or the default.
*/
export function resolveBaseUrl(params) {
const fromParam = params && params.operatorBaseUrl;
const fromEnv =
typeof process !== "undefined" && process.env
? process.env.OPERATOR_BASE_URL
: undefined;
const fromParam = params?.operatorBaseUrl;
const fromEnv = typeof process === "undefined" ? undefined : process.env?.OPERATOR_BASE_URL;
return (fromParam || fromEnv || DEFAULT_BASE_URL).replace(/\/+$/, "");
}

Expand Down Expand Up @@ -45,8 +42,7 @@ export async function callOperator({ params, path, method = "GET", body }) {
parsed = text;
}
if (!res.ok) {
const detail =
parsed && parsed.error ? parsed.error : `HTTP ${res.status}`;
const detail = parsed?.error ? parsed.error : `HTTP ${res.status}`;
return { success: false, result: parsed, error: `${method} ${url} failed: ${detail}` };
}
return { success: true, result: parsed, error: null };
Expand Down
2 changes: 1 addition & 1 deletion agnt-plugin/run-step.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// Each exported node represents one issuetype step and carries
// { ticket, step, prompt, ... } in its config. This tool reads `ticket` and asks Operator to run it via the launch endpoint.
// Operator sequences its own steps internally, so the per-step nodes are a faithful visualization of the ticket's shape;
// Operator sequences its own steps internally, so the per-step nodes are a faithful visualization of the ticket's shape;
// executing them drives the one underlying Operator ticket (the launch endpoint's relaunch path tolerates a ticket that is already in progress).
import { callOperator } from "./lib/operator-client.js";

Expand Down
3 changes: 3 additions & 0 deletions bindings/GitOnboardingState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

export type GitOnboardingState = "cli-missing" | "token-required" | "authenticated";
4 changes: 4 additions & 0 deletions bindings/GitProviderOnboardingResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { GitOnboardingState } from "./GitOnboardingState";

export type GitProviderOnboardingResponse = { slug: string, label: string, docs_url: string, configured: boolean, command: string, token_env: string, state: GitOnboardingState, action_url: string, username?: string | null, };
3 changes: 3 additions & 0 deletions bindings/HostedCollectionSelection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

export type HostedCollectionSelection = { id: string, checksum: string, };
4 changes: 4 additions & 0 deletions bindings/LaunchConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import type { DockerConfig } from "./DockerConfig";
import type { YoloConfig } from "./YoloConfig";

export type LaunchConfig = { confirm_autonomous: boolean, confirm_paired: boolean, launch_delay_ms: bigint,
/**
* Default named execution target. Per-launch and per-delegator choices take precedence.
*/
target: string | null,
/**
* Docker execution configuration
*/
Expand Down
2 changes: 1 addition & 1 deletion bindings/LaunchConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { SessionWrapper } from "./SessionWrapper";

export type LaunchConfiguration = { confirm_autonomous: boolean, confirm_paired: boolean, launch_delay_ms: bigint, docker_enabled: boolean, docker_image: string, yolo_enabled: boolean, session_wrapper: SessionWrapper, };
export type LaunchConfiguration = { confirm_autonomous: boolean, confirm_paired: boolean, launch_delay_ms: bigint, target: string | null, docker_enabled: boolean, docker_image: string, yolo_enabled: boolean, session_wrapper: SessionWrapper, };
2 changes: 1 addition & 1 deletion bindings/LaunchConfigurationPatch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { SessionWrapper } from "./SessionWrapper";

export type LaunchConfigurationPatch = { confirm_autonomous: boolean | null, confirm_paired: boolean | null, launch_delay_ms: bigint | null, docker_enabled: boolean | null, docker_image: string | null, yolo_enabled: boolean | null, session_wrapper: SessionWrapper | null, };
export type LaunchConfigurationPatch = { confirm_autonomous: boolean | null, confirm_paired: boolean | null, launch_delay_ms: bigint | null, target: string | null, docker_enabled: boolean | null, docker_image: string | null, yolo_enabled: boolean | null, session_wrapper: SessionWrapper | null, };
3 changes: 3 additions & 0 deletions bindings/SetGitSessionEnvRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.

export type SetGitSessionEnvRequest = { provider: string, token: string, };
Loading
Loading