Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
f49ac8d
CS-11034: opencode skeleton + dependencies (foundation only)
jurgenwerk May 5, 2026
60471ff
CS-11034: replace OpenRouter HTTP agent with opencode-driven backend
jurgenwerk May 5, 2026
de3a2af
Merge branch 'retire-structured-update-tools' into cs-11034-software-…
jurgenwerk May 6, 2026
12c100f
realm-server: add /_openrouter/chat/completions passthrough; drop ope…
jurgenwerk May 6, 2026
66bf073
software-factory: drive opencode completion off session.idle events
jurgenwerk May 6, 2026
5166d1d
software-factory: poll session.status to detect opencode loop completion
jurgenwerk May 6, 2026
0d0d24b
software-factory: pass directory + handle session-disappears-on-idle …
jurgenwerk May 6, 2026
d889ce2
software-factory: pass realpath of workspaceDir to opencode
jurgenwerk May 6, 2026
4581fcd
software-factory: detect opencode loop completion via time.updated st…
jurgenwerk May 6, 2026
7bcfbe0
software-factory: race captured signal against time.updated polling
jurgenwerk May 6, 2026
cd1bb7b
software-factory: widen idle stability + free port 4096 between itera…
jurgenwerk May 6, 2026
453bb7a
software-factory: SIGKILL stale opencode process holding port 4096
jurgenwerk May 6, 2026
e9a53ca
software-factory: tell opus to actually call Write; retry flaky promp…
jurgenwerk May 6, 2026
e37b400
software-factory: keep factory:go alive when opencode dies mid-iteration
jurgenwerk May 6, 2026
d47060b
software-factory: long-lived opencode subprocess across iterations
jurgenwerk May 6, 2026
14a2abc
realm-server: fix SSE line-buffer bug that duplicated every streamed …
jurgenwerk May 6, 2026
45ab9c7
software-factory: surface live progress during opencode runs
jurgenwerk May 6, 2026
600d861
software-factory: trim opencode tool catalog to what the factory needs
jurgenwerk May 6, 2026
9be9d4f
software-factory: stop telling the model to call retired tools; log w…
jurgenwerk May 6, 2026
84fec46
software-factory: pass issue description + acceptance criteria into a…
jurgenwerk May 6, 2026
1ba34a5
software-factory: chdir to workspace before spawning opencode subprocess
jurgenwerk May 6, 2026
d8e78fc
software-factory: force schema fetch + concrete containsMany serializ…
jurgenwerk May 6, 2026
b5308f8
software-factory: add OPENCODE_PERFORMANCE doc explaining why factory…
jurgenwerk May 6, 2026
cadff85
realm-server: instrument openrouter passthrough + factory:stats CLI
jurgenwerk May 7, 2026
4e93de1
software-factory: unwrap fetch errors in opencode logs, drop --debug …
jurgenwerk May 7, 2026
6298d07
software-factory: sync workspace before run_evaluate / run_instantiate
jurgenwerk May 7, 2026
6e1bf13
software-factory: sync workspace after marking project completed
jurgenwerk May 7, 2026
e60efa9
Merge branch 'main' into cs-11034-software-factory-replace-openrouter…
jurgenwerk May 7, 2026
263f50a
software-factory: drop OPENCODE_PERFORMANCE.md
jurgenwerk May 7, 2026
866d41c
realm-server + software-factory: drop instrumentation scaffolding
jurgenwerk May 7, 2026
9f8a43c
software-factory + realm-server: prune historical narrative comments
jurgenwerk May 7, 2026
ea7350e
pnpm-workspace: drop opencode minimumReleaseAge exclusions
jurgenwerk May 7, 2026
1fe459e
software-factory: drop redundant containsMany guidance
jurgenwerk May 7, 2026
19a7c56
software-factory + realm-server: address Copilot review on PR #4653
jurgenwerk May 7, 2026
abd61cb
software-factory: fix CI test failures from main merge / Copilot fixes
jurgenwerk May 7, 2026
4384ad3
Merge branch 'fix-sf-atomic-mock-waitforindex' into cs-11034-software…
jurgenwerk May 7, 2026
07e4832
software-factory: pass invalid OpenRouter key in target-realm e2e test
jurgenwerk May 8, 2026
7430677
software-factory: trim opencode.ts (-81 lines)
jurgenwerk May 8, 2026
cd37c94
software-factory: propagate opencode session.error as agent block
jurgenwerk May 8, 2026
cf0ac85
software-factory: honor agent-blocked status in issue loop
jurgenwerk May 8, 2026
305e1cf
software-factory: expect 'blocked' seed issue in target-realm e2e test
jurgenwerk May 8, 2026
4c5a5e3
boxel-cli: re-mint realm-server JWT when within 1 day of expiry
jurgenwerk May 8, 2026
916c4ae
software-factory: bound post-race drain in opencode session run
jurgenwerk May 8, 2026
9075c9f
ci: trigger fresh run after cancelled prerender-pool flake
jurgenwerk May 8, 2026
e083d9d
Merge branch 'main' into cs-11034-software-factory-replace-openrouter…
jurgenwerk May 8, 2026
3afc8c1
boxel-cli: strip 'Bearer ' before decoding cached realm-server JWT
jurgenwerk May 8, 2026
840df1f
software-factory: keep the agent on-task and surface failures clearly
jurgenwerk May 11, 2026
f632190
software-factory: align always-loaded skill references with current t…
jurgenwerk May 11, 2026
ce931df
software-factory: drop dead exports + refresh stale historical comments
jurgenwerk May 11, 2026
4d1ec42
Merge pull request #4753 from cardstack/cs-10613-align-skill-loading
jurgenwerk May 12, 2026
08a6d1c
Merge branch 'main' into cs-11034-software-factory-replace-openrouter…
jurgenwerk May 12, 2026
cbbceac
boxel-cli: regenerate plugin/skills/realm-sync synopsis after merge
jurgenwerk May 12, 2026
9cfd7a6
boxel-cli: bump plugin version 0.1.1 → 0.1.2 after synopsis regen
jurgenwerk May 12, 2026
5713320
boxel-cli: add boxel-api skill; retire dev-realm-search.md from factory
jurgenwerk May 11, 2026
82aafc7
skills: relocate skill files; rewrite software-factory-operations + d…
jurgenwerk May 11, 2026
f046f2a
software-factory: fix prettier formatting in software-factory-operati…
jurgenwerk May 11, 2026
0920f47
software-factory: address PR #4756 review comments
jurgenwerk May 11, 2026
ee6a905
boxel-cli: trim realm-creation/readiness from boxel-api skill
jurgenwerk May 11, 2026
49c04ba
skills: delete CLI skills documenting commands not in this codebase
jurgenwerk May 11, 2026
f2bd0c5
software-factory: replace stale CLAUDE.md/AGENTS.md with current docs
jurgenwerk May 11, 2026
469e7bf
boxel-cli: move boxel-api + boxel-command into plugin/skills
jurgenwerk May 12, 2026
efe6a1f
skills: drop duplicate boxel-file-structure from root .agents/skills
jurgenwerk May 12, 2026
cccbac7
Merge pull request #4756 from cardstack/cs-10666-create-boxel-api-skill
jurgenwerk May 12, 2026
d8fc38b
software-factory: standardize on "issue" terminology, drop "ticket"
jurgenwerk May 12, 2026
e886cc4
Merge branch 'main' into cs-11034-software-factory-replace-openrouter…
jurgenwerk May 12, 2026
5b99722
boxel-cli: drop misleading 'search' from `boxel file` description
jurgenwerk May 12, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Add `data-test-*` attributes to card templates for stable test selectors:

