# @asciidev/box-sdk

> **Box is now Boat.** This package is the last release of the box SDK line. It keeps
> working against the frozen `/api/box/v1` endpoints until their sunset (see the
> `Sunset` response header), but gets no new features. Migrate to the boat SDK:
> https://docs.boat.dev/migrating-from-box

Use Box from your application code.

## Install

```bash
npm install @asciidev/box-sdk
```

## Links

- SDK docs: https://docs.boat.dev/box/sdks
- API reference: https://docs.boat.dev/box/api/reference
- Dashboard: https://box.ascii.dev/dashboard
- API keys: https://box.ascii.dev/box/dashboard?tab=api-keys

## Flow

1. Create an API key in the Box dashboard.
2. Create or resume a Box.
3. Prompt the Box.
4. Read events until the work is done.
5. Open desktop access when you need browser or GUI visibility.
6. Stop, resume, fork, or delete the Box according to your retention policy.

## Notes

- Put cleanup in `finally`: stop/archive or delete Boxes you create for tests.
- Treat API key secrets, Box secrets, SSH keys, and desktop stream URLs as sensitive.
- `updateSecrets` / `update_secrets` replaces the entire secret setup. Read the current setup first and send every env var and secret file that should remain.
- `rotateApiKey` / `rotate_api_key` rotates the raw secret in place. Store the returned secret immediately; it is shown once.
- Repository selection is idempotent. Selecting an already-selected repository updates its base branch.

## Example

### TypeScript

```ts
import { BoxApi, Configuration } from "@asciidev/box-sdk";

const box = new BoxApi(new Configuration({
  basePath: process.env.BOX_BASE_URL ?? "https://ascii.dev/api/box/v1",
  accessToken: process.env.BOX_API_KEY ?? (() => {
    throw new Error("Set BOX_API_KEY from the Box dashboard API keys tab.");
  })(),
}));

async function main() {
  let boxId: string | undefined;

  try {
    const created = await box.create({
      createBoxRequest: {
        ttlSeconds: 1800,
      },
    });

    boxId = created.box.id;

    await box.update({
      boxId,
      updateBoxRequest: { name: "sdk-demo" },
    });

    while (!["ready", "idle"].includes((await box.get({ boxId })).box.state)) {
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }

    await box.prompt({
      boxId,
      promptRequest: {
        prompt: "Inspect the repository and summarize the test command.",
        provider: "codex",
      },
    });

    const events = await box.events({ boxId });
    console.log(events.events);
  } finally {
    if (boxId) {
      await box.stop({ boxId });
    }
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

### JavaScript

```js
const { BoxApi, Configuration } = require("@asciidev/box-sdk");

const box = new BoxApi(new Configuration({
  basePath: process.env.BOX_BASE_URL || "https://ascii.dev/api/box/v1",
  accessToken: process.env.BOX_API_KEY || (() => {
    throw new Error("Set BOX_API_KEY from the Box dashboard API keys tab.");
  })(),
}));

async function main() {
  let boxId;

  try {
    const created = await box.create({
      createBoxRequest: {
        ttlSeconds: 1800,
      },
    });

    boxId = created.box.id;

    await box.update({
      boxId,
      updateBoxRequest: { name: "sdk-demo" },
    });

    while (!["ready", "idle"].includes((await box.get({ boxId })).box.state)) {
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }

    await box.prompt({
      boxId,
      promptRequest: {
        prompt: "Inspect the repository and summarize the test command.",
        provider: "codex",
      },
    });

    const events = await box.events({ boxId });
    console.log(events.events);
  } finally {
    if (boxId) {
      await box.stop({ boxId });
    }
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

## License

This SDK is MIT licensed. Box, the Box API, the Box CLI, and the Box product are proprietary.
