@opencomputer/blue 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +287 -0
- package/dist/auth/cli-auth.d.ts +30 -0
- package/dist/auth/cli-auth.js +206 -0
- package/dist/auth/cli-auth.js.map +1 -0
- package/dist/channels/slack-progress.d.ts +27 -0
- package/dist/channels/slack-progress.js +149 -0
- package/dist/channels/slack-progress.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +790 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/agent.d.ts +10 -0
- package/dist/core/agent.js +112 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/artifact.d.ts +7 -0
- package/dist/core/artifact.js +46 -0
- package/dist/core/artifact.js.map +1 -0
- package/dist/dev/local-control-plane.d.ts +11 -0
- package/dist/dev/local-control-plane.js +639 -0
- package/dist/dev/local-control-plane.js.map +1 -0
- package/dist/dev/manager.d.ts +35 -0
- package/dist/dev/manager.js +589 -0
- package/dist/dev/manager.js.map +1 -0
- package/dist/openrouter/auth.d.ts +2 -0
- package/dist/openrouter/auth.js +144 -0
- package/dist/openrouter/auth.js.map +1 -0
- package/dist/protocol.d.ts +187 -0
- package/dist/protocol.js +14 -0
- package/dist/protocol.js.map +1 -0
- package/dist/runtime/harness.d.ts +30 -0
- package/dist/runtime/harness.js +370 -0
- package/dist/runtime/harness.js.map +1 -0
- package/dist/runtime/local-runtime.d.ts +2 -0
- package/dist/runtime/local-runtime.js +161 -0
- package/dist/runtime/local-runtime.js.map +1 -0
- package/dist/sdk/client.d.ts +28 -0
- package/dist/sdk/client.js +131 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.js +3 -0
- package/dist/sdk/index.js.map +1 -0
- package/package.json +95 -0
package/README.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Blue
|
|
2
|
+
|
|
3
|
+
Blue is an early framework for authoring OpenCode agents locally and running
|
|
4
|
+
the same session protocol against Lambda MicroVM deployments. Its control
|
|
5
|
+
plane is a Cloudflare Worker with one SQLite-backed Durable Object per session.
|
|
6
|
+
|
|
7
|
+
This repository ships the local framework and the authenticated hosted
|
|
8
|
+
control-plane contract:
|
|
9
|
+
|
|
10
|
+
- an Eve-style agent layout under `examples/hello-agent`;
|
|
11
|
+
- a `blue` CLI and TypeScript client SDK;
|
|
12
|
+
- an OpenCode adapter plus a credential-free mock harness;
|
|
13
|
+
- durable sessions, FIFO turns, idempotency, event replay, runtime fencing,
|
|
14
|
+
and hibernating WebSockets;
|
|
15
|
+
- WorkOS device authentication for the hosted CLI;
|
|
16
|
+
- a Blue model gateway that keeps the platform OpenRouter key server-side;
|
|
17
|
+
- sub-second content-addressed agent artifacts on a generic Lambda MicroVM
|
|
18
|
+
runtime image;
|
|
19
|
+
- an AccountDO registry for agents, immutable deployments, and aliases;
|
|
20
|
+
- one S3 Files access point and mounted workspace per deployed session;
|
|
21
|
+
- platform-only AWS adapters for S3, S3 Files, networking, and MicroVMs;
|
|
22
|
+
- Cloudflare Workers integration tests.
|
|
23
|
+
|
|
24
|
+
## Try It
|
|
25
|
+
|
|
26
|
+
Run Blue directly from npm with Node.js 22 or newer:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx -y @opencomputer/blue@latest login
|
|
30
|
+
npx -y @opencomputer/blue@latest whoami
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Install it globally for the shorter command:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install --global @opencomputer/blue
|
|
37
|
+
blue login
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
To work from this repository:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install
|
|
44
|
+
npm test
|
|
45
|
+
npm run blue -- demo "hello Blue" --agent-dir examples/hello-agent
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The demo starts Blue's embedded Node control plane, creates a session, attaches
|
|
49
|
+
a local runtime, runs one turn, streams the result, and shuts down. It uses the
|
|
50
|
+
mock harness by default. Wrangler is not involved.
|
|
51
|
+
|
|
52
|
+
Create a new agent with:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm run blue -- init my-agent
|
|
56
|
+
npm run blue -- demo "hello" --agent-dir my-agent
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Blue compiles `agent/instructions.md`, skills, and the seeded sandbox workspace
|
|
60
|
+
into `.blue/runtime/`, which is the directory passed to OpenCode.
|
|
61
|
+
|
|
62
|
+
Log in once to use the hosted service and its OpenRouter gateway:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
blue login
|
|
66
|
+
blue whoami
|
|
67
|
+
cd examples/hello-agent
|
|
68
|
+
blue dev
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
WorkOS opens a browser-based device confirmation at the configured AuthKit
|
|
72
|
+
domain. The CLI stores rotating access and refresh tokens in
|
|
73
|
+
`~/.config/blue/credentials.json` with mode `0600`. The platform OpenRouter key
|
|
74
|
+
never reaches the developer's machine: `blue dev` proxies local OpenCode model
|
|
75
|
+
requests through the authenticated Blue API. `blue auth openrouter` remains an
|
|
76
|
+
optional user-owned OpenRouter fallback.
|
|
77
|
+
|
|
78
|
+
Start local development from an agent:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cd examples/hello-agent
|
|
82
|
+
blue dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`blue dev` starts a self-contained local HTTP/WebSocket control plane, runtime
|
|
86
|
+
manager, OpenCode processes, and configured channels. It has no Wrangler,
|
|
87
|
+
Cloudflare account, Docker, or AWS dependency. Session state and authenticated
|
|
88
|
+
discovery metadata live under `.blue/dev/`; ports are selected automatically
|
|
89
|
+
unless `--port` or `--manager-port` is provided. Each session also receives an
|
|
90
|
+
isolated OpenCode database, so concurrent CLI and Slack sessions do not contend
|
|
91
|
+
for OpenCode's global database.
|
|
92
|
+
|
|
93
|
+
In another terminal, run a one-shot prompt from anywhere inside that agent
|
|
94
|
+
repository:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
blue session "inspect the workspace and summarize it"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Omit the prompt for an interactive, multi-turn session:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
blue session
|
|
104
|
+
blue session send <session-id> "now make the change"
|
|
105
|
+
blue session inspect <session-id>
|
|
106
|
+
blue session list
|
|
107
|
+
blue session end <session-id>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`blue session create` remains an explicit alias. The CLI automatically selects
|
|
111
|
+
the live development server discovered from the repository. Use `--remote` to
|
|
112
|
+
target the authenticated Blue service instead.
|
|
113
|
+
|
|
114
|
+
When running this repository directly, substitute
|
|
115
|
+
`../../node_modules/.bin/tsx ../../src/cli/index.ts` for `blue`. The installed
|
|
116
|
+
package exposes the shorter `blue` binary.
|
|
117
|
+
|
|
118
|
+
### Local Slack
|
|
119
|
+
|
|
120
|
+
Add the declarative Slack channel to an agent:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
blue channels add slack
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
For local development, Socket Mode is the shortest path:
|
|
127
|
+
|
|
128
|
+
```env
|
|
129
|
+
SLACK_APP_TOKEN=xapp-...
|
|
130
|
+
SLACK_BOT_TOKEN=xoxb-...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Restart `blue dev`; it prints `slack: Socket Mode connected`. No request URL or
|
|
134
|
+
tunnel is required. Subscribe the app to `app_mention` and grant
|
|
135
|
+
`app_mentions:read` plus `chat:write`.
|
|
136
|
+
|
|
137
|
+
Blue immediately shows Slack's native loading indicator, rotates startup
|
|
138
|
+
messages, and updates the status with reasoning and tool activity. The final
|
|
139
|
+
reply clears the indicator automatically. Each Slack thread maps to one
|
|
140
|
+
persistent local Blue session, with the mapping stored under `.blue/dev/`.
|
|
141
|
+
|
|
142
|
+
The HTTP Events API remains available as a fallback. Set
|
|
143
|
+
`SLACK_SIGNING_SECRET` and `SLACK_BOT_TOKEN`, expose the webhook printed by
|
|
144
|
+
`blue dev`, and configure it as the Slack app's Events API request URL.
|
|
145
|
+
|
|
146
|
+
Deployed Slack delivery is not wired yet. The intended Events API route is
|
|
147
|
+
agent-specific and owned by the hosted Blue service.
|
|
148
|
+
|
|
149
|
+
## Hosted Flow
|
|
150
|
+
|
|
151
|
+
End users need only the Blue CLI and a browser:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
blue login
|
|
155
|
+
blue whoami
|
|
156
|
+
blue agents list
|
|
157
|
+
blue deploy --alias production
|
|
158
|
+
blue session create "summarize the workspace"
|
|
159
|
+
blue session send <session-id> "now make the change"
|
|
160
|
+
blue session list
|
|
161
|
+
blue session end <session-id>
|
|
162
|
+
blue logout
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The CLI defaults to `https://blue.opencomputer.dev`; `BLUE_API_URL` or
|
|
166
|
+
`--api-url` selects another Blue installation. The logged-in WorkOS
|
|
167
|
+
organization, or the user ID when no organization is selected, is the account
|
|
168
|
+
boundary for agents, deployments, and sessions.
|
|
169
|
+
|
|
170
|
+
`blue deploy` builds the immutable agent artifact locally, requests a
|
|
171
|
+
platform-owned upload, uploads directly to the returned signed URL, and
|
|
172
|
+
registers the deployment. Session create, resume, suspend, and terminate call
|
|
173
|
+
the Blue runtime service. The user machine does not require AWS credentials.
|
|
174
|
+
|
|
175
|
+
### Service configuration
|
|
176
|
+
|
|
177
|
+
The hosted Worker requires:
|
|
178
|
+
|
|
179
|
+
- `BLUE_WORKOS_CLIENT_ID` and optionally `BLUE_WORKOS_ISSUER` /
|
|
180
|
+
`BLUE_WORKOS_JWKS_URL`;
|
|
181
|
+
- `OPENROUTER_API_KEY` as a Worker secret;
|
|
182
|
+
- `BLUE_RUNTIME_IMAGE_ARN` and `BLUE_RUNTIME_IMAGE_VERSION`;
|
|
183
|
+
- a `DEPLOYMENTS` service binding that returns signed platform artifact
|
|
184
|
+
uploads;
|
|
185
|
+
- a `RUNTIMES` service binding that owns Lambda MicroVM and S3 Files lifecycle.
|
|
186
|
+
|
|
187
|
+
Recommended domains are `blue.opencomputer.dev` for the API/dashboard and
|
|
188
|
+
`auth.blue.opencomputer.dev` for the WorkOS AuthKit domain. Enable CLI Auth in
|
|
189
|
+
the WorkOS application, then configure the Worker:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npx wrangler secret put BLUE_WORKOS_CLIENT_ID \
|
|
193
|
+
--config wrangler.production.jsonc
|
|
194
|
+
npx wrangler secret put OPENROUTER_API_KEY \
|
|
195
|
+
--config wrangler.production.jsonc
|
|
196
|
+
npx wrangler secret put BLUE_RUNTIME_IMAGE_ARN \
|
|
197
|
+
--config wrangler.production.jsonc
|
|
198
|
+
npx wrangler secret put BLUE_RUNTIME_IMAGE_VERSION \
|
|
199
|
+
--config wrangler.production.jsonc
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Configure the platform Worker's AWS secrets plus
|
|
203
|
+
`BLUE_AWS_REGION`, `BLUE_ARTIFACT_BUCKET`, `BLUE_EXECUTION_ROLE_ARN`,
|
|
204
|
+
`BLUE_NETWORK_CONNECTOR_ARN`, `BLUE_S3_FILESYSTEM_ID`, and
|
|
205
|
+
`BLUE_S3_MOUNT_TARGET_IP`, then deploy in dependency order:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm run deploy:platform
|
|
209
|
+
npm run deploy:edge:production
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`GET /v1/auth/config` publishes only the WorkOS client ID and device endpoints;
|
|
213
|
+
no WorkOS secret is shipped in Blue.
|
|
214
|
+
|
|
215
|
+
Prompt-based `session create` and `session send` suspend the MicroVM after a
|
|
216
|
+
completed turn. Interactive `session create` keeps it running until the shell
|
|
217
|
+
exits, then suspends it.
|
|
218
|
+
Pass `--keep` when debugging a running MicroVM. AWS provisioning, Depot runtime
|
|
219
|
+
image builds, and Cloudflare deployment are platform operator tasks.
|
|
220
|
+
|
|
221
|
+
### Test multiple deployed agents
|
|
222
|
+
|
|
223
|
+
This repository includes `hello-agent` and `reviewer-agent`. Deploy and list
|
|
224
|
+
both:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
blue deploy --agent-dir examples/hello-agent
|
|
228
|
+
blue deploy --agent-dir examples/reviewer-agent
|
|
229
|
+
blue agents list
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Start one independent MicroVM session for each agent. Run these in separate
|
|
233
|
+
terminals to exercise concurrent cold starts:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
blue session create --agent hello-agent@production --keep \
|
|
237
|
+
"Describe your role in one sentence"
|
|
238
|
+
|
|
239
|
+
blue session create --agent reviewer-agent@production --keep \
|
|
240
|
+
"Review this workspace and report the highest-risk issue"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Use the session IDs printed by those commands:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
npm run blue -- session list
|
|
247
|
+
npm run blue -- session send <hello-session-id> "Create hello.txt"
|
|
248
|
+
npm run blue -- session send <review-session-id> "Review that change"
|
|
249
|
+
npm run blue -- session inspect <hello-session-id>
|
|
250
|
+
npm run blue -- session inspect <review-session-id>
|
|
251
|
+
npm run blue -- session end <hello-session-id>
|
|
252
|
+
npm run blue -- session end <review-session-id>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Every session has its own MicroVM and S3 Files workspace. The two agents share
|
|
256
|
+
the platform runtime image while loading different immutable agent artifacts.
|
|
257
|
+
|
|
258
|
+
## Agent Layout
|
|
259
|
+
|
|
260
|
+
```text
|
|
261
|
+
my-agent/
|
|
262
|
+
├── agent/
|
|
263
|
+
│ ├── agent.ts
|
|
264
|
+
│ ├── instructions.md
|
|
265
|
+
│ ├── tools/
|
|
266
|
+
│ ├── skills/
|
|
267
|
+
│ ├── channels/
|
|
268
|
+
│ └── sandbox/workspace/
|
|
269
|
+
├── evals/
|
|
270
|
+
└── blue.config.ts
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The complete architecture, AWS/S3 Files deployment path, security model, and
|
|
274
|
+
delivery phases are in [PLAN.md](./PLAN.md).
|
|
275
|
+
|
|
276
|
+
## Current Boundary
|
|
277
|
+
|
|
278
|
+
The standalone local control plane, WorkOS device login, token refresh,
|
|
279
|
+
tenant-isolated Durable Object routing, signed-upload API, runtime lifecycle
|
|
280
|
+
API, and authenticated OpenRouter proxy are implemented.
|
|
281
|
+
|
|
282
|
+
The `DEPLOYMENTS` and `RUNTIMES` platform services still need to be deployed
|
|
283
|
+
and bound before `blue deploy` and remote sessions work against
|
|
284
|
+
`blue.opencomputer.dev`. Those services own AWS credentials, signed S3 uploads,
|
|
285
|
+
Lambda MicroVM calls, and S3 Files access points. Versioned checkpoint
|
|
286
|
+
replacement, deployed channels, permissions, evals, cleanup, and the web UI
|
|
287
|
+
remain subsequent milestones.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const DEFAULT_BLUE_API_URL = "https://blue.opencomputer.dev";
|
|
2
|
+
interface WorkOsUser {
|
|
3
|
+
id: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
first_name?: string | null;
|
|
6
|
+
last_name?: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface BlueAuthConfiguration {
|
|
9
|
+
clientId: string;
|
|
10
|
+
deviceAuthorizationEndpoint: string;
|
|
11
|
+
tokenEndpoint: string;
|
|
12
|
+
}
|
|
13
|
+
export interface BlueCredentials {
|
|
14
|
+
version: 1;
|
|
15
|
+
apiUrl: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
tokenEndpoint: string;
|
|
18
|
+
accessToken: string;
|
|
19
|
+
refreshToken: string;
|
|
20
|
+
organizationId?: string;
|
|
21
|
+
user?: WorkOsUser;
|
|
22
|
+
updatedAt: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function credentialsPath(): string;
|
|
25
|
+
export declare function readCredentials(): Promise<BlueCredentials | null>;
|
|
26
|
+
export declare function logout(): Promise<boolean>;
|
|
27
|
+
export declare function login(apiUrl?: string): Promise<BlueCredentials>;
|
|
28
|
+
export declare function isLocalApiUrl(apiUrl: string): boolean;
|
|
29
|
+
export declare function accessTokenFor(apiUrl: string): Promise<string | undefined>;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { chmod, mkdir, readFile, rm, writeFile, } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
export const DEFAULT_BLUE_API_URL = "https://blue.opencomputer.dev";
|
|
6
|
+
function configHome() {
|
|
7
|
+
if (process.env.BLUE_CONFIG_HOME) {
|
|
8
|
+
return resolve(process.env.BLUE_CONFIG_HOME);
|
|
9
|
+
}
|
|
10
|
+
if (process.platform === "win32" && process.env.APPDATA) {
|
|
11
|
+
return resolve(process.env.APPDATA, "blue");
|
|
12
|
+
}
|
|
13
|
+
return resolve(process.env.XDG_CONFIG_HOME ?? resolve(homedir(), ".config"), "blue");
|
|
14
|
+
}
|
|
15
|
+
export function credentialsPath() {
|
|
16
|
+
return resolve(configHome(), "credentials.json");
|
|
17
|
+
}
|
|
18
|
+
function normalizeUrl(value) {
|
|
19
|
+
return value.replace(/\/+$/, "");
|
|
20
|
+
}
|
|
21
|
+
async function readResponse(response) {
|
|
22
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
23
|
+
if (!contentType.includes("application/json")) {
|
|
24
|
+
throw new Error(`Authentication endpoint returned ${String(response.status)} ${contentType || "without a content type"} from ${response.url}`);
|
|
25
|
+
}
|
|
26
|
+
const body = await response.json();
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const record = typeof body === "object" && body !== null
|
|
29
|
+
? body
|
|
30
|
+
: {};
|
|
31
|
+
const message = typeof record.error_description === "string"
|
|
32
|
+
? record.error_description
|
|
33
|
+
: typeof record.message === "string"
|
|
34
|
+
? record.message
|
|
35
|
+
: typeof record.error === "string"
|
|
36
|
+
? record.error
|
|
37
|
+
: `Request failed with status ${String(response.status)}`;
|
|
38
|
+
throw new Error(message);
|
|
39
|
+
}
|
|
40
|
+
return body;
|
|
41
|
+
}
|
|
42
|
+
function openBrowser(url) {
|
|
43
|
+
if (process.env.BLUE_NO_BROWSER === "1")
|
|
44
|
+
return;
|
|
45
|
+
const command = process.platform === "darwin"
|
|
46
|
+
? "open"
|
|
47
|
+
: process.platform === "win32"
|
|
48
|
+
? "cmd"
|
|
49
|
+
: "xdg-open";
|
|
50
|
+
const args = process.platform === "win32"
|
|
51
|
+
? ["/c", "start", "", url]
|
|
52
|
+
: [url];
|
|
53
|
+
const child = spawn(command, args, {
|
|
54
|
+
detached: true,
|
|
55
|
+
stdio: "ignore",
|
|
56
|
+
});
|
|
57
|
+
child.once("error", () => undefined);
|
|
58
|
+
child.unref();
|
|
59
|
+
}
|
|
60
|
+
async function saveCredentials(credentials) {
|
|
61
|
+
const path = credentialsPath();
|
|
62
|
+
await mkdir(dirname(path), { recursive: true });
|
|
63
|
+
await writeFile(path, `${JSON.stringify(credentials, null, 2)}\n`, {
|
|
64
|
+
mode: 0o600,
|
|
65
|
+
});
|
|
66
|
+
await chmod(path, 0o600);
|
|
67
|
+
}
|
|
68
|
+
export async function readCredentials() {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(await readFile(credentialsPath(), "utf8"));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function logout() {
|
|
77
|
+
try {
|
|
78
|
+
await rm(credentialsPath());
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof Error &&
|
|
83
|
+
"code" in error &&
|
|
84
|
+
error.code === "ENOENT") {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export async function login(apiUrl = DEFAULT_BLUE_API_URL) {
|
|
91
|
+
const normalizedApiUrl = normalizeUrl(apiUrl);
|
|
92
|
+
const configuration = await readResponse(await fetch(`${normalizedApiUrl}/v1/auth/config`));
|
|
93
|
+
const authorization = await readResponse(await fetch(configuration.deviceAuthorizationEndpoint, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
97
|
+
},
|
|
98
|
+
body: new URLSearchParams({
|
|
99
|
+
client_id: configuration.clientId,
|
|
100
|
+
}),
|
|
101
|
+
}));
|
|
102
|
+
process.stdout.write(`Open ${authorization.verification_uri}\n` +
|
|
103
|
+
`Enter code: ${authorization.user_code}\n` +
|
|
104
|
+
"Waiting for authentication...\n");
|
|
105
|
+
openBrowser(authorization.verification_uri_complete ??
|
|
106
|
+
authorization.verification_uri);
|
|
107
|
+
const deadline = Date.now() + authorization.expires_in * 1_000;
|
|
108
|
+
let intervalSeconds = Math.max(1, authorization.interval ?? 5);
|
|
109
|
+
let tokens;
|
|
110
|
+
while (Date.now() < deadline) {
|
|
111
|
+
const response = await fetch(configuration.tokenEndpoint, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: {
|
|
114
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
115
|
+
},
|
|
116
|
+
body: new URLSearchParams({
|
|
117
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
118
|
+
device_code: authorization.device_code,
|
|
119
|
+
client_id: configuration.clientId,
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
const body = (await response.json());
|
|
123
|
+
if (response.ok) {
|
|
124
|
+
tokens = body;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (body.error === "authorization_pending") {
|
|
128
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, intervalSeconds * 1_000));
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (body.error === "slow_down") {
|
|
132
|
+
intervalSeconds += 1;
|
|
133
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, intervalSeconds * 1_000));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
throw new Error(body.error_description ??
|
|
137
|
+
body.error ??
|
|
138
|
+
"WorkOS authentication failed");
|
|
139
|
+
}
|
|
140
|
+
if (!tokens?.access_token || !tokens.refresh_token) {
|
|
141
|
+
throw new Error("WorkOS authentication timed out");
|
|
142
|
+
}
|
|
143
|
+
const credentials = {
|
|
144
|
+
version: 1,
|
|
145
|
+
apiUrl: normalizedApiUrl,
|
|
146
|
+
clientId: configuration.clientId,
|
|
147
|
+
tokenEndpoint: configuration.tokenEndpoint,
|
|
148
|
+
accessToken: tokens.access_token,
|
|
149
|
+
refreshToken: tokens.refresh_token,
|
|
150
|
+
organizationId: tokens.organization_id,
|
|
151
|
+
user: tokens.user,
|
|
152
|
+
updatedAt: new Date().toISOString(),
|
|
153
|
+
};
|
|
154
|
+
await saveCredentials(credentials);
|
|
155
|
+
return credentials;
|
|
156
|
+
}
|
|
157
|
+
function tokenExpiresSoon(token) {
|
|
158
|
+
try {
|
|
159
|
+
const payload = JSON.parse(Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
160
|
+
return (typeof payload.exp !== "number" ||
|
|
161
|
+
payload.exp * 1_000 <= Date.now() + 60_000);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function refresh(credentials) {
|
|
168
|
+
const tokens = await readResponse(await fetch(credentials.tokenEndpoint, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: {
|
|
171
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
172
|
+
},
|
|
173
|
+
body: new URLSearchParams({
|
|
174
|
+
grant_type: "refresh_token",
|
|
175
|
+
refresh_token: credentials.refreshToken,
|
|
176
|
+
client_id: credentials.clientId,
|
|
177
|
+
}),
|
|
178
|
+
}));
|
|
179
|
+
const refreshed = {
|
|
180
|
+
...credentials,
|
|
181
|
+
accessToken: tokens.access_token,
|
|
182
|
+
refreshToken: tokens.refresh_token,
|
|
183
|
+
organizationId: tokens.organization_id ?? credentials.organizationId,
|
|
184
|
+
user: tokens.user ?? credentials.user,
|
|
185
|
+
updatedAt: new Date().toISOString(),
|
|
186
|
+
};
|
|
187
|
+
await saveCredentials(refreshed);
|
|
188
|
+
return refreshed;
|
|
189
|
+
}
|
|
190
|
+
export function isLocalApiUrl(apiUrl) {
|
|
191
|
+
const hostname = new URL(apiUrl).hostname;
|
|
192
|
+
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1";
|
|
193
|
+
}
|
|
194
|
+
export async function accessTokenFor(apiUrl) {
|
|
195
|
+
if (isLocalApiUrl(apiUrl))
|
|
196
|
+
return undefined;
|
|
197
|
+
const credentials = await readCredentials();
|
|
198
|
+
if (!credentials || normalizeUrl(credentials.apiUrl) !== normalizeUrl(apiUrl)) {
|
|
199
|
+
throw new Error(`Not logged in to ${apiUrl}. Run \`blue login\`.`);
|
|
200
|
+
}
|
|
201
|
+
const current = tokenExpiresSoon(credentials.accessToken)
|
|
202
|
+
? await refresh(credentials)
|
|
203
|
+
: credentials;
|
|
204
|
+
return current.accessToken;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=cli-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-auth.js","sourceRoot":"","sources":["../../src/auth/cli-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BlueEvent } from "../protocol.js";
|
|
2
|
+
export interface SlackStatus {
|
|
3
|
+
status: string;
|
|
4
|
+
loadingMessages?: string[];
|
|
5
|
+
}
|
|
6
|
+
type SlackStatusUpdater = (status: SlackStatus) => Promise<void>;
|
|
7
|
+
export declare function truncateSlackStatus(value: string): string;
|
|
8
|
+
export declare function describeSlackTool(event: BlueEvent): string;
|
|
9
|
+
export declare class SlackProgress {
|
|
10
|
+
private readonly update;
|
|
11
|
+
private chain;
|
|
12
|
+
private lastReasoningAt;
|
|
13
|
+
private lastReasoningStatus;
|
|
14
|
+
private reasoning;
|
|
15
|
+
private stopped;
|
|
16
|
+
private writing;
|
|
17
|
+
constructor(update: SlackStatusUpdater);
|
|
18
|
+
start(): void;
|
|
19
|
+
runtimeStarting(): void;
|
|
20
|
+
runtimeReady(): void;
|
|
21
|
+
handle(event: BlueEvent): void;
|
|
22
|
+
stop(options?: {
|
|
23
|
+
clear?: boolean;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
private enqueue;
|
|
26
|
+
}
|
|
27
|
+
export {};
|