When tests fail, the orchestrator feeds test failure details back to the agent. For more detail:

- **TestRun cards** live in the target realm's `Validations/` folder with a `test_` prefix (e.g., `Validations/test_issue-slug-1.json`). To find all test runs, search by the TestRun card type in the target realm. Each TestRun has a `sequenceNumber` that increases with each iteration. Use `read_file` on a specific TestRun for full details.
- **TestRun cards** live in the target realm's `Validations/` folder with a `test_` prefix (e.g., `Validations/test_issue-slug-1.json`). To find all test runs, run `Glob` over `Validations/test_*.json` or shell out via `Bash` to `boxel search --realm <url>` filtered on the TestRun card type. Each TestRun has a `sequenceNumber` that increases with each iteration. Use native `Read` on a specific TestRun for full details — paths are workspace-relative.

## Rules

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
# Catalog Spec Card Instances

For each top-level card definition, create a Catalog Spec card instance in the target realm's `Spec/` folder using the `create_catalog_spec` tool. This makes the card discoverable in the Boxel catalog.
For each top-level card definition, write a Catalog Spec card instance in the target realm's `Spec/` folder. This makes the card discoverable in the Boxel catalog.

The `create_catalog_spec` tool has the authoritative JSON schema for Spec card fields — use its parameter definitions to know which attributes and relationships are available. The tool auto-constructs the document with the correct `adoptsFrom` (`https://cardstack.com/base/spec#Spec`).
Specs adopt from the `Spec` class exported by `https://cardstack.com/base/spec` — that module lives in the base realm, not your target realm. Fetch the authoritative schema by calling the `get_card_schema` factory tool:

## Usage
```
get_card_schema({ module: 'https://cardstack.com/base/spec', name: 'Spec' })
```

Use the `create_catalog_spec` tool to create a Spec card. The tool's parameters define the available fields dynamically from the card definition — consult the tool schema for the exact field names and types.
The result gives you the exact `attributes` and `relationships` shape. Write the JSON file with native `Write` (paths are workspace-relative, e.g. `Spec/sticky-note.json`); `boxel sync` pushes it to the realm between iterations.

## Required Shape

```json
{
"data": {
"type": "card",
"attributes": {
"specType": "card",
"ref": { "module": "../sticky-note", "name": "StickyNote" },
"readMe": "...",
"cardInfo": { "name": "Sticky Note", "summary": "..." }
},
"relationships": {
"linkedExamples.0": { "links": { "self": "../StickyNote/welcome-note" } }
},
"meta": {
"adoptsFrom": {
"module": "https://cardstack.com/base/spec",
"name": "Spec"
}
}
}
}
```

Key concepts:

- `ref` — a CodeRef pointing to the card definition (module path + exported class name). The module path is relative from the Spec card to the `.gts` file (e.g., `../sticky-note` from `Spec/sticky-note.json`).
- `specType` — `"card"` for CardDef, `"field"` for FieldDef, `"component"` for standalone components.
- `linkedExamples` — a relationship pointing to sample card instances. Create at least one sample instance and link it here.
- `linkedExamples` — a `linksToMany` relationship pointing to sample card instances. Use dotted keys (`linkedExamples.0`, `linkedExamples.1`, …) — the array form is rejected by the indexer. Create at least one sample instance and link it here.
- **Do NOT call `run_instantiate` on the Spec file itself.** Spec's module lives in the base realm; the prerender enforces same-origin module loads and the call always fails. To validate Specs, call `run_instantiate` WITHOUT a `path`; it discovers Specs in the target realm and exercises their `linkedExamples` against the card classes you wrote.

## Sample Card Instances

Create at least one sample instance with realistic data for each top-level card. Sample instances serve as both catalog examples and test fixtures.

Place sample instances in a folder named after the card type (e.g., `StickyNote/welcome-note.json`). Use `write_file` to create them. The `linkedExamples` relationship in the Spec card points to these using a relative path (e.g., `../StickyNote/welcome-note`).
Place sample instances in a folder named after the card type (e.g., `StickyNote/welcome-note.json`) and write them with native `Write`. The `linkedExamples` relationship in the Spec card points to these using a relative path without the `.json` suffix (e.g., `../StickyNote/welcome-note`).

---

Expand Down
2 changes: 1 addition & 1 deletion packages/boxel-cli/plugin/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "boxel-cli",
"description": "Claude Code skills for working with Boxel realms via @cardstack/boxel-cli. Requires @cardstack/boxel-cli >= 0.0.1 installed on PATH (npm install -g @cardstack/boxel-cli).",
"version": "0.1.1",
"version": "0.1.3",
"author": {
"name": "Cardstack",
"url": "https://boxel.ai"
Expand Down
182 changes: 182 additions & 0 deletions packages/boxel-cli/plugin/skills/boxel-api/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
name: boxel-api
description: Use when calling Boxel realm-server APIs from code — primarily federated search across realms. Documents the boxel-cli programmatic surface (`BoxelCLIClient`) and the matching CLI commands. Read this whenever you need to query a realm's index.
---

# Boxel API

Canonical home for Boxel platform API knowledge.

**Architectural principle:** boxel-cli owns the entire Boxel API surface. Any code that talks to the realm server or Matrix lives in boxel-cli; consumers (the software-factory, custom scripts, hand-written tools) import `BoxelCLIClient` from `@cardstack/boxel-cli/api` and call its methods. Auth (tokens, refresh, retries) is fully internal — if you're holding a JWT or calling `fetch` against a realm URL directly, you're in the wrong layer.

```ts
import { BoxelCLIClient } from '@cardstack/boxel-cli/api';

let client = new BoxelCLIClient(); // reads the active Boxel profile
```

All examples below assume `client` is a `BoxelCLIClient` instance.

## Federated search

Search across one or more realms via `/_federated-search`. Query syntax matches the Boxel realm search format.

### CLI

```
boxel search --realm <realm-url> [--realm <realm-url>...] --query '<json>'
```

`--realm` is repeatable. `--query` takes a JSON string. Append `--json` for raw output.

### Programmatic

```ts
let result = await client.search(realmUrl, query); // single realm
let result = await client.search([realmA, realmB], query); // federated
```

Returns `{ ok, status, data?, error? }`. `data` is an array of card resources.

### Query syntax

```json
{
"filter": { ... },
"sort": [ ... ],
"page": { "size": 10 }
}
```

All top-level fields are optional. An empty query `{}` returns all cards in the targeted realms.

#### Filter by card type

```json
{
"filter": {
"type": {
"module": "http://localhost:4201/software-factory/darkfactory",
"name": "Project"
}
}
}
```

Returns all cards that adopt from (or extend) the specified type. Wildcards (`*`) in `module` or `name` are **not** supported — always use a specific CodeRef.

#### Filter by field value (`eq`)

`eq` requires an `on` to scope the field to a card type:

```json
{
"filter": {
"on": { "module": "...", "name": "Issue" },
"eq": { "status": "in_progress" }
}
}
```

Multiple fields in `eq` are ANDed. Use dot paths for nested fields (e.g. `"author.firstName": "Carl"`). Use `null` to match empty/missing fields.

#### Substring search (`contains`)

Case-insensitive substring match:

```json
{ "filter": { "contains": { "cardTitle": "sticky" } } }
```

Scoped form same as `eq` (`on` + `contains`).

#### Range filters

```json
{
"filter": {
"on": { "module": "...", "name": "Post" },
"range": { "views": { "lte": 10, "gt": 5 } }
}
}
```

Operators: `gt`, `gte`, `lt`, `lte`. Works on numeric, date, and string fields.

#### Boolean combinators

```json
// AND
{ "filter": { "on": {...}, "every": [ {...}, {...} ] } }

// OR
{ "filter": { "any": [ {...}, {...} ] } }

// NOT
{ "filter": { "on": {...}, "not": { "eq": { ... } } } }
```

#### Sort

```json
{
"sort": [
{ "by": "author.lastName", "on": { "module": "...", "name": "Article" } }
],
"filter": { "type": { "module": "...", "name": "Article" } }
}
```

Add `"direction": "desc"` for descending.

#### Pagination

```json
{ "filter": {...}, "page": { "size": 10 } }
```

#### CodeRef field matching

CodeRef fields (e.g. `ref` on a Spec card) are matched against the full `{ module, name }`:

```json
{
"filter": {
"on": { "module": "https://cardstack.com/base/spec", "name": "Spec" },
"eq": {
"ref": {
"module": "http://localhost:4201/my-realm/sticky-note",
"name": "StickyNote"
}
}
}
}
```

### Common mistakes

- **Field names without `on`.** Fields like `title`, `status`, etc. are type-specific. The exceptions are `cardTitle` and `cardDescription` — those exist on the base `CardDef`.
- **Relative or bare module URLs.** Always use full absolute module URLs in CodeRefs.
- **Slash separators in dotted paths.** Use `author.firstName`, not `author/firstName`.
- **Searching relationships that aren't rendered in an embedded/fitted template.** The query engine indexes a linked field only if it appears in an embedded format. Otherwise the filter silently misses.

## When to use what

| Goal | Use |
| -------------------------------------------------------- | ------------------------------------------------------------------ |
| Find cards in your local synced workspace | Native `grep` / `find` — files are already on disk |
| Find cards by type / field across one or more realms | `boxel search` / `client.search` |
| Read a single card's source from a realm | `client.read(realmUrl, path)` / `boxel file read` |
| Read the transpiled (browser) version of a `.gts` module | `client.readTranspiled(...)` / `boxel read-transpiled` |
| List files in a realm | `client.listFiles(realmUrl)` / `boxel file list` |
| Push local changes to a realm | `client.sync(realmUrl, dir, { preferLocal: true })` / `boxel sync` |
| Pull a realm's state to a local dir | `client.pull(realmUrl, dir)` / `boxel pull` |
| Run a host command (prerendered) | See the `boxel-command` skill |

## What this skill is **not** for

- **Card development patterns** (`.gts` field declarations, templates, `linksTo` vs `contains`) — that's `boxel-development`.
- **JSON:API document structure** for card instances — that's `boxel-file-structure`.
- **Sync / pull / track / watch CLI ergonomics** — those have their own per-command skills (`boxel-sync`, `boxel-track`, `boxel-watch`).
- **Host commands via the prerenderer** (`/_run-command`) — that's the `boxel-command` skill.
- **Realm provisioning** (`createRealm` / `boxel realm create`) and **readiness polling** (`client.waitForReady` / `/_readiness-check`) — orchestration concerns. The software-factory creates target realms in `factory-target-realm.ts` before the agent loop starts; consumers needing those APIs should read `boxel-cli/src/api.ts` directly or run `boxel realm create --help`.
71 changes: 71 additions & 0 deletions packages/boxel-cli/plugin/skills/boxel-command/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
name: boxel-command
description: Use when running a Boxel host command via the realm server's prerenderer — invoking commands like `get-card-type-schema`, `evaluate-module`, `instantiate-card`, or any other module exposed at `@cardstack/boxel-host/commands/.../default`. Documents `boxel run-command` and the matching `client.runCommand()` method.
---

# Boxel Host Commands

Some Boxel operations only exist inside the host app's prerendered runtime — there's no realm-server HTTP endpoint for them, and they can't be reimplemented in plain Node. The realm server's `/_run-command` endpoint forwards a job to the prerenderer (a headless Chrome instance that has the full host runtime loaded), executes the named command there, and returns the serialized result. Schema introspection, module evaluation, card instantiation, transpiled-module fetches — all of these go through `run-command`.

This skill documents how to invoke that flow.

## When to use it

- **Card type schema lookup.** Get the live `{ attributes, relationships }` JSON Schema for a `CardDef` by introspecting its real class at runtime — not by reading the `.gts` source.
- **Module evaluation.** Load a `.gts` / `.ts` module in the prerender sandbox to surface broken imports, circular references, or top-level runtime errors before they hit a real consumer.
- **Card instantiation.** Construct a card instance from a JSON document inside the prerender — exercises the `CardDef` class against the document shape.
- **Anything else exposed at `@cardstack/boxel-host/commands/<name>/default`.** Each module is its own host command.

## CLI

```
boxel run-command <command-specifier> --realm <realm-url> [--input '<json>'] [--json]
```

- `<command-specifier>` — the module path of the command (e.g. `@cardstack/boxel-host/commands/get-card-type-schema/default`).
- `--realm` — the realm URL the command runs against. Required.
- `--input` — JSON string passed as the command's input. Optional; some commands take no input.
- `--json` — emit the raw response instead of the formatted summary.

### Example

```
boxel run-command @cardstack/boxel-host/commands/get-card-type-schema/default \
--realm http://localhost:4201/my-realm/ \
--input '{"codeRef":{"module":"http://localhost:4201/my-realm/sticky-note","name":"StickyNote"}}'
```

## Programmatic

```ts
import { BoxelCLIClient } from '@cardstack/boxel-cli/api';

let client = new BoxelCLIClient();

let result = await client.runCommand(
realmServerUrl,
realmUrl,
'@cardstack/boxel-host/commands/get-card-type-schema/default',
{ codeRef: { module: '<absolute-module-url>', name: 'StickyNote' } },
);
```

Returns `{ status: 'ready' | 'error' | 'unusable', result?: string | null, error?: string | null }`. `result` is the command's serialized output (a JSON string — parse it yourself). `error` is set when `status !== 'ready'`.

## How it works under the hood

`/_run-command` enqueues a job for the realm worker. The worker hands it to the prerenderer (which has the host app, the realm's Loader, the CardAPI, and all field serializers loaded). The command module is imported, called with the input, and its result is serialized back through the queue to the HTTP response.

Three failure modes you'll see:

- `status: 'unusable'` — the prerender pool is broken (e.g. "No standby page available for prerender"). Not retryable from the caller's side; usually a sign the realm-server worker / prerender pool itself is unhealthy.
- `status: 'error'` with `error: "module URL not found"` — the realm's in-memory module map hasn't indexed the file yet. Common right after a `/_atomic` write; caller can retry briefly or use `client.sync(..., { waitForIndex: true })` upstream.
- `status: 'error'` with any other message — the command threw inside the prerender. The `error` is the thrown error's message; the original stack is usually in the worker logs.

The realm server itself enforces auth (server JWT via `BoxelCLIClient`); the prerender executes inside the realm's sandbox with the realm's permissions.

## What this skill is **not** for

- **Realm-side HTTP endpoints** (search, file read/write, atomic batches) — those are direct `BoxelCLIClient` methods. See the `boxel-api` skill.
- **Programmatic in-memory validators** (`runLintInMemory`, `runEvaluateInMemory`, `runParseInMemory`, `runInstantiateInMemory`) — those wrap `runCommand` internally but expose a flatter result shape; consumers usually want those, not raw `runCommand`. They live in the software-factory package.
- **Defining new host commands.** That's host-app development (`packages/host/app/commands/`).
15 changes: 2 additions & 13 deletions packages/boxel-cli/plugin/skills/realm-sync/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,9 @@ Bidirectional sync between a local directory and a Boxel realm
- `--dry-run` — Preview without making changes
- `--realm-secret-seed` — Administrative auth: prompt for a realm secret seed and mint a JWT locally instead of using a Matrix profile (env: BOXEL_REALM_SECRET_SEED)

### `boxel realm watch <realm-url> <local-dir>`
### `boxel realm watch`

Watch a Boxel realm for server-side changes and pull them into a local directory

**Arguments:**

- `<realm-url>` — The URL of the realm to watch (e.g., https://app.boxel.ai/demo/)
- `<local-dir>` — The local directory to write changes into

**Options:**

- `-i, --interval <seconds>` — Polling interval in seconds
- `-d, --debounce <seconds>` — Seconds to wait after a burst of changes before applying them
- `--realm-secret-seed` — Administrative auth: prompt for a realm secret seed and mint a JWT locally instead of using a Matrix profile (env: BOXEL_REALM_SECRET_SEED)
Watch a Boxel realm; subcommands manage watch processes

### `boxel realm push <local-dir> <realm-url>`

Expand Down
2 changes: 1 addition & 1 deletion packages/boxel-cli/src/commands/file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { registerWriteCommand } from './write';
export function registerFileCommand(program: Command): void {
let file = program
.command('file')
.description('Read, write, search, and manage files in a realm');
.description('Read, write, and manage files in a realm');

registerDeleteCommand(file);
registerListCommand(file);
Expand Down
12 changes: 12 additions & 0 deletions packages/boxel-cli/src/lib/boxel-cli-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,18 @@ export class BoxelCLIClient {
return this.pm.authedRealmServerFetch(input, init);
}

/**
* Return the realm-server JWT, fetching one via Matrix login if no token
* is cached. Use only when you need to hand the bare token to a downstream
* client that can't go through `authedServerFetch` (e.g. opencode's
* static-Authorization provider config). Prefer `authedServerFetch` for
* server endpoints called from JS — it handles per-request 401 retries
* that this getter cannot.
*/
async getServerToken(): Promise<string> {
return this.pm.getOrRefreshServerToken();
}

async pull(
realmUrl: string,
localDir: string,
Expand Down
Loading
Loading